xref: /linux/fs/bcachefs/subvolume.c (revision 6738dd19db5c96e574af79a3b7c1754fb2ecf2bd)
114b393eeSKent Overstreet // SPDX-License-Identifier: GPL-2.0
214b393eeSKent Overstreet 
314b393eeSKent Overstreet #include "bcachefs.h"
414b393eeSKent Overstreet #include "btree_key_cache.h"
514b393eeSKent Overstreet #include "btree_update.h"
614b393eeSKent Overstreet #include "error.h"
72027875bSKent Overstreet #include "fs.h"
814b393eeSKent Overstreet #include "subvolume.h"
914b393eeSKent Overstreet 
1014b393eeSKent Overstreet /* Snapshot tree: */
1114b393eeSKent Overstreet 
1214b393eeSKent Overstreet void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c,
1314b393eeSKent Overstreet 			   struct bkey_s_c k)
1414b393eeSKent Overstreet {
1514b393eeSKent Overstreet 	struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(k);
1614b393eeSKent Overstreet 
17416cc426SKent Overstreet 	prt_printf(out, "is_subvol %llu deleted %llu parent %10u children %10u %10u subvol %u",
1814b393eeSKent Overstreet 	       BCH_SNAPSHOT_SUBVOL(s.v),
1914b393eeSKent Overstreet 	       BCH_SNAPSHOT_DELETED(s.v),
2014b393eeSKent Overstreet 	       le32_to_cpu(s.v->parent),
2114b393eeSKent Overstreet 	       le32_to_cpu(s.v->children[0]),
2214b393eeSKent Overstreet 	       le32_to_cpu(s.v->children[1]),
2314b393eeSKent Overstreet 	       le32_to_cpu(s.v->subvol));
2414b393eeSKent Overstreet }
2514b393eeSKent Overstreet 
26f0ac7df2SKent Overstreet int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k,
27275c8426SKent Overstreet 			  int rw, struct printbuf *err)
2814b393eeSKent Overstreet {
2914b393eeSKent Overstreet 	struct bkey_s_c_snapshot s;
3014b393eeSKent Overstreet 	u32 i, id;
3114b393eeSKent Overstreet 
3214b393eeSKent Overstreet 	if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0 ||
33f0ac7df2SKent Overstreet 	    bkey_cmp(k.k->p, POS(0, 1)) < 0) {
34401ec4dbSKent Overstreet 		prt_printf(err, "bad pos");
35f0ac7df2SKent Overstreet 		return -EINVAL;
36f0ac7df2SKent Overstreet 	}
3714b393eeSKent Overstreet 
38f0ac7df2SKent Overstreet 	if (bkey_val_bytes(k.k) != sizeof(struct bch_snapshot)) {
39401ec4dbSKent Overstreet 		prt_printf(err, "bad val size (%zu != %zu)",
40f0ac7df2SKent Overstreet 		       bkey_val_bytes(k.k), sizeof(struct bch_snapshot));
41f0ac7df2SKent Overstreet 		return -EINVAL;
42f0ac7df2SKent Overstreet 	}
4314b393eeSKent Overstreet 
4414b393eeSKent Overstreet 	s = bkey_s_c_to_snapshot(k);
4514b393eeSKent Overstreet 
4614b393eeSKent Overstreet 	id = le32_to_cpu(s.v->parent);
47f0ac7df2SKent Overstreet 	if (id && id <= k.k->p.offset) {
48401ec4dbSKent Overstreet 		prt_printf(err, "bad parent node (%u <= %llu)",
49f0ac7df2SKent Overstreet 		       id, k.k->p.offset);
50f0ac7df2SKent Overstreet 		return -EINVAL;
51f0ac7df2SKent Overstreet 	}
5214b393eeSKent Overstreet 
53f0ac7df2SKent Overstreet 	if (le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1])) {
54401ec4dbSKent Overstreet 		prt_printf(err, "children not normalized");
55f0ac7df2SKent Overstreet 		return -EINVAL;
56f0ac7df2SKent Overstreet 	}
5714b393eeSKent Overstreet 
5814b393eeSKent Overstreet 	if (s.v->children[0] &&
59f0ac7df2SKent Overstreet 	    s.v->children[0] == s.v->children[1]) {
60401ec4dbSKent Overstreet 		prt_printf(err, "duplicate child nodes");
61f0ac7df2SKent Overstreet 		return -EINVAL;
62f0ac7df2SKent Overstreet 	}
6314b393eeSKent Overstreet 
6414b393eeSKent Overstreet 	for (i = 0; i < 2; i++) {
6514b393eeSKent Overstreet 		id = le32_to_cpu(s.v->children[i]);
6614b393eeSKent Overstreet 
67f0ac7df2SKent Overstreet 		if (id >= k.k->p.offset) {
68401ec4dbSKent Overstreet 			prt_printf(err, "bad child node (%u >= %llu)",
69f0ac7df2SKent Overstreet 			       id, k.k->p.offset);
70f0ac7df2SKent Overstreet 			return -EINVAL;
71f0ac7df2SKent Overstreet 		}
7214b393eeSKent Overstreet 	}
7314b393eeSKent Overstreet 
74f0ac7df2SKent Overstreet 	return 0;
7514b393eeSKent Overstreet }
7614b393eeSKent Overstreet 
77904823deSKent Overstreet int bch2_mark_snapshot(struct btree_trans *trans,
7814b393eeSKent Overstreet 		       struct bkey_s_c old, struct bkey_s_c new,
79904823deSKent Overstreet 		       unsigned flags)
8014b393eeSKent Overstreet {
81904823deSKent Overstreet 	struct bch_fs *c = trans->c;
8214b393eeSKent Overstreet 	struct snapshot_t *t;
8314b393eeSKent Overstreet 
8414b393eeSKent Overstreet 	t = genradix_ptr_alloc(&c->snapshots,
8514b393eeSKent Overstreet 			       U32_MAX - new.k->p.offset,
8614b393eeSKent Overstreet 			       GFP_KERNEL);
8714b393eeSKent Overstreet 	if (!t)
8814b393eeSKent Overstreet 		return -ENOMEM;
8914b393eeSKent Overstreet 
9014b393eeSKent Overstreet 	if (new.k->type == KEY_TYPE_snapshot) {
9114b393eeSKent Overstreet 		struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(new);
9214b393eeSKent Overstreet 
9314b393eeSKent Overstreet 		t->parent	= le32_to_cpu(s.v->parent);
9414b393eeSKent Overstreet 		t->children[0]	= le32_to_cpu(s.v->children[0]);
9514b393eeSKent Overstreet 		t->children[1]	= le32_to_cpu(s.v->children[1]);
9614b393eeSKent Overstreet 		t->subvol	= BCH_SNAPSHOT_SUBVOL(s.v) ? le32_to_cpu(s.v->subvol) : 0;
9714b393eeSKent Overstreet 	} else {
9814b393eeSKent Overstreet 		t->parent	= 0;
9914b393eeSKent Overstreet 		t->children[0]	= 0;
10014b393eeSKent Overstreet 		t->children[1]	= 0;
10114b393eeSKent Overstreet 		t->subvol	= 0;
10214b393eeSKent Overstreet 	}
10314b393eeSKent Overstreet 
10414b393eeSKent Overstreet 	return 0;
10514b393eeSKent Overstreet }
10614b393eeSKent Overstreet 
10714b393eeSKent Overstreet static int snapshot_lookup(struct btree_trans *trans, u32 id,
10814b393eeSKent Overstreet 			   struct bch_snapshot *s)
10914b393eeSKent Overstreet {
11014b393eeSKent Overstreet 	struct btree_iter iter;
11114b393eeSKent Overstreet 	struct bkey_s_c k;
11214b393eeSKent Overstreet 	int ret;
11314b393eeSKent Overstreet 
11414b393eeSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id),
11514b393eeSKent Overstreet 			     BTREE_ITER_WITH_UPDATES);
11614b393eeSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
11714b393eeSKent Overstreet 	ret = bkey_err(k) ?: k.k->type == KEY_TYPE_snapshot ? 0 : -ENOENT;
11814b393eeSKent Overstreet 
11914b393eeSKent Overstreet 	if (!ret)
12014b393eeSKent Overstreet 		*s = *bkey_s_c_to_snapshot(k).v;
12114b393eeSKent Overstreet 
12214b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
12314b393eeSKent Overstreet 	return ret;
12414b393eeSKent Overstreet }
12514b393eeSKent Overstreet 
12614b393eeSKent Overstreet static int snapshot_live(struct btree_trans *trans, u32 id)
12714b393eeSKent Overstreet {
12814b393eeSKent Overstreet 	struct bch_snapshot v;
12914b393eeSKent Overstreet 	int ret;
13014b393eeSKent Overstreet 
13114b393eeSKent Overstreet 	if (!id)
13214b393eeSKent Overstreet 		return 0;
13314b393eeSKent Overstreet 
134a1783320SKent Overstreet 	ret = snapshot_lookup(trans, id, &v);
13514b393eeSKent Overstreet 	if (ret == -ENOENT)
13614b393eeSKent Overstreet 		bch_err(trans->c, "snapshot node %u not found", id);
13714b393eeSKent Overstreet 	if (ret)
13814b393eeSKent Overstreet 		return ret;
13914b393eeSKent Overstreet 
14014b393eeSKent Overstreet 	return !BCH_SNAPSHOT_DELETED(&v);
14114b393eeSKent Overstreet }
14214b393eeSKent Overstreet 
143a1783320SKent Overstreet static int bch2_snapshot_set_equiv(struct btree_trans *trans, struct bkey_s_c k)
14414b393eeSKent Overstreet {
14514b393eeSKent Overstreet 	struct bch_fs *c = trans->c;
14635f1a503SKent Overstreet 	unsigned i, nr_live = 0, live_idx = 0;
147a1783320SKent Overstreet 	struct bkey_s_c_snapshot snap;
148a1783320SKent Overstreet 	u32 id = k.k->p.offset, child[2];
149a1783320SKent Overstreet 
150a1783320SKent Overstreet 	if (k.k->type != KEY_TYPE_snapshot)
151a1783320SKent Overstreet 		return 0;
152a1783320SKent Overstreet 
153a1783320SKent Overstreet 	snap = bkey_s_c_to_snapshot(k);
154a1783320SKent Overstreet 
155a1783320SKent Overstreet 	child[0] = le32_to_cpu(snap.v->children[0]);
156a1783320SKent Overstreet 	child[1] = le32_to_cpu(snap.v->children[1]);
15714b393eeSKent Overstreet 
15814b393eeSKent Overstreet 	for (i = 0; i < 2; i++) {
15935f1a503SKent Overstreet 		int ret = snapshot_live(trans, child[i]);
16014b393eeSKent Overstreet 		if (ret < 0)
16135f1a503SKent Overstreet 			return ret;
16214b393eeSKent Overstreet 
16314b393eeSKent Overstreet 		if (ret)
16414b393eeSKent Overstreet 			live_idx = i;
16514b393eeSKent Overstreet 		nr_live += ret;
16614b393eeSKent Overstreet 	}
16714b393eeSKent Overstreet 
16814b393eeSKent Overstreet 	snapshot_t(c, id)->equiv = nr_live == 1
16914b393eeSKent Overstreet 		? snapshot_t(c, child[live_idx])->equiv
17014b393eeSKent Overstreet 		: id;
17135f1a503SKent Overstreet 	return 0;
17214b393eeSKent Overstreet }
17335f1a503SKent Overstreet 
17414b393eeSKent Overstreet /* fsck: */
17535f1a503SKent Overstreet static int check_snapshot(struct btree_trans *trans,
176a1783320SKent Overstreet 			  struct btree_iter *iter,
177a1783320SKent Overstreet 			  struct bkey_s_c k)
17814b393eeSKent Overstreet {
17935f1a503SKent Overstreet 	struct bch_fs *c = trans->c;
18035f1a503SKent Overstreet 	struct bkey_s_c_snapshot s;
18114b393eeSKent Overstreet 	struct bch_subvolume subvol;
18214b393eeSKent Overstreet 	struct bch_snapshot v;
18335f1a503SKent Overstreet 	struct printbuf buf = PRINTBUF;
18435f1a503SKent Overstreet 	bool should_have_subvol;
18514b393eeSKent Overstreet 	u32 i, id;
18635f1a503SKent Overstreet 	int ret = 0;
18714b393eeSKent Overstreet 
18835f1a503SKent Overstreet 	if (k.k->type != KEY_TYPE_snapshot)
18935f1a503SKent Overstreet 		return 0;
19014b393eeSKent Overstreet 
19135f1a503SKent Overstreet 	s = bkey_s_c_to_snapshot(k);
19214b393eeSKent Overstreet 	id = le32_to_cpu(s.v->parent);
19314b393eeSKent Overstreet 	if (id) {
194a1783320SKent Overstreet 		ret = snapshot_lookup(trans, id, &v);
19514b393eeSKent Overstreet 		if (ret == -ENOENT)
19635f1a503SKent Overstreet 			bch_err(c, "snapshot with nonexistent parent:\n  %s",
19735f1a503SKent Overstreet 				(bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf));
19814b393eeSKent Overstreet 		if (ret)
19935f1a503SKent Overstreet 			goto err;
20014b393eeSKent Overstreet 
20114b393eeSKent Overstreet 		if (le32_to_cpu(v.children[0]) != s.k->p.offset &&
20214b393eeSKent Overstreet 		    le32_to_cpu(v.children[1]) != s.k->p.offset) {
20335f1a503SKent Overstreet 			bch_err(c, "snapshot parent %u missing pointer to child %llu",
20414b393eeSKent Overstreet 				id, s.k->p.offset);
20535f1a503SKent Overstreet 			ret = -EINVAL;
20635f1a503SKent Overstreet 			goto err;
20714b393eeSKent Overstreet 		}
20814b393eeSKent Overstreet 	}
20914b393eeSKent Overstreet 
21014b393eeSKent Overstreet 	for (i = 0; i < 2 && s.v->children[i]; i++) {
21114b393eeSKent Overstreet 		id = le32_to_cpu(s.v->children[i]);
21214b393eeSKent Overstreet 
213a1783320SKent Overstreet 		ret = snapshot_lookup(trans, id, &v);
21414b393eeSKent Overstreet 		if (ret == -ENOENT)
21535f1a503SKent Overstreet 			bch_err(c, "snapshot node %llu has nonexistent child %u",
21614b393eeSKent Overstreet 				s.k->p.offset, id);
21714b393eeSKent Overstreet 		if (ret)
21835f1a503SKent Overstreet 			goto err;
21914b393eeSKent Overstreet 
22014b393eeSKent Overstreet 		if (le32_to_cpu(v.parent) != s.k->p.offset) {
22135f1a503SKent Overstreet 			bch_err(c, "snapshot child %u has wrong parent (got %u should be %llu)",
22214b393eeSKent Overstreet 				id, le32_to_cpu(v.parent), s.k->p.offset);
22335f1a503SKent Overstreet 			ret = -EINVAL;
22435f1a503SKent Overstreet 			goto err;
22514b393eeSKent Overstreet 		}
22614b393eeSKent Overstreet 	}
22714b393eeSKent Overstreet 
22835f1a503SKent Overstreet 	should_have_subvol = BCH_SNAPSHOT_SUBVOL(s.v) &&
22935f1a503SKent Overstreet 		!BCH_SNAPSHOT_DELETED(s.v);
23035f1a503SKent Overstreet 
23135f1a503SKent Overstreet 	if (should_have_subvol) {
23235f1a503SKent Overstreet 		id = le32_to_cpu(s.v->subvol);
233a1783320SKent Overstreet 		ret = bch2_subvolume_get(trans, id, 0, false, &subvol);
23435f1a503SKent Overstreet 		if (ret == -ENOENT)
23535f1a503SKent Overstreet 			bch_err(c, "snapshot points to nonexistent subvolume:\n  %s",
23635f1a503SKent Overstreet 				(bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf));
23735f1a503SKent Overstreet 		if (ret)
23835f1a503SKent Overstreet 			goto err;
23935f1a503SKent Overstreet 
24035f1a503SKent Overstreet 		if (BCH_SNAPSHOT_SUBVOL(s.v) != (le32_to_cpu(subvol.snapshot) == s.k->p.offset)) {
24135f1a503SKent Overstreet 			bch_err(c, "snapshot node %llu has wrong BCH_SNAPSHOT_SUBVOL",
24235f1a503SKent Overstreet 				s.k->p.offset);
24335f1a503SKent Overstreet 			ret = -EINVAL;
24435f1a503SKent Overstreet 			goto err;
24535f1a503SKent Overstreet 		}
24635f1a503SKent Overstreet 	} else {
24735f1a503SKent Overstreet 		if (fsck_err_on(s.v->subvol, c, "snapshot should not point to subvol:\n  %s",
24835f1a503SKent Overstreet 				(bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf))) {
24935f1a503SKent Overstreet 			struct bkey_i_snapshot *u = bch2_trans_kmalloc(trans, sizeof(*u));
25035f1a503SKent Overstreet 
25135f1a503SKent Overstreet 			ret = PTR_ERR_OR_ZERO(u);
25235f1a503SKent Overstreet 			if (ret)
25335f1a503SKent Overstreet 				goto err;
25435f1a503SKent Overstreet 
25535f1a503SKent Overstreet 			bkey_reassemble(&u->k_i, s.s_c);
25635f1a503SKent Overstreet 			u->v.subvol = 0;
25735f1a503SKent Overstreet 			ret = bch2_trans_update(trans, iter, &u->k_i, 0);
25835f1a503SKent Overstreet 			if (ret)
25935f1a503SKent Overstreet 				goto err;
26035f1a503SKent Overstreet 		}
26135f1a503SKent Overstreet 	}
26235f1a503SKent Overstreet 
26335f1a503SKent Overstreet 	if (BCH_SNAPSHOT_DELETED(s.v))
26435f1a503SKent Overstreet 		set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags);
26535f1a503SKent Overstreet err:
26635f1a503SKent Overstreet fsck_err:
26735f1a503SKent Overstreet 	printbuf_exit(&buf);
26835f1a503SKent Overstreet 	return ret;
26914b393eeSKent Overstreet }
27014b393eeSKent Overstreet 
2714ab35c34SKent Overstreet int bch2_fs_check_snapshots(struct bch_fs *c)
27214b393eeSKent Overstreet {
27314b393eeSKent Overstreet 	struct btree_trans trans;
27414b393eeSKent Overstreet 	struct btree_iter iter;
275a1783320SKent Overstreet 	struct bkey_s_c k;
27614b393eeSKent Overstreet 	int ret;
27714b393eeSKent Overstreet 
27814b393eeSKent Overstreet 	bch2_trans_init(&trans, c, 0, 0);
27914b393eeSKent Overstreet 
280a1783320SKent Overstreet 	ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_snapshots,
281a1783320SKent Overstreet 			POS(BCACHEFS_ROOT_INO, 0),
282a1783320SKent Overstreet 			BTREE_ITER_PREFETCH, k,
283a1783320SKent Overstreet 			NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
284a1783320SKent Overstreet 		check_snapshot(&trans, &iter, k));
28514b393eeSKent Overstreet 
28635f1a503SKent Overstreet 	if (ret)
28714b393eeSKent Overstreet 		bch_err(c, "error %i checking snapshots", ret);
28814b393eeSKent Overstreet 
28914b393eeSKent Overstreet 	bch2_trans_exit(&trans);
29014b393eeSKent Overstreet 	return ret;
29114b393eeSKent Overstreet }
29214b393eeSKent Overstreet 
2934ab35c34SKent Overstreet static int check_subvol(struct btree_trans *trans,
294*6738dd19SKent Overstreet 			struct btree_iter *iter,
295*6738dd19SKent Overstreet 			struct bkey_s_c k)
2964ab35c34SKent Overstreet {
2974ab35c34SKent Overstreet 	struct bkey_s_c_subvolume subvol;
29835f1a503SKent Overstreet 	struct bch_snapshot snapshot;
29935f1a503SKent Overstreet 	unsigned snapid;
3004ab35c34SKent Overstreet 	int ret;
3014ab35c34SKent Overstreet 
3024ab35c34SKent Overstreet 	if (k.k->type != KEY_TYPE_subvolume)
3034ab35c34SKent Overstreet 		return 0;
3044ab35c34SKent Overstreet 
3054ab35c34SKent Overstreet 	subvol = bkey_s_c_to_subvolume(k);
30635f1a503SKent Overstreet 	snapid = le32_to_cpu(subvol.v->snapshot);
30735f1a503SKent Overstreet 	ret = snapshot_lookup(trans, snapid, &snapshot);
30835f1a503SKent Overstreet 
30935f1a503SKent Overstreet 	if (ret == -ENOENT)
31035f1a503SKent Overstreet 		bch_err(trans->c, "subvolume %llu points to nonexistent snapshot %u",
31135f1a503SKent Overstreet 			k.k->p.offset, snapid);
31235f1a503SKent Overstreet 	if (ret)
31335f1a503SKent Overstreet 		return ret;
3144ab35c34SKent Overstreet 
3154ab35c34SKent Overstreet 	if (BCH_SUBVOLUME_UNLINKED(subvol.v)) {
3164ab35c34SKent Overstreet 		ret = bch2_subvolume_delete(trans, iter->pos.offset);
3174ab35c34SKent Overstreet 		if (ret && ret != -EINTR)
3184ab35c34SKent Overstreet 			bch_err(trans->c, "error deleting subvolume %llu: %i",
3194ab35c34SKent Overstreet 				iter->pos.offset, ret);
3204ab35c34SKent Overstreet 		if (ret)
3214ab35c34SKent Overstreet 			return ret;
3224ab35c34SKent Overstreet 	}
3234ab35c34SKent Overstreet 
3244ab35c34SKent Overstreet 	return 0;
3254ab35c34SKent Overstreet }
3264ab35c34SKent Overstreet 
3274ab35c34SKent Overstreet int bch2_fs_check_subvols(struct bch_fs *c)
3284ab35c34SKent Overstreet {
3294ab35c34SKent Overstreet 	struct btree_trans trans;
3304ab35c34SKent Overstreet 	struct btree_iter iter;
331*6738dd19SKent Overstreet 	struct bkey_s_c k;
3324ab35c34SKent Overstreet 	int ret;
3334ab35c34SKent Overstreet 
33435f1a503SKent Overstreet 	bch2_trans_init(&trans, c, 0, 0);
3354ab35c34SKent Overstreet 
336*6738dd19SKent Overstreet 	ret = for_each_btree_key_commit(&trans, iter,
337*6738dd19SKent Overstreet 			BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k,
338*6738dd19SKent Overstreet 			NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
339*6738dd19SKent Overstreet 		check_subvol(&trans, &iter, k));
3404ab35c34SKent Overstreet 
3414ab35c34SKent Overstreet 	bch2_trans_exit(&trans);
3424ab35c34SKent Overstreet 
3434ab35c34SKent Overstreet 	return ret;
3444ab35c34SKent Overstreet }
3454ab35c34SKent Overstreet 
34614b393eeSKent Overstreet void bch2_fs_snapshots_exit(struct bch_fs *c)
34714b393eeSKent Overstreet {
34814b393eeSKent Overstreet 	genradix_free(&c->snapshots);
34914b393eeSKent Overstreet }
35014b393eeSKent Overstreet 
35114b393eeSKent Overstreet int bch2_fs_snapshots_start(struct bch_fs *c)
35214b393eeSKent Overstreet {
35314b393eeSKent Overstreet 	struct btree_trans trans;
35414b393eeSKent Overstreet 	struct btree_iter iter;
35514b393eeSKent Overstreet 	struct bkey_s_c k;
35614b393eeSKent Overstreet 	int ret = 0;
35714b393eeSKent Overstreet 
35814b393eeSKent Overstreet 	bch2_trans_init(&trans, c, 0, 0);
35914b393eeSKent Overstreet 
360a1783320SKent Overstreet 	for_each_btree_key2(&trans, iter, BTREE_ID_snapshots,
361a1783320SKent Overstreet 			   POS_MIN, 0, k,
362a1783320SKent Overstreet 		bch2_mark_snapshot(&trans, bkey_s_c_null, k, 0) ?:
363a1783320SKent Overstreet 		bch2_snapshot_set_equiv(&trans, k));
36414b393eeSKent Overstreet 
36514b393eeSKent Overstreet 	bch2_trans_exit(&trans);
36635f1a503SKent Overstreet 
36735f1a503SKent Overstreet 	if (ret)
36835f1a503SKent Overstreet 		bch_err(c, "error starting snapshots: %i", ret);
36914b393eeSKent Overstreet 	return ret;
37014b393eeSKent Overstreet }
37114b393eeSKent Overstreet 
37214b393eeSKent Overstreet /*
37314b393eeSKent Overstreet  * Mark a snapshot as deleted, for future cleanup:
37414b393eeSKent Overstreet  */
37514b393eeSKent Overstreet static int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id)
37614b393eeSKent Overstreet {
37714b393eeSKent Overstreet 	struct btree_iter iter;
37814b393eeSKent Overstreet 	struct bkey_s_c k;
37914b393eeSKent Overstreet 	struct bkey_i_snapshot *s;
38014b393eeSKent Overstreet 	int ret = 0;
38114b393eeSKent Overstreet 
38214b393eeSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id),
38314b393eeSKent Overstreet 			     BTREE_ITER_INTENT);
38414b393eeSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
38514b393eeSKent Overstreet 	ret = bkey_err(k);
38614b393eeSKent Overstreet 	if (ret)
38714b393eeSKent Overstreet 		goto err;
38814b393eeSKent Overstreet 
38914b393eeSKent Overstreet 	if (k.k->type != KEY_TYPE_snapshot) {
39014b393eeSKent Overstreet 		bch2_fs_inconsistent(trans->c, "missing snapshot %u", id);
39114b393eeSKent Overstreet 		ret = -ENOENT;
39214b393eeSKent Overstreet 		goto err;
39314b393eeSKent Overstreet 	}
39414b393eeSKent Overstreet 
39514b393eeSKent Overstreet 	/* already deleted? */
39614b393eeSKent Overstreet 	if (BCH_SNAPSHOT_DELETED(bkey_s_c_to_snapshot(k).v))
39714b393eeSKent Overstreet 		goto err;
39814b393eeSKent Overstreet 
39914b393eeSKent Overstreet 	s = bch2_trans_kmalloc(trans, sizeof(*s));
40014b393eeSKent Overstreet 	ret = PTR_ERR_OR_ZERO(s);
40114b393eeSKent Overstreet 	if (ret)
40214b393eeSKent Overstreet 		goto err;
40314b393eeSKent Overstreet 
40414b393eeSKent Overstreet 	bkey_reassemble(&s->k_i, k);
40514b393eeSKent Overstreet 	SET_BCH_SNAPSHOT_DELETED(&s->v, true);
406416cc426SKent Overstreet 	SET_BCH_SNAPSHOT_SUBVOL(&s->v, false);
407416cc426SKent Overstreet 	s->v.subvol = 0;
408416cc426SKent Overstreet 
40914b393eeSKent Overstreet 	ret = bch2_trans_update(trans, &iter, &s->k_i, 0);
41014b393eeSKent Overstreet 	if (ret)
41114b393eeSKent Overstreet 		goto err;
41214b393eeSKent Overstreet err:
41314b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
41414b393eeSKent Overstreet 	return ret;
41514b393eeSKent Overstreet }
41614b393eeSKent Overstreet 
41714b393eeSKent Overstreet static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id)
41814b393eeSKent Overstreet {
41914b393eeSKent Overstreet 	struct btree_iter iter, p_iter = (struct btree_iter) { NULL };
42014b393eeSKent Overstreet 	struct bkey_s_c k;
42114b393eeSKent Overstreet 	struct bkey_s_c_snapshot s;
42214b393eeSKent Overstreet 	struct bkey_i_snapshot *parent;
42314b393eeSKent Overstreet 	u32 parent_id;
42414b393eeSKent Overstreet 	unsigned i;
42514b393eeSKent Overstreet 	int ret = 0;
42614b393eeSKent Overstreet 
42714b393eeSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id),
42814b393eeSKent Overstreet 			     BTREE_ITER_INTENT);
42914b393eeSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
43014b393eeSKent Overstreet 	ret = bkey_err(k);
43114b393eeSKent Overstreet 	if (ret)
43214b393eeSKent Overstreet 		goto err;
43314b393eeSKent Overstreet 
43414b393eeSKent Overstreet 	if (k.k->type != KEY_TYPE_snapshot) {
43514b393eeSKent Overstreet 		bch2_fs_inconsistent(trans->c, "missing snapshot %u", id);
43614b393eeSKent Overstreet 		ret = -ENOENT;
43714b393eeSKent Overstreet 		goto err;
43814b393eeSKent Overstreet 	}
43914b393eeSKent Overstreet 
44014b393eeSKent Overstreet 	s = bkey_s_c_to_snapshot(k);
44114b393eeSKent Overstreet 
44214b393eeSKent Overstreet 	BUG_ON(!BCH_SNAPSHOT_DELETED(s.v));
44314b393eeSKent Overstreet 	parent_id = le32_to_cpu(s.v->parent);
44414b393eeSKent Overstreet 
44514b393eeSKent Overstreet 	if (parent_id) {
44614b393eeSKent Overstreet 		bch2_trans_iter_init(trans, &p_iter, BTREE_ID_snapshots,
44714b393eeSKent Overstreet 				     POS(0, parent_id),
44814b393eeSKent Overstreet 				     BTREE_ITER_INTENT);
44914b393eeSKent Overstreet 		k = bch2_btree_iter_peek_slot(&p_iter);
45014b393eeSKent Overstreet 		ret = bkey_err(k);
45114b393eeSKent Overstreet 		if (ret)
45214b393eeSKent Overstreet 			goto err;
45314b393eeSKent Overstreet 
45414b393eeSKent Overstreet 		if (k.k->type != KEY_TYPE_snapshot) {
45514b393eeSKent Overstreet 			bch2_fs_inconsistent(trans->c, "missing snapshot %u", parent_id);
45614b393eeSKent Overstreet 			ret = -ENOENT;
45714b393eeSKent Overstreet 			goto err;
45814b393eeSKent Overstreet 		}
45914b393eeSKent Overstreet 
46014b393eeSKent Overstreet 		parent = bch2_trans_kmalloc(trans, sizeof(*parent));
46114b393eeSKent Overstreet 		ret = PTR_ERR_OR_ZERO(parent);
46214b393eeSKent Overstreet 		if (ret)
46314b393eeSKent Overstreet 			goto err;
46414b393eeSKent Overstreet 
46514b393eeSKent Overstreet 		bkey_reassemble(&parent->k_i, k);
46614b393eeSKent Overstreet 
46714b393eeSKent Overstreet 		for (i = 0; i < 2; i++)
46814b393eeSKent Overstreet 			if (le32_to_cpu(parent->v.children[i]) == id)
46914b393eeSKent Overstreet 				break;
47014b393eeSKent Overstreet 
47114b393eeSKent Overstreet 		if (i == 2)
47214b393eeSKent Overstreet 			bch_err(trans->c, "snapshot %u missing child pointer to %u",
47314b393eeSKent Overstreet 				parent_id, id);
47414b393eeSKent Overstreet 		else
47514b393eeSKent Overstreet 			parent->v.children[i] = 0;
47614b393eeSKent Overstreet 
47714b393eeSKent Overstreet 		if (le32_to_cpu(parent->v.children[0]) <
47814b393eeSKent Overstreet 		    le32_to_cpu(parent->v.children[1]))
47914b393eeSKent Overstreet 			swap(parent->v.children[0],
48014b393eeSKent Overstreet 			     parent->v.children[1]);
48114b393eeSKent Overstreet 
48214b393eeSKent Overstreet 		ret = bch2_trans_update(trans, &p_iter, &parent->k_i, 0);
48314b393eeSKent Overstreet 		if (ret)
48414b393eeSKent Overstreet 			goto err;
48514b393eeSKent Overstreet 	}
48614b393eeSKent Overstreet 
48714b393eeSKent Overstreet 	ret = bch2_btree_delete_at(trans, &iter, 0);
48814b393eeSKent Overstreet err:
48914b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &p_iter);
49014b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
49114b393eeSKent Overstreet 	return ret;
49214b393eeSKent Overstreet }
49314b393eeSKent Overstreet 
4947f6ff935SKent Overstreet int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent,
49514b393eeSKent Overstreet 			      u32 *new_snapids,
49614b393eeSKent Overstreet 			      u32 *snapshot_subvols,
49714b393eeSKent Overstreet 			      unsigned nr_snapids)
49814b393eeSKent Overstreet {
49914b393eeSKent Overstreet 	struct btree_iter iter;
50014b393eeSKent Overstreet 	struct bkey_i_snapshot *n;
50114b393eeSKent Overstreet 	struct bkey_s_c k;
50214b393eeSKent Overstreet 	unsigned i;
50314b393eeSKent Overstreet 	int ret = 0;
50414b393eeSKent Overstreet 
50514b393eeSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots,
50614b393eeSKent Overstreet 			     POS_MIN, BTREE_ITER_INTENT);
50714b393eeSKent Overstreet 	k = bch2_btree_iter_peek(&iter);
50814b393eeSKent Overstreet 	ret = bkey_err(k);
50914b393eeSKent Overstreet 	if (ret)
51014b393eeSKent Overstreet 		goto err;
51114b393eeSKent Overstreet 
51214b393eeSKent Overstreet 	for (i = 0; i < nr_snapids; i++) {
51314b393eeSKent Overstreet 		k = bch2_btree_iter_prev_slot(&iter);
51414b393eeSKent Overstreet 		ret = bkey_err(k);
51514b393eeSKent Overstreet 		if (ret)
51614b393eeSKent Overstreet 			goto err;
51714b393eeSKent Overstreet 
51814b393eeSKent Overstreet 		if (!k.k || !k.k->p.offset) {
51914b393eeSKent Overstreet 			ret = -ENOSPC;
52014b393eeSKent Overstreet 			goto err;
52114b393eeSKent Overstreet 		}
52214b393eeSKent Overstreet 
52314b393eeSKent Overstreet 		n = bch2_trans_kmalloc(trans, sizeof(*n));
52414b393eeSKent Overstreet 		ret = PTR_ERR_OR_ZERO(n);
52514b393eeSKent Overstreet 		if (ret)
52694a3e1a6SKent Overstreet 			goto err;
52714b393eeSKent Overstreet 
52814b393eeSKent Overstreet 		bkey_snapshot_init(&n->k_i);
52914b393eeSKent Overstreet 		n->k.p		= iter.pos;
53014b393eeSKent Overstreet 		n->v.flags	= 0;
53114b393eeSKent Overstreet 		n->v.parent	= cpu_to_le32(parent);
53214b393eeSKent Overstreet 		n->v.subvol	= cpu_to_le32(snapshot_subvols[i]);
53314b393eeSKent Overstreet 		n->v.pad	= 0;
53414b393eeSKent Overstreet 		SET_BCH_SNAPSHOT_SUBVOL(&n->v, true);
53514b393eeSKent Overstreet 
53694a3e1a6SKent Overstreet 		ret   = bch2_trans_update(trans, &iter, &n->k_i, 0) ?:
53794a3e1a6SKent Overstreet 			bch2_mark_snapshot(trans, bkey_s_c_null, bkey_i_to_s_c(&n->k_i), 0);
53814b393eeSKent Overstreet 		if (ret)
53994a3e1a6SKent Overstreet 			goto err;
54014b393eeSKent Overstreet 
54114b393eeSKent Overstreet 		new_snapids[i]	= iter.pos.offset;
54214b393eeSKent Overstreet 	}
54314b393eeSKent Overstreet 
54414b393eeSKent Overstreet 	if (parent) {
54514b393eeSKent Overstreet 		bch2_btree_iter_set_pos(&iter, POS(0, parent));
54614b393eeSKent Overstreet 		k = bch2_btree_iter_peek(&iter);
54714b393eeSKent Overstreet 		ret = bkey_err(k);
54814b393eeSKent Overstreet 		if (ret)
54914b393eeSKent Overstreet 			goto err;
55014b393eeSKent Overstreet 
55114b393eeSKent Overstreet 		if (k.k->type != KEY_TYPE_snapshot) {
55214b393eeSKent Overstreet 			bch_err(trans->c, "snapshot %u not found", parent);
55314b393eeSKent Overstreet 			ret = -ENOENT;
55414b393eeSKent Overstreet 			goto err;
55514b393eeSKent Overstreet 		}
55614b393eeSKent Overstreet 
55714b393eeSKent Overstreet 		n = bch2_trans_kmalloc(trans, sizeof(*n));
55814b393eeSKent Overstreet 		ret = PTR_ERR_OR_ZERO(n);
55914b393eeSKent Overstreet 		if (ret)
560c4ecf802SKent Overstreet 			goto err;
56114b393eeSKent Overstreet 
56214b393eeSKent Overstreet 		bkey_reassemble(&n->k_i, k);
56314b393eeSKent Overstreet 
56414b393eeSKent Overstreet 		if (n->v.children[0] || n->v.children[1]) {
56514b393eeSKent Overstreet 			bch_err(trans->c, "Trying to add child snapshot nodes to parent that already has children");
56614b393eeSKent Overstreet 			ret = -EINVAL;
56714b393eeSKent Overstreet 			goto err;
56814b393eeSKent Overstreet 		}
56914b393eeSKent Overstreet 
57014b393eeSKent Overstreet 		n->v.children[0] = cpu_to_le32(new_snapids[0]);
57114b393eeSKent Overstreet 		n->v.children[1] = cpu_to_le32(new_snapids[1]);
57235f1a503SKent Overstreet 		n->v.subvol = 0;
57314b393eeSKent Overstreet 		SET_BCH_SNAPSHOT_SUBVOL(&n->v, false);
57494a3e1a6SKent Overstreet 		ret = bch2_trans_update(trans, &iter, &n->k_i, 0);
57594a3e1a6SKent Overstreet 		if (ret)
57694a3e1a6SKent Overstreet 			goto err;
57714b393eeSKent Overstreet 	}
57814b393eeSKent Overstreet err:
57914b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
58014b393eeSKent Overstreet 	return ret;
58114b393eeSKent Overstreet }
58214b393eeSKent Overstreet 
583*6738dd19SKent Overstreet static int snapshot_delete_key(struct btree_trans *trans,
584*6738dd19SKent Overstreet 			       struct btree_iter *iter,
585*6738dd19SKent Overstreet 			       struct bkey_s_c k,
58691d961baSKent Overstreet 			       snapshot_id_list *deleted,
587*6738dd19SKent Overstreet 			       snapshot_id_list *equiv_seen,
588*6738dd19SKent Overstreet 			       struct bpos *last_pos)
58914b393eeSKent Overstreet {
59014b393eeSKent Overstreet 	struct bch_fs *c = trans->c;
59114b393eeSKent Overstreet 	u32 equiv = snapshot_t(c, k.k->p.snapshot)->equiv;
59214b393eeSKent Overstreet 
593*6738dd19SKent Overstreet 	if (bkey_cmp(k.k->p, *last_pos))
594*6738dd19SKent Overstreet 		equiv_seen->nr = 0;
595*6738dd19SKent Overstreet 	*last_pos = k.k->p;
59614b393eeSKent Overstreet 
59714b393eeSKent Overstreet 	if (snapshot_list_has_id(deleted, k.k->p.snapshot) ||
598*6738dd19SKent Overstreet 	    snapshot_list_has_id(equiv_seen, equiv)) {
599*6738dd19SKent Overstreet 		return bch2_btree_delete_at(trans, iter,
600*6738dd19SKent Overstreet 					    BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
60114b393eeSKent Overstreet 	} else {
602*6738dd19SKent Overstreet 		return snapshot_list_add(c, equiv_seen, equiv);
60314b393eeSKent Overstreet 	}
60414b393eeSKent Overstreet }
60514b393eeSKent Overstreet 
606a1783320SKent Overstreet static int bch2_delete_redundant_snapshot(struct btree_trans *trans, struct btree_iter *iter,
607a1783320SKent Overstreet 					  struct bkey_s_c k)
608a1783320SKent Overstreet {
609a1783320SKent Overstreet 	struct bkey_s_c_snapshot snap;
610a1783320SKent Overstreet 	u32 children[2];
611a1783320SKent Overstreet 	int ret;
612a1783320SKent Overstreet 
613a1783320SKent Overstreet 	if (k.k->type != KEY_TYPE_snapshot)
614a1783320SKent Overstreet 		return 0;
615a1783320SKent Overstreet 
616a1783320SKent Overstreet 	snap = bkey_s_c_to_snapshot(k);
617a1783320SKent Overstreet 	if (BCH_SNAPSHOT_DELETED(snap.v) ||
618a1783320SKent Overstreet 	    BCH_SNAPSHOT_SUBVOL(snap.v))
619a1783320SKent Overstreet 		return 0;
620a1783320SKent Overstreet 
621a1783320SKent Overstreet 	children[0] = le32_to_cpu(snap.v->children[0]);
622a1783320SKent Overstreet 	children[1] = le32_to_cpu(snap.v->children[1]);
623a1783320SKent Overstreet 
624a1783320SKent Overstreet 	ret   = snapshot_live(trans, children[0]) ?:
625a1783320SKent Overstreet 		snapshot_live(trans, children[1]);
626a1783320SKent Overstreet 	if (ret < 0)
627a1783320SKent Overstreet 		return ret;
628a1783320SKent Overstreet 
629a1783320SKent Overstreet 	if (!ret)
630a1783320SKent Overstreet 		return bch2_snapshot_node_set_deleted(trans, k.k->p.offset);
631a1783320SKent Overstreet 	return 0;
632a1783320SKent Overstreet }
633a1783320SKent Overstreet 
6344ab35c34SKent Overstreet int bch2_delete_dead_snapshots(struct bch_fs *c)
63514b393eeSKent Overstreet {
63614b393eeSKent Overstreet 	struct btree_trans trans;
63714b393eeSKent Overstreet 	struct btree_iter iter;
63814b393eeSKent Overstreet 	struct bkey_s_c k;
63914b393eeSKent Overstreet 	struct bkey_s_c_snapshot snap;
64091d961baSKent Overstreet 	snapshot_id_list deleted = { 0 };
641a1783320SKent Overstreet 	u32 i, id;
64214b393eeSKent Overstreet 	int ret = 0;
64314b393eeSKent Overstreet 
6444ab35c34SKent Overstreet 	if (!test_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags))
6454ab35c34SKent Overstreet 		return 0;
6464ab35c34SKent Overstreet 
6474ab35c34SKent Overstreet 	if (!test_bit(BCH_FS_STARTED, &c->flags)) {
6484ab35c34SKent Overstreet 		ret = bch2_fs_read_write_early(c);
6494ab35c34SKent Overstreet 		if (ret) {
6504ab35c34SKent Overstreet 			bch_err(c, "error deleleting dead snapshots: error going rw: %i", ret);
6514ab35c34SKent Overstreet 			return ret;
6524ab35c34SKent Overstreet 		}
6534ab35c34SKent Overstreet 	}
6544ab35c34SKent Overstreet 
65514b393eeSKent Overstreet 	bch2_trans_init(&trans, c, 0, 0);
65614b393eeSKent Overstreet 
65714b393eeSKent Overstreet 	/*
65814b393eeSKent Overstreet 	 * For every snapshot node: If we have no live children and it's not
65914b393eeSKent Overstreet 	 * pointed to by a subvolume, delete it:
66014b393eeSKent Overstreet 	 */
661a1783320SKent Overstreet 	ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_snapshots,
662a1783320SKent Overstreet 			POS_MIN, 0, k,
663a1783320SKent Overstreet 			NULL, NULL, 0,
664a1783320SKent Overstreet 		bch2_delete_redundant_snapshot(&trans, &iter, k));
66514b393eeSKent Overstreet 	if (ret) {
666a1783320SKent Overstreet 		bch_err(c, "error deleting redundant snapshots: %i", ret);
66714b393eeSKent Overstreet 		goto err;
66814b393eeSKent Overstreet 	}
66914b393eeSKent Overstreet 
670a1783320SKent Overstreet 	for_each_btree_key2(&trans, iter, BTREE_ID_snapshots,
671a1783320SKent Overstreet 			   POS_MIN, 0, k,
672a1783320SKent Overstreet 		bch2_snapshot_set_equiv(&trans, k));
673a1783320SKent Overstreet 	if (ret) {
674a1783320SKent Overstreet 		bch_err(c, "error in bch2_snapshots_set_equiv: %i", ret);
67514b393eeSKent Overstreet 		goto err;
676a1783320SKent Overstreet 	}
67714b393eeSKent Overstreet 
67814b393eeSKent Overstreet 	for_each_btree_key(&trans, iter, BTREE_ID_snapshots,
67914b393eeSKent Overstreet 			   POS_MIN, 0, k, ret) {
68014b393eeSKent Overstreet 		if (k.k->type != KEY_TYPE_snapshot)
68114b393eeSKent Overstreet 			continue;
68214b393eeSKent Overstreet 
68314b393eeSKent Overstreet 		snap = bkey_s_c_to_snapshot(k);
68414b393eeSKent Overstreet 		if (BCH_SNAPSHOT_DELETED(snap.v)) {
685597dee1cSKent Overstreet 			ret = snapshot_list_add(c, &deleted, k.k->p.offset);
68614b393eeSKent Overstreet 			if (ret)
68714b393eeSKent Overstreet 				break;
68814b393eeSKent Overstreet 		}
68914b393eeSKent Overstreet 	}
69014b393eeSKent Overstreet 	bch2_trans_iter_exit(&trans, &iter);
69114b393eeSKent Overstreet 
69214b393eeSKent Overstreet 	if (ret) {
69314b393eeSKent Overstreet 		bch_err(c, "error walking snapshots: %i", ret);
69414b393eeSKent Overstreet 		goto err;
69514b393eeSKent Overstreet 	}
69614b393eeSKent Overstreet 
69714b393eeSKent Overstreet 	for (id = 0; id < BTREE_ID_NR; id++) {
698*6738dd19SKent Overstreet 		struct bpos last_pos = POS_MIN;
699*6738dd19SKent Overstreet 		snapshot_id_list equiv_seen = { 0 };
700*6738dd19SKent Overstreet 
70114b393eeSKent Overstreet 		if (!btree_type_has_snapshots(id))
70214b393eeSKent Overstreet 			continue;
70314b393eeSKent Overstreet 
704*6738dd19SKent Overstreet 		ret = for_each_btree_key_commit(&trans, iter,
705*6738dd19SKent Overstreet 				id, POS_MIN,
706*6738dd19SKent Overstreet 				BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
707*6738dd19SKent Overstreet 				NULL, NULL, BTREE_INSERT_NOFAIL,
708*6738dd19SKent Overstreet 			snapshot_delete_key(&trans, &iter, k, &deleted, &equiv_seen, &last_pos));
709*6738dd19SKent Overstreet 
710*6738dd19SKent Overstreet 		darray_exit(&equiv_seen);
711*6738dd19SKent Overstreet 
71214b393eeSKent Overstreet 		if (ret) {
71314b393eeSKent Overstreet 			bch_err(c, "error deleting snapshot keys: %i", ret);
71414b393eeSKent Overstreet 			goto err;
71514b393eeSKent Overstreet 		}
71614b393eeSKent Overstreet 	}
71714b393eeSKent Overstreet 
71814b393eeSKent Overstreet 	for (i = 0; i < deleted.nr; i++) {
719e68914caSKent Overstreet 		ret = commit_do(&trans, NULL, NULL, 0,
72091d961baSKent Overstreet 			bch2_snapshot_node_delete(&trans, deleted.data[i]));
72114b393eeSKent Overstreet 		if (ret) {
72214b393eeSKent Overstreet 			bch_err(c, "error deleting snapshot %u: %i",
72391d961baSKent Overstreet 				deleted.data[i], ret);
72414b393eeSKent Overstreet 			goto err;
72514b393eeSKent Overstreet 		}
72614b393eeSKent Overstreet 	}
7274ab35c34SKent Overstreet 
7284ab35c34SKent Overstreet 	clear_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags);
72914b393eeSKent Overstreet err:
73091d961baSKent Overstreet 	darray_exit(&deleted);
73114b393eeSKent Overstreet 	bch2_trans_exit(&trans);
7324ab35c34SKent Overstreet 	return ret;
7334ab35c34SKent Overstreet }
7344ab35c34SKent Overstreet 
7354ab35c34SKent Overstreet static void bch2_delete_dead_snapshots_work(struct work_struct *work)
7364ab35c34SKent Overstreet {
7374ab35c34SKent Overstreet 	struct bch_fs *c = container_of(work, struct bch_fs, snapshot_delete_work);
7384ab35c34SKent Overstreet 
7394ab35c34SKent Overstreet 	bch2_delete_dead_snapshots(c);
74014b393eeSKent Overstreet 	percpu_ref_put(&c->writes);
74114b393eeSKent Overstreet }
74214b393eeSKent Overstreet 
7434ab35c34SKent Overstreet void bch2_delete_dead_snapshots_async(struct bch_fs *c)
74414b393eeSKent Overstreet {
7454ab35c34SKent Overstreet 	if (!percpu_ref_tryget_live(&c->writes))
74614b393eeSKent Overstreet 		return;
74714b393eeSKent Overstreet 
74814b393eeSKent Overstreet 	if (!queue_work(system_long_wq, &c->snapshot_delete_work))
74914b393eeSKent Overstreet 		percpu_ref_put(&c->writes);
75014b393eeSKent Overstreet }
75114b393eeSKent Overstreet 
75214b393eeSKent Overstreet static int bch2_delete_dead_snapshots_hook(struct btree_trans *trans,
75314b393eeSKent Overstreet 					   struct btree_trans_commit_hook *h)
75414b393eeSKent Overstreet {
7554ab35c34SKent Overstreet 	struct bch_fs *c = trans->c;
7564ab35c34SKent Overstreet 
7574ab35c34SKent Overstreet 	set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags);
7584ab35c34SKent Overstreet 
7594ab35c34SKent Overstreet 	if (!test_bit(BCH_FS_FSCK_DONE, &c->flags))
7604ab35c34SKent Overstreet 		return 0;
7614ab35c34SKent Overstreet 
7624ab35c34SKent Overstreet 	bch2_delete_dead_snapshots_async(c);
76314b393eeSKent Overstreet 	return 0;
76414b393eeSKent Overstreet }
76514b393eeSKent Overstreet 
76614b393eeSKent Overstreet /* Subvolumes: */
76714b393eeSKent Overstreet 
768f0ac7df2SKent Overstreet int bch2_subvolume_invalid(const struct bch_fs *c, struct bkey_s_c k,
769275c8426SKent Overstreet 			   int rw, struct printbuf *err)
77014b393eeSKent Overstreet {
771f0ac7df2SKent Overstreet 	if (bkey_cmp(k.k->p, SUBVOL_POS_MIN) < 0 ||
772f0ac7df2SKent Overstreet 	    bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) {
773401ec4dbSKent Overstreet 		prt_printf(err, "invalid pos");
774f0ac7df2SKent Overstreet 		return -EINVAL;
775f0ac7df2SKent Overstreet 	}
77614b393eeSKent Overstreet 
777f0ac7df2SKent Overstreet 	if (bkey_val_bytes(k.k) != sizeof(struct bch_subvolume)) {
778401ec4dbSKent Overstreet 		prt_printf(err, "incorrect value size (%zu != %zu)",
779f0ac7df2SKent Overstreet 		       bkey_val_bytes(k.k), sizeof(struct bch_subvolume));
780f0ac7df2SKent Overstreet 		return -EINVAL;
781f0ac7df2SKent Overstreet 	}
78214b393eeSKent Overstreet 
783f0ac7df2SKent Overstreet 	return 0;
78414b393eeSKent Overstreet }
78514b393eeSKent Overstreet 
78614b393eeSKent Overstreet void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c,
78714b393eeSKent Overstreet 			    struct bkey_s_c k)
78814b393eeSKent Overstreet {
78914b393eeSKent Overstreet 	struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k);
79014b393eeSKent Overstreet 
791401ec4dbSKent Overstreet 	prt_printf(out, "root %llu snapshot id %u",
79214b393eeSKent Overstreet 	       le64_to_cpu(s.v->inode),
79314b393eeSKent Overstreet 	       le32_to_cpu(s.v->snapshot));
79414b393eeSKent Overstreet }
79514b393eeSKent Overstreet 
79697996ddfSKent Overstreet int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol,
79797996ddfSKent Overstreet 		       bool inconsistent_if_not_found,
79897996ddfSKent Overstreet 		       int iter_flags,
79997996ddfSKent Overstreet 		       struct bch_subvolume *s)
80014b393eeSKent Overstreet {
80114b393eeSKent Overstreet 	struct btree_iter iter;
80214b393eeSKent Overstreet 	struct bkey_s_c k;
80314b393eeSKent Overstreet 	int ret;
80414b393eeSKent Overstreet 
80597996ddfSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, POS(0, subvol),
80697996ddfSKent Overstreet 			     iter_flags);
80714b393eeSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
80897996ddfSKent Overstreet 	ret = bkey_err(k) ?: k.k->type == KEY_TYPE_subvolume ? 0 : -ENOENT;
80914b393eeSKent Overstreet 
81097996ddfSKent Overstreet 	if (ret == -ENOENT && inconsistent_if_not_found)
81114b393eeSKent Overstreet 		bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvol);
81297996ddfSKent Overstreet 	if (!ret)
81397996ddfSKent Overstreet 		*s = *bkey_s_c_to_subvolume(k).v;
81497996ddfSKent Overstreet 
81597996ddfSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
81697996ddfSKent Overstreet 	return ret;
81714b393eeSKent Overstreet }
81814b393eeSKent Overstreet 
8199ca4853bSKent Overstreet int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot,
8209ca4853bSKent Overstreet 			     struct bch_subvolume *subvol)
8219ca4853bSKent Overstreet {
8229ca4853bSKent Overstreet 	struct bch_snapshot snap;
8239ca4853bSKent Overstreet 
8249ca4853bSKent Overstreet 	return  snapshot_lookup(trans, snapshot, &snap) ?:
8259ca4853bSKent Overstreet 		bch2_subvolume_get(trans, le32_to_cpu(snap.subvol), true, 0, subvol);
8269ca4853bSKent Overstreet }
8279ca4853bSKent Overstreet 
82897996ddfSKent Overstreet int bch2_subvolume_get_snapshot(struct btree_trans *trans, u32 subvol,
82997996ddfSKent Overstreet 				u32 *snapid)
83097996ddfSKent Overstreet {
83197996ddfSKent Overstreet 	struct bch_subvolume s;
83297996ddfSKent Overstreet 	int ret;
83397996ddfSKent Overstreet 
83497996ddfSKent Overstreet 	ret = bch2_subvolume_get(trans, subvol, true,
83597996ddfSKent Overstreet 				 BTREE_ITER_CACHED|
83697996ddfSKent Overstreet 				 BTREE_ITER_WITH_UPDATES,
83797996ddfSKent Overstreet 				 &s);
83897996ddfSKent Overstreet 
83997996ddfSKent Overstreet 	*snapid = le32_to_cpu(s.snapshot);
84014b393eeSKent Overstreet 	return ret;
84114b393eeSKent Overstreet }
84214b393eeSKent Overstreet 
8432027875bSKent Overstreet /*
8442027875bSKent Overstreet  * Delete subvolume, mark snapshot ID as deleted, queue up snapshot
8452027875bSKent Overstreet  * deletion/cleanup:
8462027875bSKent Overstreet  */
8472027875bSKent Overstreet int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
84814b393eeSKent Overstreet {
84914b393eeSKent Overstreet 	struct btree_iter iter;
85014b393eeSKent Overstreet 	struct bkey_s_c k;
85114b393eeSKent Overstreet 	struct bkey_s_c_subvolume subvol;
85214b393eeSKent Overstreet 	struct btree_trans_commit_hook *h;
85314b393eeSKent Overstreet 	u32 snapid;
85414b393eeSKent Overstreet 	int ret = 0;
85514b393eeSKent Overstreet 
85614b393eeSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes,
85714b393eeSKent Overstreet 			     POS(0, subvolid),
85814b393eeSKent Overstreet 			     BTREE_ITER_CACHED|
85914b393eeSKent Overstreet 			     BTREE_ITER_INTENT);
86014b393eeSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
86114b393eeSKent Overstreet 	ret = bkey_err(k);
86214b393eeSKent Overstreet 	if (ret)
86314b393eeSKent Overstreet 		goto err;
86414b393eeSKent Overstreet 
86514b393eeSKent Overstreet 	if (k.k->type != KEY_TYPE_subvolume) {
86614b393eeSKent Overstreet 		bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid);
86714b393eeSKent Overstreet 		ret = -EIO;
86814b393eeSKent Overstreet 		goto err;
86914b393eeSKent Overstreet 	}
87014b393eeSKent Overstreet 
87114b393eeSKent Overstreet 	subvol = bkey_s_c_to_subvolume(k);
87214b393eeSKent Overstreet 	snapid = le32_to_cpu(subvol.v->snapshot);
87314b393eeSKent Overstreet 
874416cc426SKent Overstreet 	ret = bch2_btree_delete_at(trans, &iter, 0);
87514b393eeSKent Overstreet 	if (ret)
87614b393eeSKent Overstreet 		goto err;
87714b393eeSKent Overstreet 
87814b393eeSKent Overstreet 	ret = bch2_snapshot_node_set_deleted(trans, snapid);
87914b393eeSKent Overstreet 
88014b393eeSKent Overstreet 	h = bch2_trans_kmalloc(trans, sizeof(*h));
88114b393eeSKent Overstreet 	ret = PTR_ERR_OR_ZERO(h);
88214b393eeSKent Overstreet 	if (ret)
88314b393eeSKent Overstreet 		goto err;
88414b393eeSKent Overstreet 
88514b393eeSKent Overstreet 	h->fn = bch2_delete_dead_snapshots_hook;
88614b393eeSKent Overstreet 	bch2_trans_commit_hook(trans, h);
88714b393eeSKent Overstreet err:
88814b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
88914b393eeSKent Overstreet 	return ret;
89014b393eeSKent Overstreet }
89114b393eeSKent Overstreet 
8922027875bSKent Overstreet void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
8932027875bSKent Overstreet {
8942027875bSKent Overstreet 	struct bch_fs *c = container_of(work, struct bch_fs,
8952027875bSKent Overstreet 				snapshot_wait_for_pagecache_and_delete_work);
89691d961baSKent Overstreet 	snapshot_id_list s;
8972027875bSKent Overstreet 	u32 *id;
8982027875bSKent Overstreet 	int ret = 0;
8992027875bSKent Overstreet 
9002027875bSKent Overstreet 	while (!ret) {
9012027875bSKent Overstreet 		mutex_lock(&c->snapshots_unlinked_lock);
9022027875bSKent Overstreet 		s = c->snapshots_unlinked;
90391d961baSKent Overstreet 		darray_init(&c->snapshots_unlinked);
9042027875bSKent Overstreet 		mutex_unlock(&c->snapshots_unlinked_lock);
9052027875bSKent Overstreet 
9062027875bSKent Overstreet 		if (!s.nr)
9072027875bSKent Overstreet 			break;
9082027875bSKent Overstreet 
9092027875bSKent Overstreet 		bch2_evict_subvolume_inodes(c, &s);
9102027875bSKent Overstreet 
91191d961baSKent Overstreet 		for (id = s.data; id < s.data + s.nr; id++) {
9122027875bSKent Overstreet 			ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL,
9132027875bSKent Overstreet 				      bch2_subvolume_delete(&trans, *id));
9142027875bSKent Overstreet 			if (ret) {
9152027875bSKent Overstreet 				bch_err(c, "error %i deleting subvolume %u", ret, *id);
9162027875bSKent Overstreet 				break;
9172027875bSKent Overstreet 			}
9182027875bSKent Overstreet 		}
9192027875bSKent Overstreet 
92091d961baSKent Overstreet 		darray_exit(&s);
9212027875bSKent Overstreet 	}
9222027875bSKent Overstreet 
9232027875bSKent Overstreet 	percpu_ref_put(&c->writes);
9242027875bSKent Overstreet }
9252027875bSKent Overstreet 
9262027875bSKent Overstreet struct subvolume_unlink_hook {
9272027875bSKent Overstreet 	struct btree_trans_commit_hook	h;
9282027875bSKent Overstreet 	u32				subvol;
9292027875bSKent Overstreet };
9302027875bSKent Overstreet 
9312027875bSKent Overstreet int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans *trans,
9322027875bSKent Overstreet 						      struct btree_trans_commit_hook *_h)
9332027875bSKent Overstreet {
9342027875bSKent Overstreet 	struct subvolume_unlink_hook *h = container_of(_h, struct subvolume_unlink_hook, h);
9352027875bSKent Overstreet 	struct bch_fs *c = trans->c;
9362027875bSKent Overstreet 	int ret = 0;
9372027875bSKent Overstreet 
9382027875bSKent Overstreet 	mutex_lock(&c->snapshots_unlinked_lock);
9392027875bSKent Overstreet 	if (!snapshot_list_has_id(&c->snapshots_unlinked, h->subvol))
940597dee1cSKent Overstreet 		ret = snapshot_list_add(c, &c->snapshots_unlinked, h->subvol);
9412027875bSKent Overstreet 	mutex_unlock(&c->snapshots_unlinked_lock);
9422027875bSKent Overstreet 
9432027875bSKent Overstreet 	if (ret)
9442027875bSKent Overstreet 		return ret;
9452027875bSKent Overstreet 
946a3d7afa5SKent Overstreet 	if (unlikely(!percpu_ref_tryget_live(&c->writes)))
9472027875bSKent Overstreet 		return -EROFS;
9482027875bSKent Overstreet 
9492027875bSKent Overstreet 	if (!queue_work(system_long_wq, &c->snapshot_wait_for_pagecache_and_delete_work))
9502027875bSKent Overstreet 		percpu_ref_put(&c->writes);
9512027875bSKent Overstreet 	return 0;
9522027875bSKent Overstreet }
9532027875bSKent Overstreet 
9542027875bSKent Overstreet int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid)
9552027875bSKent Overstreet {
9562027875bSKent Overstreet 	struct btree_iter iter;
9572027875bSKent Overstreet 	struct bkey_s_c k;
9582027875bSKent Overstreet 	struct bkey_i_subvolume *n;
9592027875bSKent Overstreet 	struct subvolume_unlink_hook *h;
9602027875bSKent Overstreet 	int ret = 0;
9612027875bSKent Overstreet 
9622027875bSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes,
9632027875bSKent Overstreet 			     POS(0, subvolid),
9642027875bSKent Overstreet 			     BTREE_ITER_CACHED|
9652027875bSKent Overstreet 			     BTREE_ITER_INTENT);
9662027875bSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
9672027875bSKent Overstreet 	ret = bkey_err(k);
9682027875bSKent Overstreet 	if (ret)
9692027875bSKent Overstreet 		goto err;
9702027875bSKent Overstreet 
9712027875bSKent Overstreet 	if (k.k->type != KEY_TYPE_subvolume) {
9722027875bSKent Overstreet 		bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid);
9732027875bSKent Overstreet 		ret = -EIO;
9742027875bSKent Overstreet 		goto err;
9752027875bSKent Overstreet 	}
9762027875bSKent Overstreet 
9772027875bSKent Overstreet 	n = bch2_trans_kmalloc(trans, sizeof(*n));
9782027875bSKent Overstreet 	ret = PTR_ERR_OR_ZERO(n);
9792027875bSKent Overstreet 	if (ret)
9802027875bSKent Overstreet 		goto err;
9812027875bSKent Overstreet 
9822027875bSKent Overstreet 	bkey_reassemble(&n->k_i, k);
9832027875bSKent Overstreet 	SET_BCH_SUBVOLUME_UNLINKED(&n->v, true);
9842027875bSKent Overstreet 
9852027875bSKent Overstreet 	ret = bch2_trans_update(trans, &iter, &n->k_i, 0);
9862027875bSKent Overstreet 	if (ret)
9872027875bSKent Overstreet 		goto err;
9882027875bSKent Overstreet 
9892027875bSKent Overstreet 	h = bch2_trans_kmalloc(trans, sizeof(*h));
9902027875bSKent Overstreet 	ret = PTR_ERR_OR_ZERO(h);
9912027875bSKent Overstreet 	if (ret)
9922027875bSKent Overstreet 		goto err;
9932027875bSKent Overstreet 
9942027875bSKent Overstreet 	h->h.fn		= bch2_subvolume_wait_for_pagecache_and_delete_hook;
9952027875bSKent Overstreet 	h->subvol	= subvolid;
9962027875bSKent Overstreet 	bch2_trans_commit_hook(trans, &h->h);
9972027875bSKent Overstreet err:
9982027875bSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
9992027875bSKent Overstreet 	return ret;
10002027875bSKent Overstreet }
10012027875bSKent Overstreet 
100214b393eeSKent Overstreet int bch2_subvolume_create(struct btree_trans *trans, u64 inode,
100314b393eeSKent Overstreet 			  u32 src_subvolid,
100414b393eeSKent Overstreet 			  u32 *new_subvolid,
100514b393eeSKent Overstreet 			  u32 *new_snapshotid,
100614b393eeSKent Overstreet 			  bool ro)
100714b393eeSKent Overstreet {
1008ca130b9cSKent Overstreet 	struct bch_fs *c = trans->c;
100914b393eeSKent Overstreet 	struct btree_iter dst_iter, src_iter = (struct btree_iter) { NULL };
101014b393eeSKent Overstreet 	struct bkey_i_subvolume *new_subvol = NULL;
101114b393eeSKent Overstreet 	struct bkey_i_subvolume *src_subvol = NULL;
101214b393eeSKent Overstreet 	struct bkey_s_c k;
101314b393eeSKent Overstreet 	u32 parent = 0, new_nodes[2], snapshot_subvols[2];
101414b393eeSKent Overstreet 	int ret = 0;
101514b393eeSKent Overstreet 
101614b393eeSKent Overstreet 	for_each_btree_key(trans, dst_iter, BTREE_ID_subvolumes, SUBVOL_POS_MIN,
101714b393eeSKent Overstreet 			   BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
101814b393eeSKent Overstreet 		if (bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0)
101914b393eeSKent Overstreet 			break;
1020ca130b9cSKent Overstreet 
1021ca130b9cSKent Overstreet 		/*
1022ca130b9cSKent Overstreet 		 * bch2_subvolume_delete() doesn't flush the btree key cache -
1023ca130b9cSKent Overstreet 		 * ideally it would but that's tricky
1024ca130b9cSKent Overstreet 		 */
1025ca130b9cSKent Overstreet 		if (bkey_deleted(k.k) &&
1026ca130b9cSKent Overstreet 		    !bch2_btree_key_cache_find(c, BTREE_ID_subvolumes, dst_iter.pos))
102714b393eeSKent Overstreet 			goto found_slot;
102814b393eeSKent Overstreet 	}
102914b393eeSKent Overstreet 
103014b393eeSKent Overstreet 	if (!ret)
103114b393eeSKent Overstreet 		ret = -ENOSPC;
103214b393eeSKent Overstreet 	goto err;
103314b393eeSKent Overstreet found_slot:
103414b393eeSKent Overstreet 	snapshot_subvols[0] = dst_iter.pos.offset;
103514b393eeSKent Overstreet 	snapshot_subvols[1] = src_subvolid;
103614b393eeSKent Overstreet 
103714b393eeSKent Overstreet 	if (src_subvolid) {
103814b393eeSKent Overstreet 		/* Creating a snapshot: */
103914b393eeSKent Overstreet 		src_subvol = bch2_trans_kmalloc(trans, sizeof(*src_subvol));
104014b393eeSKent Overstreet 		ret = PTR_ERR_OR_ZERO(src_subvol);
104114b393eeSKent Overstreet 		if (ret)
104214b393eeSKent Overstreet 			goto err;
104314b393eeSKent Overstreet 
104414b393eeSKent Overstreet 		bch2_trans_iter_init(trans, &src_iter, BTREE_ID_subvolumes,
104514b393eeSKent Overstreet 				     POS(0, src_subvolid),
104614b393eeSKent Overstreet 				     BTREE_ITER_CACHED|
104714b393eeSKent Overstreet 				     BTREE_ITER_INTENT);
104814b393eeSKent Overstreet 		k = bch2_btree_iter_peek_slot(&src_iter);
104914b393eeSKent Overstreet 		ret = bkey_err(k);
105014b393eeSKent Overstreet 		if (ret)
105114b393eeSKent Overstreet 			goto err;
105214b393eeSKent Overstreet 
105314b393eeSKent Overstreet 		if (k.k->type != KEY_TYPE_subvolume) {
1054ca130b9cSKent Overstreet 			bch_err(c, "subvolume %u not found", src_subvolid);
105514b393eeSKent Overstreet 			ret = -ENOENT;
105614b393eeSKent Overstreet 			goto err;
105714b393eeSKent Overstreet 		}
105814b393eeSKent Overstreet 
105914b393eeSKent Overstreet 		bkey_reassemble(&src_subvol->k_i, k);
106014b393eeSKent Overstreet 		parent = le32_to_cpu(src_subvol->v.snapshot);
106114b393eeSKent Overstreet 	}
106214b393eeSKent Overstreet 
106314b393eeSKent Overstreet 	ret = bch2_snapshot_node_create(trans, parent, new_nodes,
106414b393eeSKent Overstreet 					snapshot_subvols,
106514b393eeSKent Overstreet 					src_subvolid ? 2 : 1);
106614b393eeSKent Overstreet 	if (ret)
106714b393eeSKent Overstreet 		goto err;
106814b393eeSKent Overstreet 
106914b393eeSKent Overstreet 	if (src_subvolid) {
107014b393eeSKent Overstreet 		src_subvol->v.snapshot = cpu_to_le32(new_nodes[1]);
107194a3e1a6SKent Overstreet 		ret = bch2_trans_update(trans, &src_iter, &src_subvol->k_i, 0);
107294a3e1a6SKent Overstreet 		if (ret)
107394a3e1a6SKent Overstreet 			goto err;
107414b393eeSKent Overstreet 	}
107514b393eeSKent Overstreet 
107614b393eeSKent Overstreet 	new_subvol = bch2_trans_kmalloc(trans, sizeof(*new_subvol));
107714b393eeSKent Overstreet 	ret = PTR_ERR_OR_ZERO(new_subvol);
107814b393eeSKent Overstreet 	if (ret)
107914b393eeSKent Overstreet 		goto err;
108014b393eeSKent Overstreet 
108114b393eeSKent Overstreet 	bkey_subvolume_init(&new_subvol->k_i);
108214b393eeSKent Overstreet 	new_subvol->v.flags	= 0;
108314b393eeSKent Overstreet 	new_subvol->v.snapshot	= cpu_to_le32(new_nodes[0]);
108414b393eeSKent Overstreet 	new_subvol->v.inode	= cpu_to_le64(inode);
108514b393eeSKent Overstreet 	SET_BCH_SUBVOLUME_RO(&new_subvol->v, ro);
108614b393eeSKent Overstreet 	SET_BCH_SUBVOLUME_SNAP(&new_subvol->v, src_subvolid != 0);
108714b393eeSKent Overstreet 	new_subvol->k.p		= dst_iter.pos;
108894a3e1a6SKent Overstreet 	ret = bch2_trans_update(trans, &dst_iter, &new_subvol->k_i, 0);
108994a3e1a6SKent Overstreet 	if (ret)
109094a3e1a6SKent Overstreet 		goto err;
109114b393eeSKent Overstreet 
109214b393eeSKent Overstreet 	*new_subvolid	= new_subvol->k.p.offset;
109314b393eeSKent Overstreet 	*new_snapshotid	= new_nodes[0];
109414b393eeSKent Overstreet err:
109514b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &src_iter);
109614b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &dst_iter);
109714b393eeSKent Overstreet 	return ret;
109814b393eeSKent Overstreet }
109914b393eeSKent Overstreet 
110014b393eeSKent Overstreet int bch2_fs_subvolumes_init(struct bch_fs *c)
110114b393eeSKent Overstreet {
110214b393eeSKent Overstreet 	INIT_WORK(&c->snapshot_delete_work, bch2_delete_dead_snapshots_work);
11032027875bSKent Overstreet 	INIT_WORK(&c->snapshot_wait_for_pagecache_and_delete_work,
11042027875bSKent Overstreet 		  bch2_subvolume_wait_for_pagecache_and_delete);
11052027875bSKent Overstreet 	mutex_init(&c->snapshots_unlinked_lock);
110614b393eeSKent Overstreet 	return 0;
110714b393eeSKent Overstreet }
1108