xref: /linux/fs/bcachefs/subvolume.c (revision a10195764901e0a41e64d596de57a957e7f982f0)
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"
6d4bf5eecSKent Overstreet #include "errcode.h"
714b393eeSKent Overstreet #include "error.h"
82027875bSKent Overstreet #include "fs.h"
914b393eeSKent Overstreet #include "subvolume.h"
1014b393eeSKent Overstreet 
1114b393eeSKent Overstreet /* Snapshot tree: */
1214b393eeSKent Overstreet 
1314b393eeSKent Overstreet void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c,
1414b393eeSKent Overstreet 			   struct bkey_s_c k)
1514b393eeSKent Overstreet {
1614b393eeSKent Overstreet 	struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(k);
1714b393eeSKent Overstreet 
18416cc426SKent Overstreet 	prt_printf(out, "is_subvol %llu deleted %llu parent %10u children %10u %10u subvol %u",
1914b393eeSKent Overstreet 	       BCH_SNAPSHOT_SUBVOL(s.v),
2014b393eeSKent Overstreet 	       BCH_SNAPSHOT_DELETED(s.v),
2114b393eeSKent Overstreet 	       le32_to_cpu(s.v->parent),
2214b393eeSKent Overstreet 	       le32_to_cpu(s.v->children[0]),
2314b393eeSKent Overstreet 	       le32_to_cpu(s.v->children[1]),
2414b393eeSKent Overstreet 	       le32_to_cpu(s.v->subvol));
2514b393eeSKent Overstreet }
2614b393eeSKent Overstreet 
27f0ac7df2SKent Overstreet int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k,
28275c8426SKent Overstreet 			  int rw, struct printbuf *err)
2914b393eeSKent Overstreet {
3014b393eeSKent Overstreet 	struct bkey_s_c_snapshot s;
3114b393eeSKent Overstreet 	u32 i, id;
3214b393eeSKent Overstreet 
3314b393eeSKent Overstreet 	if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0 ||
34f0ac7df2SKent Overstreet 	    bkey_cmp(k.k->p, POS(0, 1)) < 0) {
35401ec4dbSKent Overstreet 		prt_printf(err, "bad pos");
36f0ac7df2SKent Overstreet 		return -EINVAL;
37f0ac7df2SKent Overstreet 	}
3814b393eeSKent Overstreet 
39f0ac7df2SKent Overstreet 	if (bkey_val_bytes(k.k) != sizeof(struct bch_snapshot)) {
40401ec4dbSKent Overstreet 		prt_printf(err, "bad val size (%zu != %zu)",
41f0ac7df2SKent Overstreet 		       bkey_val_bytes(k.k), sizeof(struct bch_snapshot));
42f0ac7df2SKent Overstreet 		return -EINVAL;
43f0ac7df2SKent Overstreet 	}
4414b393eeSKent Overstreet 
4514b393eeSKent Overstreet 	s = bkey_s_c_to_snapshot(k);
4614b393eeSKent Overstreet 
4714b393eeSKent Overstreet 	id = le32_to_cpu(s.v->parent);
48f0ac7df2SKent Overstreet 	if (id && id <= k.k->p.offset) {
49401ec4dbSKent Overstreet 		prt_printf(err, "bad parent node (%u <= %llu)",
50f0ac7df2SKent Overstreet 		       id, k.k->p.offset);
51f0ac7df2SKent Overstreet 		return -EINVAL;
52f0ac7df2SKent Overstreet 	}
5314b393eeSKent Overstreet 
54f0ac7df2SKent Overstreet 	if (le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1])) {
55401ec4dbSKent Overstreet 		prt_printf(err, "children not normalized");
56f0ac7df2SKent Overstreet 		return -EINVAL;
57f0ac7df2SKent Overstreet 	}
5814b393eeSKent Overstreet 
5914b393eeSKent Overstreet 	if (s.v->children[0] &&
60f0ac7df2SKent Overstreet 	    s.v->children[0] == s.v->children[1]) {
61401ec4dbSKent Overstreet 		prt_printf(err, "duplicate child nodes");
62f0ac7df2SKent Overstreet 		return -EINVAL;
63f0ac7df2SKent Overstreet 	}
6414b393eeSKent Overstreet 
6514b393eeSKent Overstreet 	for (i = 0; i < 2; i++) {
6614b393eeSKent Overstreet 		id = le32_to_cpu(s.v->children[i]);
6714b393eeSKent Overstreet 
68f0ac7df2SKent Overstreet 		if (id >= k.k->p.offset) {
69401ec4dbSKent Overstreet 			prt_printf(err, "bad child node (%u >= %llu)",
70f0ac7df2SKent Overstreet 			       id, k.k->p.offset);
71f0ac7df2SKent Overstreet 			return -EINVAL;
72f0ac7df2SKent Overstreet 		}
7314b393eeSKent Overstreet 	}
7414b393eeSKent Overstreet 
75f0ac7df2SKent Overstreet 	return 0;
7614b393eeSKent Overstreet }
7714b393eeSKent Overstreet 
78904823deSKent Overstreet int bch2_mark_snapshot(struct btree_trans *trans,
7914b393eeSKent Overstreet 		       struct bkey_s_c old, struct bkey_s_c new,
80904823deSKent Overstreet 		       unsigned flags)
8114b393eeSKent Overstreet {
82904823deSKent Overstreet 	struct bch_fs *c = trans->c;
8314b393eeSKent Overstreet 	struct snapshot_t *t;
8414b393eeSKent Overstreet 
8514b393eeSKent Overstreet 	t = genradix_ptr_alloc(&c->snapshots,
8614b393eeSKent Overstreet 			       U32_MAX - new.k->p.offset,
8714b393eeSKent Overstreet 			       GFP_KERNEL);
8814b393eeSKent Overstreet 	if (!t)
8914b393eeSKent Overstreet 		return -ENOMEM;
9014b393eeSKent Overstreet 
9114b393eeSKent Overstreet 	if (new.k->type == KEY_TYPE_snapshot) {
9214b393eeSKent Overstreet 		struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(new);
9314b393eeSKent Overstreet 
9414b393eeSKent Overstreet 		t->parent	= le32_to_cpu(s.v->parent);
9514b393eeSKent Overstreet 		t->children[0]	= le32_to_cpu(s.v->children[0]);
9614b393eeSKent Overstreet 		t->children[1]	= le32_to_cpu(s.v->children[1]);
9714b393eeSKent Overstreet 		t->subvol	= BCH_SNAPSHOT_SUBVOL(s.v) ? le32_to_cpu(s.v->subvol) : 0;
9814b393eeSKent Overstreet 	} else {
9914b393eeSKent Overstreet 		t->parent	= 0;
10014b393eeSKent Overstreet 		t->children[0]	= 0;
10114b393eeSKent Overstreet 		t->children[1]	= 0;
10214b393eeSKent Overstreet 		t->subvol	= 0;
10314b393eeSKent Overstreet 	}
10414b393eeSKent Overstreet 
10514b393eeSKent Overstreet 	return 0;
10614b393eeSKent Overstreet }
10714b393eeSKent Overstreet 
10814b393eeSKent Overstreet static int snapshot_lookup(struct btree_trans *trans, u32 id,
10914b393eeSKent Overstreet 			   struct bch_snapshot *s)
11014b393eeSKent Overstreet {
11114b393eeSKent Overstreet 	struct btree_iter iter;
11214b393eeSKent Overstreet 	struct bkey_s_c k;
11314b393eeSKent Overstreet 	int ret;
11414b393eeSKent Overstreet 
11514b393eeSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id),
11614b393eeSKent Overstreet 			     BTREE_ITER_WITH_UPDATES);
11714b393eeSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
11814b393eeSKent Overstreet 	ret = bkey_err(k) ?: k.k->type == KEY_TYPE_snapshot ? 0 : -ENOENT;
11914b393eeSKent Overstreet 
12014b393eeSKent Overstreet 	if (!ret)
12114b393eeSKent Overstreet 		*s = *bkey_s_c_to_snapshot(k).v;
12214b393eeSKent Overstreet 
12314b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
12414b393eeSKent Overstreet 	return ret;
12514b393eeSKent Overstreet }
12614b393eeSKent Overstreet 
12714b393eeSKent Overstreet static int snapshot_live(struct btree_trans *trans, u32 id)
12814b393eeSKent Overstreet {
12914b393eeSKent Overstreet 	struct bch_snapshot v;
13014b393eeSKent Overstreet 	int ret;
13114b393eeSKent Overstreet 
13214b393eeSKent Overstreet 	if (!id)
13314b393eeSKent Overstreet 		return 0;
13414b393eeSKent Overstreet 
135a1783320SKent Overstreet 	ret = snapshot_lookup(trans, id, &v);
13614b393eeSKent Overstreet 	if (ret == -ENOENT)
13714b393eeSKent Overstreet 		bch_err(trans->c, "snapshot node %u not found", id);
13814b393eeSKent Overstreet 	if (ret)
13914b393eeSKent Overstreet 		return ret;
14014b393eeSKent Overstreet 
14114b393eeSKent Overstreet 	return !BCH_SNAPSHOT_DELETED(&v);
14214b393eeSKent Overstreet }
14314b393eeSKent Overstreet 
144a1783320SKent Overstreet static int bch2_snapshot_set_equiv(struct btree_trans *trans, struct bkey_s_c k)
14514b393eeSKent Overstreet {
14614b393eeSKent Overstreet 	struct bch_fs *c = trans->c;
14735f1a503SKent Overstreet 	unsigned i, nr_live = 0, live_idx = 0;
148a1783320SKent Overstreet 	struct bkey_s_c_snapshot snap;
149a1783320SKent Overstreet 	u32 id = k.k->p.offset, child[2];
150a1783320SKent Overstreet 
151a1783320SKent Overstreet 	if (k.k->type != KEY_TYPE_snapshot)
152a1783320SKent Overstreet 		return 0;
153a1783320SKent Overstreet 
154a1783320SKent Overstreet 	snap = bkey_s_c_to_snapshot(k);
155a1783320SKent Overstreet 
156a1783320SKent Overstreet 	child[0] = le32_to_cpu(snap.v->children[0]);
157a1783320SKent Overstreet 	child[1] = le32_to_cpu(snap.v->children[1]);
15814b393eeSKent Overstreet 
15914b393eeSKent Overstreet 	for (i = 0; i < 2; i++) {
16035f1a503SKent Overstreet 		int ret = snapshot_live(trans, child[i]);
161*a1019576SKent Overstreet 
16214b393eeSKent Overstreet 		if (ret < 0)
16335f1a503SKent Overstreet 			return ret;
16414b393eeSKent Overstreet 
16514b393eeSKent Overstreet 		if (ret)
16614b393eeSKent Overstreet 			live_idx = i;
16714b393eeSKent Overstreet 		nr_live += ret;
16814b393eeSKent Overstreet 	}
16914b393eeSKent Overstreet 
17014b393eeSKent Overstreet 	snapshot_t(c, id)->equiv = nr_live == 1
17114b393eeSKent Overstreet 		? snapshot_t(c, child[live_idx])->equiv
17214b393eeSKent Overstreet 		: id;
17335f1a503SKent Overstreet 	return 0;
17414b393eeSKent Overstreet }
17535f1a503SKent Overstreet 
17614b393eeSKent Overstreet /* fsck: */
17735f1a503SKent Overstreet static int check_snapshot(struct btree_trans *trans,
178a1783320SKent Overstreet 			  struct btree_iter *iter,
179a1783320SKent Overstreet 			  struct bkey_s_c k)
18014b393eeSKent Overstreet {
18135f1a503SKent Overstreet 	struct bch_fs *c = trans->c;
18235f1a503SKent Overstreet 	struct bkey_s_c_snapshot s;
18314b393eeSKent Overstreet 	struct bch_subvolume subvol;
18414b393eeSKent Overstreet 	struct bch_snapshot v;
18535f1a503SKent Overstreet 	struct printbuf buf = PRINTBUF;
18635f1a503SKent Overstreet 	bool should_have_subvol;
18714b393eeSKent Overstreet 	u32 i, id;
18835f1a503SKent Overstreet 	int ret = 0;
18914b393eeSKent Overstreet 
19035f1a503SKent Overstreet 	if (k.k->type != KEY_TYPE_snapshot)
19135f1a503SKent Overstreet 		return 0;
19214b393eeSKent Overstreet 
19335f1a503SKent Overstreet 	s = bkey_s_c_to_snapshot(k);
19414b393eeSKent Overstreet 	id = le32_to_cpu(s.v->parent);
19514b393eeSKent Overstreet 	if (id) {
196a1783320SKent Overstreet 		ret = snapshot_lookup(trans, id, &v);
19714b393eeSKent Overstreet 		if (ret == -ENOENT)
19835f1a503SKent Overstreet 			bch_err(c, "snapshot with nonexistent parent:\n  %s",
19935f1a503SKent Overstreet 				(bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf));
20014b393eeSKent Overstreet 		if (ret)
20135f1a503SKent Overstreet 			goto err;
20214b393eeSKent Overstreet 
20314b393eeSKent Overstreet 		if (le32_to_cpu(v.children[0]) != s.k->p.offset &&
20414b393eeSKent Overstreet 		    le32_to_cpu(v.children[1]) != s.k->p.offset) {
20535f1a503SKent Overstreet 			bch_err(c, "snapshot parent %u missing pointer to child %llu",
20614b393eeSKent Overstreet 				id, s.k->p.offset);
20735f1a503SKent Overstreet 			ret = -EINVAL;
20835f1a503SKent Overstreet 			goto err;
20914b393eeSKent Overstreet 		}
21014b393eeSKent Overstreet 	}
21114b393eeSKent Overstreet 
21214b393eeSKent Overstreet 	for (i = 0; i < 2 && s.v->children[i]; i++) {
21314b393eeSKent Overstreet 		id = le32_to_cpu(s.v->children[i]);
21414b393eeSKent Overstreet 
215a1783320SKent Overstreet 		ret = snapshot_lookup(trans, id, &v);
21614b393eeSKent Overstreet 		if (ret == -ENOENT)
21735f1a503SKent Overstreet 			bch_err(c, "snapshot node %llu has nonexistent child %u",
21814b393eeSKent Overstreet 				s.k->p.offset, id);
21914b393eeSKent Overstreet 		if (ret)
22035f1a503SKent Overstreet 			goto err;
22114b393eeSKent Overstreet 
22214b393eeSKent Overstreet 		if (le32_to_cpu(v.parent) != s.k->p.offset) {
22335f1a503SKent Overstreet 			bch_err(c, "snapshot child %u has wrong parent (got %u should be %llu)",
22414b393eeSKent Overstreet 				id, le32_to_cpu(v.parent), s.k->p.offset);
22535f1a503SKent Overstreet 			ret = -EINVAL;
22635f1a503SKent Overstreet 			goto err;
22714b393eeSKent Overstreet 		}
22814b393eeSKent Overstreet 	}
22914b393eeSKent Overstreet 
23035f1a503SKent Overstreet 	should_have_subvol = BCH_SNAPSHOT_SUBVOL(s.v) &&
23135f1a503SKent Overstreet 		!BCH_SNAPSHOT_DELETED(s.v);
23235f1a503SKent Overstreet 
23335f1a503SKent Overstreet 	if (should_have_subvol) {
23435f1a503SKent Overstreet 		id = le32_to_cpu(s.v->subvol);
235a1783320SKent Overstreet 		ret = bch2_subvolume_get(trans, id, 0, false, &subvol);
23635f1a503SKent Overstreet 		if (ret == -ENOENT)
23735f1a503SKent Overstreet 			bch_err(c, "snapshot points to nonexistent subvolume:\n  %s",
23835f1a503SKent Overstreet 				(bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf));
23935f1a503SKent Overstreet 		if (ret)
24035f1a503SKent Overstreet 			goto err;
24135f1a503SKent Overstreet 
24235f1a503SKent Overstreet 		if (BCH_SNAPSHOT_SUBVOL(s.v) != (le32_to_cpu(subvol.snapshot) == s.k->p.offset)) {
24335f1a503SKent Overstreet 			bch_err(c, "snapshot node %llu has wrong BCH_SNAPSHOT_SUBVOL",
24435f1a503SKent Overstreet 				s.k->p.offset);
24535f1a503SKent Overstreet 			ret = -EINVAL;
24635f1a503SKent Overstreet 			goto err;
24735f1a503SKent Overstreet 		}
24835f1a503SKent Overstreet 	} else {
24935f1a503SKent Overstreet 		if (fsck_err_on(s.v->subvol, c, "snapshot should not point to subvol:\n  %s",
25035f1a503SKent Overstreet 				(bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf))) {
25135f1a503SKent Overstreet 			struct bkey_i_snapshot *u = bch2_trans_kmalloc(trans, sizeof(*u));
25235f1a503SKent Overstreet 
25335f1a503SKent Overstreet 			ret = PTR_ERR_OR_ZERO(u);
25435f1a503SKent Overstreet 			if (ret)
25535f1a503SKent Overstreet 				goto err;
25635f1a503SKent Overstreet 
25735f1a503SKent Overstreet 			bkey_reassemble(&u->k_i, s.s_c);
25835f1a503SKent Overstreet 			u->v.subvol = 0;
25935f1a503SKent Overstreet 			ret = bch2_trans_update(trans, iter, &u->k_i, 0);
26035f1a503SKent Overstreet 			if (ret)
26135f1a503SKent Overstreet 				goto err;
26235f1a503SKent Overstreet 		}
26335f1a503SKent Overstreet 	}
26435f1a503SKent Overstreet 
26535f1a503SKent Overstreet 	if (BCH_SNAPSHOT_DELETED(s.v))
26635f1a503SKent Overstreet 		set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags);
26735f1a503SKent Overstreet err:
26835f1a503SKent Overstreet fsck_err:
26935f1a503SKent Overstreet 	printbuf_exit(&buf);
27035f1a503SKent Overstreet 	return ret;
27114b393eeSKent Overstreet }
27214b393eeSKent Overstreet 
2734ab35c34SKent Overstreet int bch2_fs_check_snapshots(struct bch_fs *c)
27414b393eeSKent Overstreet {
27514b393eeSKent Overstreet 	struct btree_trans trans;
27614b393eeSKent Overstreet 	struct btree_iter iter;
277a1783320SKent Overstreet 	struct bkey_s_c k;
27814b393eeSKent Overstreet 	int ret;
27914b393eeSKent Overstreet 
28014b393eeSKent Overstreet 	bch2_trans_init(&trans, c, 0, 0);
28114b393eeSKent Overstreet 
282c59d66b5SKent Overstreet 	ret = for_each_btree_key_commit(&trans, iter,
283c59d66b5SKent Overstreet 			BTREE_ID_snapshots, POS_MIN,
284a1783320SKent Overstreet 			BTREE_ITER_PREFETCH, k,
285a1783320SKent Overstreet 			NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
286a1783320SKent Overstreet 		check_snapshot(&trans, &iter, k));
28714b393eeSKent Overstreet 
28835f1a503SKent Overstreet 	if (ret)
28914b393eeSKent Overstreet 		bch_err(c, "error %i checking snapshots", ret);
29014b393eeSKent Overstreet 
29114b393eeSKent Overstreet 	bch2_trans_exit(&trans);
29214b393eeSKent Overstreet 	return ret;
29314b393eeSKent Overstreet }
29414b393eeSKent Overstreet 
2954ab35c34SKent Overstreet static int check_subvol(struct btree_trans *trans,
2966738dd19SKent Overstreet 			struct btree_iter *iter,
2976738dd19SKent Overstreet 			struct bkey_s_c k)
2984ab35c34SKent Overstreet {
2994ab35c34SKent Overstreet 	struct bkey_s_c_subvolume subvol;
30035f1a503SKent Overstreet 	struct bch_snapshot snapshot;
30135f1a503SKent Overstreet 	unsigned snapid;
3024ab35c34SKent Overstreet 	int ret;
3034ab35c34SKent Overstreet 
3044ab35c34SKent Overstreet 	if (k.k->type != KEY_TYPE_subvolume)
3054ab35c34SKent Overstreet 		return 0;
3064ab35c34SKent Overstreet 
3074ab35c34SKent Overstreet 	subvol = bkey_s_c_to_subvolume(k);
30835f1a503SKent Overstreet 	snapid = le32_to_cpu(subvol.v->snapshot);
30935f1a503SKent Overstreet 	ret = snapshot_lookup(trans, snapid, &snapshot);
31035f1a503SKent Overstreet 
31135f1a503SKent Overstreet 	if (ret == -ENOENT)
31235f1a503SKent Overstreet 		bch_err(trans->c, "subvolume %llu points to nonexistent snapshot %u",
31335f1a503SKent Overstreet 			k.k->p.offset, snapid);
31435f1a503SKent Overstreet 	if (ret)
31535f1a503SKent Overstreet 		return ret;
3164ab35c34SKent Overstreet 
3174ab35c34SKent Overstreet 	if (BCH_SUBVOLUME_UNLINKED(subvol.v)) {
3184ab35c34SKent Overstreet 		ret = bch2_subvolume_delete(trans, iter->pos.offset);
319549d173cSKent Overstreet 		if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
320d4bf5eecSKent Overstreet 			bch_err(trans->c, "error deleting subvolume %llu: %s",
321d4bf5eecSKent Overstreet 				iter->pos.offset, bch2_err_str(ret));
3224ab35c34SKent Overstreet 		if (ret)
3234ab35c34SKent Overstreet 			return ret;
3244ab35c34SKent Overstreet 	}
3254ab35c34SKent Overstreet 
3264ab35c34SKent Overstreet 	return 0;
3274ab35c34SKent Overstreet }
3284ab35c34SKent Overstreet 
3294ab35c34SKent Overstreet int bch2_fs_check_subvols(struct bch_fs *c)
3304ab35c34SKent Overstreet {
3314ab35c34SKent Overstreet 	struct btree_trans trans;
3324ab35c34SKent Overstreet 	struct btree_iter iter;
3336738dd19SKent Overstreet 	struct bkey_s_c k;
3344ab35c34SKent Overstreet 	int ret;
3354ab35c34SKent Overstreet 
33635f1a503SKent Overstreet 	bch2_trans_init(&trans, c, 0, 0);
3374ab35c34SKent Overstreet 
3386738dd19SKent Overstreet 	ret = for_each_btree_key_commit(&trans, iter,
3396738dd19SKent Overstreet 			BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k,
3406738dd19SKent Overstreet 			NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
3416738dd19SKent Overstreet 		check_subvol(&trans, &iter, k));
3424ab35c34SKent Overstreet 
3434ab35c34SKent Overstreet 	bch2_trans_exit(&trans);
3444ab35c34SKent Overstreet 
3454ab35c34SKent Overstreet 	return ret;
3464ab35c34SKent Overstreet }
3474ab35c34SKent Overstreet 
34814b393eeSKent Overstreet void bch2_fs_snapshots_exit(struct bch_fs *c)
34914b393eeSKent Overstreet {
35014b393eeSKent Overstreet 	genradix_free(&c->snapshots);
35114b393eeSKent Overstreet }
35214b393eeSKent Overstreet 
35314b393eeSKent Overstreet int bch2_fs_snapshots_start(struct bch_fs *c)
35414b393eeSKent Overstreet {
35514b393eeSKent Overstreet 	struct btree_trans trans;
35614b393eeSKent Overstreet 	struct btree_iter iter;
35714b393eeSKent Overstreet 	struct bkey_s_c k;
35814b393eeSKent Overstreet 	int ret = 0;
35914b393eeSKent Overstreet 
36014b393eeSKent Overstreet 	bch2_trans_init(&trans, c, 0, 0);
36114b393eeSKent Overstreet 
362a1783320SKent Overstreet 	for_each_btree_key2(&trans, iter, BTREE_ID_snapshots,
363a1783320SKent Overstreet 			   POS_MIN, 0, k,
364a1783320SKent Overstreet 		bch2_mark_snapshot(&trans, bkey_s_c_null, k, 0) ?:
365a1783320SKent Overstreet 		bch2_snapshot_set_equiv(&trans, k));
36614b393eeSKent Overstreet 
36714b393eeSKent Overstreet 	bch2_trans_exit(&trans);
36835f1a503SKent Overstreet 
36935f1a503SKent Overstreet 	if (ret)
370d4bf5eecSKent Overstreet 		bch_err(c, "error starting snapshots: %s", bch2_err_str(ret));
37114b393eeSKent Overstreet 	return ret;
37214b393eeSKent Overstreet }
37314b393eeSKent Overstreet 
37414b393eeSKent Overstreet /*
37514b393eeSKent Overstreet  * Mark a snapshot as deleted, for future cleanup:
37614b393eeSKent Overstreet  */
37714b393eeSKent Overstreet static int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id)
37814b393eeSKent Overstreet {
37914b393eeSKent Overstreet 	struct btree_iter iter;
38014b393eeSKent Overstreet 	struct bkey_s_c k;
38114b393eeSKent Overstreet 	struct bkey_i_snapshot *s;
38214b393eeSKent Overstreet 	int ret = 0;
38314b393eeSKent Overstreet 
38414b393eeSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id),
38514b393eeSKent Overstreet 			     BTREE_ITER_INTENT);
38614b393eeSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
38714b393eeSKent Overstreet 	ret = bkey_err(k);
38814b393eeSKent Overstreet 	if (ret)
38914b393eeSKent Overstreet 		goto err;
39014b393eeSKent Overstreet 
39114b393eeSKent Overstreet 	if (k.k->type != KEY_TYPE_snapshot) {
39214b393eeSKent Overstreet 		bch2_fs_inconsistent(trans->c, "missing snapshot %u", id);
39314b393eeSKent Overstreet 		ret = -ENOENT;
39414b393eeSKent Overstreet 		goto err;
39514b393eeSKent Overstreet 	}
39614b393eeSKent Overstreet 
39714b393eeSKent Overstreet 	/* already deleted? */
39814b393eeSKent Overstreet 	if (BCH_SNAPSHOT_DELETED(bkey_s_c_to_snapshot(k).v))
39914b393eeSKent Overstreet 		goto err;
40014b393eeSKent Overstreet 
40114b393eeSKent Overstreet 	s = bch2_trans_kmalloc(trans, sizeof(*s));
40214b393eeSKent Overstreet 	ret = PTR_ERR_OR_ZERO(s);
40314b393eeSKent Overstreet 	if (ret)
40414b393eeSKent Overstreet 		goto err;
40514b393eeSKent Overstreet 
40614b393eeSKent Overstreet 	bkey_reassemble(&s->k_i, k);
40714b393eeSKent Overstreet 	SET_BCH_SNAPSHOT_DELETED(&s->v, true);
408416cc426SKent Overstreet 	SET_BCH_SNAPSHOT_SUBVOL(&s->v, false);
409416cc426SKent Overstreet 	s->v.subvol = 0;
410416cc426SKent Overstreet 
41114b393eeSKent Overstreet 	ret = bch2_trans_update(trans, &iter, &s->k_i, 0);
41214b393eeSKent Overstreet 	if (ret)
41314b393eeSKent Overstreet 		goto err;
41414b393eeSKent Overstreet err:
41514b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
41614b393eeSKent Overstreet 	return ret;
41714b393eeSKent Overstreet }
41814b393eeSKent Overstreet 
41914b393eeSKent Overstreet static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id)
42014b393eeSKent Overstreet {
42114b393eeSKent Overstreet 	struct btree_iter iter, p_iter = (struct btree_iter) { NULL };
42214b393eeSKent Overstreet 	struct bkey_s_c k;
42314b393eeSKent Overstreet 	struct bkey_s_c_snapshot s;
42414b393eeSKent Overstreet 	struct bkey_i_snapshot *parent;
42514b393eeSKent Overstreet 	u32 parent_id;
42614b393eeSKent Overstreet 	unsigned i;
42714b393eeSKent Overstreet 	int ret = 0;
42814b393eeSKent Overstreet 
42914b393eeSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id),
43014b393eeSKent Overstreet 			     BTREE_ITER_INTENT);
43114b393eeSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
43214b393eeSKent Overstreet 	ret = bkey_err(k);
43314b393eeSKent Overstreet 	if (ret)
43414b393eeSKent Overstreet 		goto err;
43514b393eeSKent Overstreet 
43614b393eeSKent Overstreet 	if (k.k->type != KEY_TYPE_snapshot) {
43714b393eeSKent Overstreet 		bch2_fs_inconsistent(trans->c, "missing snapshot %u", id);
43814b393eeSKent Overstreet 		ret = -ENOENT;
43914b393eeSKent Overstreet 		goto err;
44014b393eeSKent Overstreet 	}
44114b393eeSKent Overstreet 
44214b393eeSKent Overstreet 	s = bkey_s_c_to_snapshot(k);
44314b393eeSKent Overstreet 
44414b393eeSKent Overstreet 	BUG_ON(!BCH_SNAPSHOT_DELETED(s.v));
44514b393eeSKent Overstreet 	parent_id = le32_to_cpu(s.v->parent);
44614b393eeSKent Overstreet 
44714b393eeSKent Overstreet 	if (parent_id) {
44814b393eeSKent Overstreet 		bch2_trans_iter_init(trans, &p_iter, BTREE_ID_snapshots,
44914b393eeSKent Overstreet 				     POS(0, parent_id),
45014b393eeSKent Overstreet 				     BTREE_ITER_INTENT);
45114b393eeSKent Overstreet 		k = bch2_btree_iter_peek_slot(&p_iter);
45214b393eeSKent Overstreet 		ret = bkey_err(k);
45314b393eeSKent Overstreet 		if (ret)
45414b393eeSKent Overstreet 			goto err;
45514b393eeSKent Overstreet 
45614b393eeSKent Overstreet 		if (k.k->type != KEY_TYPE_snapshot) {
45714b393eeSKent Overstreet 			bch2_fs_inconsistent(trans->c, "missing snapshot %u", parent_id);
45814b393eeSKent Overstreet 			ret = -ENOENT;
45914b393eeSKent Overstreet 			goto err;
46014b393eeSKent Overstreet 		}
46114b393eeSKent Overstreet 
46214b393eeSKent Overstreet 		parent = bch2_trans_kmalloc(trans, sizeof(*parent));
46314b393eeSKent Overstreet 		ret = PTR_ERR_OR_ZERO(parent);
46414b393eeSKent Overstreet 		if (ret)
46514b393eeSKent Overstreet 			goto err;
46614b393eeSKent Overstreet 
46714b393eeSKent Overstreet 		bkey_reassemble(&parent->k_i, k);
46814b393eeSKent Overstreet 
46914b393eeSKent Overstreet 		for (i = 0; i < 2; i++)
47014b393eeSKent Overstreet 			if (le32_to_cpu(parent->v.children[i]) == id)
47114b393eeSKent Overstreet 				break;
47214b393eeSKent Overstreet 
47314b393eeSKent Overstreet 		if (i == 2)
47414b393eeSKent Overstreet 			bch_err(trans->c, "snapshot %u missing child pointer to %u",
47514b393eeSKent Overstreet 				parent_id, id);
47614b393eeSKent Overstreet 		else
47714b393eeSKent Overstreet 			parent->v.children[i] = 0;
47814b393eeSKent Overstreet 
47914b393eeSKent Overstreet 		if (le32_to_cpu(parent->v.children[0]) <
48014b393eeSKent Overstreet 		    le32_to_cpu(parent->v.children[1]))
48114b393eeSKent Overstreet 			swap(parent->v.children[0],
48214b393eeSKent Overstreet 			     parent->v.children[1]);
48314b393eeSKent Overstreet 
48414b393eeSKent Overstreet 		ret = bch2_trans_update(trans, &p_iter, &parent->k_i, 0);
48514b393eeSKent Overstreet 		if (ret)
48614b393eeSKent Overstreet 			goto err;
48714b393eeSKent Overstreet 	}
48814b393eeSKent Overstreet 
48914b393eeSKent Overstreet 	ret = bch2_btree_delete_at(trans, &iter, 0);
49014b393eeSKent Overstreet err:
49114b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &p_iter);
49214b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
49314b393eeSKent Overstreet 	return ret;
49414b393eeSKent Overstreet }
49514b393eeSKent Overstreet 
4967f6ff935SKent Overstreet int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent,
49714b393eeSKent Overstreet 			      u32 *new_snapids,
49814b393eeSKent Overstreet 			      u32 *snapshot_subvols,
49914b393eeSKent Overstreet 			      unsigned nr_snapids)
50014b393eeSKent Overstreet {
50114b393eeSKent Overstreet 	struct btree_iter iter;
50214b393eeSKent Overstreet 	struct bkey_i_snapshot *n;
50314b393eeSKent Overstreet 	struct bkey_s_c k;
50414b393eeSKent Overstreet 	unsigned i;
50514b393eeSKent Overstreet 	int ret = 0;
50614b393eeSKent Overstreet 
50714b393eeSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots,
50814b393eeSKent Overstreet 			     POS_MIN, BTREE_ITER_INTENT);
50914b393eeSKent Overstreet 	k = bch2_btree_iter_peek(&iter);
51014b393eeSKent Overstreet 	ret = bkey_err(k);
51114b393eeSKent Overstreet 	if (ret)
51214b393eeSKent Overstreet 		goto err;
51314b393eeSKent Overstreet 
51414b393eeSKent Overstreet 	for (i = 0; i < nr_snapids; i++) {
51514b393eeSKent Overstreet 		k = bch2_btree_iter_prev_slot(&iter);
51614b393eeSKent Overstreet 		ret = bkey_err(k);
51714b393eeSKent Overstreet 		if (ret)
51814b393eeSKent Overstreet 			goto err;
51914b393eeSKent Overstreet 
52014b393eeSKent Overstreet 		if (!k.k || !k.k->p.offset) {
521098ef98dSKent Overstreet 			ret = -BCH_ERR_ENOSPC_snapshot_create;
52214b393eeSKent Overstreet 			goto err;
52314b393eeSKent Overstreet 		}
52414b393eeSKent Overstreet 
52514b393eeSKent Overstreet 		n = bch2_trans_kmalloc(trans, sizeof(*n));
52614b393eeSKent Overstreet 		ret = PTR_ERR_OR_ZERO(n);
52714b393eeSKent Overstreet 		if (ret)
52894a3e1a6SKent Overstreet 			goto err;
52914b393eeSKent Overstreet 
53014b393eeSKent Overstreet 		bkey_snapshot_init(&n->k_i);
53114b393eeSKent Overstreet 		n->k.p		= iter.pos;
53214b393eeSKent Overstreet 		n->v.flags	= 0;
53314b393eeSKent Overstreet 		n->v.parent	= cpu_to_le32(parent);
53414b393eeSKent Overstreet 		n->v.subvol	= cpu_to_le32(snapshot_subvols[i]);
53514b393eeSKent Overstreet 		n->v.pad	= 0;
53614b393eeSKent Overstreet 		SET_BCH_SNAPSHOT_SUBVOL(&n->v, true);
53714b393eeSKent Overstreet 
53894a3e1a6SKent Overstreet 		ret   = bch2_trans_update(trans, &iter, &n->k_i, 0) ?:
53994a3e1a6SKent Overstreet 			bch2_mark_snapshot(trans, bkey_s_c_null, bkey_i_to_s_c(&n->k_i), 0);
54014b393eeSKent Overstreet 		if (ret)
54194a3e1a6SKent Overstreet 			goto err;
54214b393eeSKent Overstreet 
54314b393eeSKent Overstreet 		new_snapids[i]	= iter.pos.offset;
54414b393eeSKent Overstreet 	}
54514b393eeSKent Overstreet 
54614b393eeSKent Overstreet 	if (parent) {
54714b393eeSKent Overstreet 		bch2_btree_iter_set_pos(&iter, POS(0, parent));
54814b393eeSKent Overstreet 		k = bch2_btree_iter_peek(&iter);
54914b393eeSKent Overstreet 		ret = bkey_err(k);
55014b393eeSKent Overstreet 		if (ret)
55114b393eeSKent Overstreet 			goto err;
55214b393eeSKent Overstreet 
55314b393eeSKent Overstreet 		if (k.k->type != KEY_TYPE_snapshot) {
55414b393eeSKent Overstreet 			bch_err(trans->c, "snapshot %u not found", parent);
55514b393eeSKent Overstreet 			ret = -ENOENT;
55614b393eeSKent Overstreet 			goto err;
55714b393eeSKent Overstreet 		}
55814b393eeSKent Overstreet 
55914b393eeSKent Overstreet 		n = bch2_trans_kmalloc(trans, sizeof(*n));
56014b393eeSKent Overstreet 		ret = PTR_ERR_OR_ZERO(n);
56114b393eeSKent Overstreet 		if (ret)
562c4ecf802SKent Overstreet 			goto err;
56314b393eeSKent Overstreet 
56414b393eeSKent Overstreet 		bkey_reassemble(&n->k_i, k);
56514b393eeSKent Overstreet 
56614b393eeSKent Overstreet 		if (n->v.children[0] || n->v.children[1]) {
56714b393eeSKent Overstreet 			bch_err(trans->c, "Trying to add child snapshot nodes to parent that already has children");
56814b393eeSKent Overstreet 			ret = -EINVAL;
56914b393eeSKent Overstreet 			goto err;
57014b393eeSKent Overstreet 		}
57114b393eeSKent Overstreet 
57214b393eeSKent Overstreet 		n->v.children[0] = cpu_to_le32(new_snapids[0]);
57314b393eeSKent Overstreet 		n->v.children[1] = cpu_to_le32(new_snapids[1]);
57435f1a503SKent Overstreet 		n->v.subvol = 0;
57514b393eeSKent Overstreet 		SET_BCH_SNAPSHOT_SUBVOL(&n->v, false);
57694a3e1a6SKent Overstreet 		ret = bch2_trans_update(trans, &iter, &n->k_i, 0);
57794a3e1a6SKent Overstreet 		if (ret)
57894a3e1a6SKent Overstreet 			goto err;
57914b393eeSKent Overstreet 	}
58014b393eeSKent Overstreet err:
58114b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
58214b393eeSKent Overstreet 	return ret;
58314b393eeSKent Overstreet }
58414b393eeSKent Overstreet 
5856738dd19SKent Overstreet static int snapshot_delete_key(struct btree_trans *trans,
5866738dd19SKent Overstreet 			       struct btree_iter *iter,
5876738dd19SKent Overstreet 			       struct bkey_s_c k,
58891d961baSKent Overstreet 			       snapshot_id_list *deleted,
5896738dd19SKent Overstreet 			       snapshot_id_list *equiv_seen,
5906738dd19SKent Overstreet 			       struct bpos *last_pos)
59114b393eeSKent Overstreet {
59214b393eeSKent Overstreet 	struct bch_fs *c = trans->c;
59314b393eeSKent Overstreet 	u32 equiv = snapshot_t(c, k.k->p.snapshot)->equiv;
59414b393eeSKent Overstreet 
5956738dd19SKent Overstreet 	if (bkey_cmp(k.k->p, *last_pos))
5966738dd19SKent Overstreet 		equiv_seen->nr = 0;
5976738dd19SKent Overstreet 	*last_pos = k.k->p;
59814b393eeSKent Overstreet 
59914b393eeSKent Overstreet 	if (snapshot_list_has_id(deleted, k.k->p.snapshot) ||
6006738dd19SKent Overstreet 	    snapshot_list_has_id(equiv_seen, equiv)) {
6016738dd19SKent Overstreet 		return bch2_btree_delete_at(trans, iter,
6026738dd19SKent Overstreet 					    BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
60314b393eeSKent Overstreet 	} else {
6046738dd19SKent Overstreet 		return snapshot_list_add(c, equiv_seen, equiv);
60514b393eeSKent Overstreet 	}
60614b393eeSKent Overstreet }
60714b393eeSKent Overstreet 
608a1783320SKent Overstreet static int bch2_delete_redundant_snapshot(struct btree_trans *trans, struct btree_iter *iter,
609a1783320SKent Overstreet 					  struct bkey_s_c k)
610a1783320SKent Overstreet {
611a1783320SKent Overstreet 	struct bkey_s_c_snapshot snap;
612a1783320SKent Overstreet 	u32 children[2];
613a1783320SKent Overstreet 	int ret;
614a1783320SKent Overstreet 
615a1783320SKent Overstreet 	if (k.k->type != KEY_TYPE_snapshot)
616a1783320SKent Overstreet 		return 0;
617a1783320SKent Overstreet 
618a1783320SKent Overstreet 	snap = bkey_s_c_to_snapshot(k);
619a1783320SKent Overstreet 	if (BCH_SNAPSHOT_DELETED(snap.v) ||
620a1783320SKent Overstreet 	    BCH_SNAPSHOT_SUBVOL(snap.v))
621a1783320SKent Overstreet 		return 0;
622a1783320SKent Overstreet 
623a1783320SKent Overstreet 	children[0] = le32_to_cpu(snap.v->children[0]);
624a1783320SKent Overstreet 	children[1] = le32_to_cpu(snap.v->children[1]);
625a1783320SKent Overstreet 
626a1783320SKent Overstreet 	ret   = snapshot_live(trans, children[0]) ?:
627a1783320SKent Overstreet 		snapshot_live(trans, children[1]);
628a1783320SKent Overstreet 	if (ret < 0)
629a1783320SKent Overstreet 		return ret;
630a1783320SKent Overstreet 
631a1783320SKent Overstreet 	if (!ret)
632a1783320SKent Overstreet 		return bch2_snapshot_node_set_deleted(trans, k.k->p.offset);
633a1783320SKent Overstreet 	return 0;
634a1783320SKent Overstreet }
635a1783320SKent Overstreet 
6364ab35c34SKent Overstreet int bch2_delete_dead_snapshots(struct bch_fs *c)
63714b393eeSKent Overstreet {
63814b393eeSKent Overstreet 	struct btree_trans trans;
63914b393eeSKent Overstreet 	struct btree_iter iter;
64014b393eeSKent Overstreet 	struct bkey_s_c k;
64114b393eeSKent Overstreet 	struct bkey_s_c_snapshot snap;
64291d961baSKent Overstreet 	snapshot_id_list deleted = { 0 };
643a1783320SKent Overstreet 	u32 i, id;
64414b393eeSKent Overstreet 	int ret = 0;
64514b393eeSKent Overstreet 
6464ab35c34SKent Overstreet 	if (!test_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags))
6474ab35c34SKent Overstreet 		return 0;
6484ab35c34SKent Overstreet 
6494ab35c34SKent Overstreet 	if (!test_bit(BCH_FS_STARTED, &c->flags)) {
6504ab35c34SKent Overstreet 		ret = bch2_fs_read_write_early(c);
6514ab35c34SKent Overstreet 		if (ret) {
652d4bf5eecSKent Overstreet 			bch_err(c, "error deleleting dead snapshots: error going rw: %s", bch2_err_str(ret));
6534ab35c34SKent Overstreet 			return ret;
6544ab35c34SKent Overstreet 		}
6554ab35c34SKent Overstreet 	}
6564ab35c34SKent Overstreet 
65714b393eeSKent Overstreet 	bch2_trans_init(&trans, c, 0, 0);
65814b393eeSKent Overstreet 
65914b393eeSKent Overstreet 	/*
66014b393eeSKent Overstreet 	 * For every snapshot node: If we have no live children and it's not
66114b393eeSKent Overstreet 	 * pointed to by a subvolume, delete it:
66214b393eeSKent Overstreet 	 */
663a1783320SKent Overstreet 	ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_snapshots,
664a1783320SKent Overstreet 			POS_MIN, 0, k,
665a1783320SKent Overstreet 			NULL, NULL, 0,
666a1783320SKent Overstreet 		bch2_delete_redundant_snapshot(&trans, &iter, k));
66714b393eeSKent Overstreet 	if (ret) {
668d4bf5eecSKent Overstreet 		bch_err(c, "error deleting redundant snapshots: %s", bch2_err_str(ret));
66914b393eeSKent Overstreet 		goto err;
67014b393eeSKent Overstreet 	}
67114b393eeSKent Overstreet 
672a1783320SKent Overstreet 	for_each_btree_key2(&trans, iter, BTREE_ID_snapshots,
673a1783320SKent Overstreet 			   POS_MIN, 0, k,
674a1783320SKent Overstreet 		bch2_snapshot_set_equiv(&trans, k));
675a1783320SKent Overstreet 	if (ret) {
676d4bf5eecSKent Overstreet 		bch_err(c, "error in bch2_snapshots_set_equiv: %s", bch2_err_str(ret));
67714b393eeSKent Overstreet 		goto err;
678a1783320SKent Overstreet 	}
67914b393eeSKent Overstreet 
68014b393eeSKent Overstreet 	for_each_btree_key(&trans, iter, BTREE_ID_snapshots,
68114b393eeSKent Overstreet 			   POS_MIN, 0, k, ret) {
68214b393eeSKent Overstreet 		if (k.k->type != KEY_TYPE_snapshot)
68314b393eeSKent Overstreet 			continue;
68414b393eeSKent Overstreet 
68514b393eeSKent Overstreet 		snap = bkey_s_c_to_snapshot(k);
68614b393eeSKent Overstreet 		if (BCH_SNAPSHOT_DELETED(snap.v)) {
687597dee1cSKent Overstreet 			ret = snapshot_list_add(c, &deleted, k.k->p.offset);
68814b393eeSKent Overstreet 			if (ret)
68914b393eeSKent Overstreet 				break;
69014b393eeSKent Overstreet 		}
69114b393eeSKent Overstreet 	}
69214b393eeSKent Overstreet 	bch2_trans_iter_exit(&trans, &iter);
69314b393eeSKent Overstreet 
69414b393eeSKent Overstreet 	if (ret) {
695d4bf5eecSKent Overstreet 		bch_err(c, "error walking snapshots: %s", bch2_err_str(ret));
69614b393eeSKent Overstreet 		goto err;
69714b393eeSKent Overstreet 	}
69814b393eeSKent Overstreet 
69914b393eeSKent Overstreet 	for (id = 0; id < BTREE_ID_NR; id++) {
7006738dd19SKent Overstreet 		struct bpos last_pos = POS_MIN;
7016738dd19SKent Overstreet 		snapshot_id_list equiv_seen = { 0 };
7026738dd19SKent Overstreet 
70314b393eeSKent Overstreet 		if (!btree_type_has_snapshots(id))
70414b393eeSKent Overstreet 			continue;
70514b393eeSKent Overstreet 
7066738dd19SKent Overstreet 		ret = for_each_btree_key_commit(&trans, iter,
7076738dd19SKent Overstreet 				id, POS_MIN,
7086738dd19SKent Overstreet 				BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
7096738dd19SKent Overstreet 				NULL, NULL, BTREE_INSERT_NOFAIL,
7106738dd19SKent Overstreet 			snapshot_delete_key(&trans, &iter, k, &deleted, &equiv_seen, &last_pos));
7116738dd19SKent Overstreet 
7126738dd19SKent Overstreet 		darray_exit(&equiv_seen);
7136738dd19SKent Overstreet 
71414b393eeSKent Overstreet 		if (ret) {
715d4bf5eecSKent Overstreet 			bch_err(c, "error deleting snapshot keys: %s", bch2_err_str(ret));
71614b393eeSKent Overstreet 			goto err;
71714b393eeSKent Overstreet 		}
71814b393eeSKent Overstreet 	}
71914b393eeSKent Overstreet 
72014b393eeSKent Overstreet 	for (i = 0; i < deleted.nr; i++) {
721e68914caSKent Overstreet 		ret = commit_do(&trans, NULL, NULL, 0,
72291d961baSKent Overstreet 			bch2_snapshot_node_delete(&trans, deleted.data[i]));
72314b393eeSKent Overstreet 		if (ret) {
724d4bf5eecSKent Overstreet 			bch_err(c, "error deleting snapshot %u: %s",
725d4bf5eecSKent Overstreet 				deleted.data[i], bch2_err_str(ret));
72614b393eeSKent Overstreet 			goto err;
72714b393eeSKent Overstreet 		}
72814b393eeSKent Overstreet 	}
7294ab35c34SKent Overstreet 
7304ab35c34SKent Overstreet 	clear_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags);
73114b393eeSKent Overstreet err:
73291d961baSKent Overstreet 	darray_exit(&deleted);
73314b393eeSKent Overstreet 	bch2_trans_exit(&trans);
7344ab35c34SKent Overstreet 	return ret;
7354ab35c34SKent Overstreet }
7364ab35c34SKent Overstreet 
7374ab35c34SKent Overstreet static void bch2_delete_dead_snapshots_work(struct work_struct *work)
7384ab35c34SKent Overstreet {
7394ab35c34SKent Overstreet 	struct bch_fs *c = container_of(work, struct bch_fs, snapshot_delete_work);
7404ab35c34SKent Overstreet 
7414ab35c34SKent Overstreet 	bch2_delete_dead_snapshots(c);
74214b393eeSKent Overstreet 	percpu_ref_put(&c->writes);
74314b393eeSKent Overstreet }
74414b393eeSKent Overstreet 
7454ab35c34SKent Overstreet void bch2_delete_dead_snapshots_async(struct bch_fs *c)
74614b393eeSKent Overstreet {
7474ab35c34SKent Overstreet 	if (!percpu_ref_tryget_live(&c->writes))
74814b393eeSKent Overstreet 		return;
74914b393eeSKent Overstreet 
75014b393eeSKent Overstreet 	if (!queue_work(system_long_wq, &c->snapshot_delete_work))
75114b393eeSKent Overstreet 		percpu_ref_put(&c->writes);
75214b393eeSKent Overstreet }
75314b393eeSKent Overstreet 
75414b393eeSKent Overstreet static int bch2_delete_dead_snapshots_hook(struct btree_trans *trans,
75514b393eeSKent Overstreet 					   struct btree_trans_commit_hook *h)
75614b393eeSKent Overstreet {
7574ab35c34SKent Overstreet 	struct bch_fs *c = trans->c;
7584ab35c34SKent Overstreet 
7594ab35c34SKent Overstreet 	set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags);
7604ab35c34SKent Overstreet 
7614ab35c34SKent Overstreet 	if (!test_bit(BCH_FS_FSCK_DONE, &c->flags))
7624ab35c34SKent Overstreet 		return 0;
7634ab35c34SKent Overstreet 
7644ab35c34SKent Overstreet 	bch2_delete_dead_snapshots_async(c);
76514b393eeSKent Overstreet 	return 0;
76614b393eeSKent Overstreet }
76714b393eeSKent Overstreet 
76814b393eeSKent Overstreet /* Subvolumes: */
76914b393eeSKent Overstreet 
770f0ac7df2SKent Overstreet int bch2_subvolume_invalid(const struct bch_fs *c, struct bkey_s_c k,
771275c8426SKent Overstreet 			   int rw, struct printbuf *err)
77214b393eeSKent Overstreet {
773f0ac7df2SKent Overstreet 	if (bkey_cmp(k.k->p, SUBVOL_POS_MIN) < 0 ||
774f0ac7df2SKent Overstreet 	    bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) {
775401ec4dbSKent Overstreet 		prt_printf(err, "invalid pos");
776f0ac7df2SKent Overstreet 		return -EINVAL;
777f0ac7df2SKent Overstreet 	}
77814b393eeSKent Overstreet 
779f0ac7df2SKent Overstreet 	if (bkey_val_bytes(k.k) != sizeof(struct bch_subvolume)) {
780401ec4dbSKent Overstreet 		prt_printf(err, "incorrect value size (%zu != %zu)",
781f0ac7df2SKent Overstreet 		       bkey_val_bytes(k.k), sizeof(struct bch_subvolume));
782f0ac7df2SKent Overstreet 		return -EINVAL;
783f0ac7df2SKent Overstreet 	}
78414b393eeSKent Overstreet 
785f0ac7df2SKent Overstreet 	return 0;
78614b393eeSKent Overstreet }
78714b393eeSKent Overstreet 
78814b393eeSKent Overstreet void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c,
78914b393eeSKent Overstreet 			    struct bkey_s_c k)
79014b393eeSKent Overstreet {
79114b393eeSKent Overstreet 	struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k);
79214b393eeSKent Overstreet 
793401ec4dbSKent Overstreet 	prt_printf(out, "root %llu snapshot id %u",
79414b393eeSKent Overstreet 	       le64_to_cpu(s.v->inode),
79514b393eeSKent Overstreet 	       le32_to_cpu(s.v->snapshot));
79614b393eeSKent Overstreet }
79714b393eeSKent Overstreet 
79897996ddfSKent Overstreet int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol,
79997996ddfSKent Overstreet 		       bool inconsistent_if_not_found,
80097996ddfSKent Overstreet 		       int iter_flags,
80197996ddfSKent Overstreet 		       struct bch_subvolume *s)
80214b393eeSKent Overstreet {
80314b393eeSKent Overstreet 	struct btree_iter iter;
80414b393eeSKent Overstreet 	struct bkey_s_c k;
80514b393eeSKent Overstreet 	int ret;
80614b393eeSKent Overstreet 
80797996ddfSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, POS(0, subvol),
80897996ddfSKent Overstreet 			     iter_flags);
80914b393eeSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
81097996ddfSKent Overstreet 	ret = bkey_err(k) ?: k.k->type == KEY_TYPE_subvolume ? 0 : -ENOENT;
81114b393eeSKent Overstreet 
81297996ddfSKent Overstreet 	if (ret == -ENOENT && inconsistent_if_not_found)
81314b393eeSKent Overstreet 		bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvol);
81497996ddfSKent Overstreet 	if (!ret)
81597996ddfSKent Overstreet 		*s = *bkey_s_c_to_subvolume(k).v;
81697996ddfSKent Overstreet 
81797996ddfSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
81897996ddfSKent Overstreet 	return ret;
81914b393eeSKent Overstreet }
82014b393eeSKent Overstreet 
8219ca4853bSKent Overstreet int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot,
8229ca4853bSKent Overstreet 			     struct bch_subvolume *subvol)
8239ca4853bSKent Overstreet {
8249ca4853bSKent Overstreet 	struct bch_snapshot snap;
8259ca4853bSKent Overstreet 
8269ca4853bSKent Overstreet 	return  snapshot_lookup(trans, snapshot, &snap) ?:
8279ca4853bSKent Overstreet 		bch2_subvolume_get(trans, le32_to_cpu(snap.subvol), true, 0, subvol);
8289ca4853bSKent Overstreet }
8299ca4853bSKent Overstreet 
83097996ddfSKent Overstreet int bch2_subvolume_get_snapshot(struct btree_trans *trans, u32 subvol,
83197996ddfSKent Overstreet 				u32 *snapid)
83297996ddfSKent Overstreet {
83397996ddfSKent Overstreet 	struct bch_subvolume s;
83497996ddfSKent Overstreet 	int ret;
83597996ddfSKent Overstreet 
83697996ddfSKent Overstreet 	ret = bch2_subvolume_get(trans, subvol, true,
83797996ddfSKent Overstreet 				 BTREE_ITER_CACHED|
83897996ddfSKent Overstreet 				 BTREE_ITER_WITH_UPDATES,
83997996ddfSKent Overstreet 				 &s);
84097996ddfSKent Overstreet 
84197996ddfSKent Overstreet 	*snapid = le32_to_cpu(s.snapshot);
84214b393eeSKent Overstreet 	return ret;
84314b393eeSKent Overstreet }
84414b393eeSKent Overstreet 
8452027875bSKent Overstreet /*
8462027875bSKent Overstreet  * Delete subvolume, mark snapshot ID as deleted, queue up snapshot
8472027875bSKent Overstreet  * deletion/cleanup:
8482027875bSKent Overstreet  */
8492027875bSKent Overstreet int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
85014b393eeSKent Overstreet {
85114b393eeSKent Overstreet 	struct btree_iter iter;
85214b393eeSKent Overstreet 	struct bkey_s_c k;
85314b393eeSKent Overstreet 	struct bkey_s_c_subvolume subvol;
85414b393eeSKent Overstreet 	struct btree_trans_commit_hook *h;
85514b393eeSKent Overstreet 	u32 snapid;
85614b393eeSKent Overstreet 	int ret = 0;
85714b393eeSKent Overstreet 
85814b393eeSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes,
85914b393eeSKent Overstreet 			     POS(0, subvolid),
86014b393eeSKent Overstreet 			     BTREE_ITER_CACHED|
86114b393eeSKent Overstreet 			     BTREE_ITER_INTENT);
86214b393eeSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
86314b393eeSKent Overstreet 	ret = bkey_err(k);
86414b393eeSKent Overstreet 	if (ret)
86514b393eeSKent Overstreet 		goto err;
86614b393eeSKent Overstreet 
86714b393eeSKent Overstreet 	if (k.k->type != KEY_TYPE_subvolume) {
86814b393eeSKent Overstreet 		bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid);
86914b393eeSKent Overstreet 		ret = -EIO;
87014b393eeSKent Overstreet 		goto err;
87114b393eeSKent Overstreet 	}
87214b393eeSKent Overstreet 
87314b393eeSKent Overstreet 	subvol = bkey_s_c_to_subvolume(k);
87414b393eeSKent Overstreet 	snapid = le32_to_cpu(subvol.v->snapshot);
87514b393eeSKent Overstreet 
876416cc426SKent Overstreet 	ret = bch2_btree_delete_at(trans, &iter, 0);
87714b393eeSKent Overstreet 	if (ret)
87814b393eeSKent Overstreet 		goto err;
87914b393eeSKent Overstreet 
88014b393eeSKent Overstreet 	ret = bch2_snapshot_node_set_deleted(trans, snapid);
88131301dd4SKent Overstreet 	if (ret)
88231301dd4SKent Overstreet 		goto err;
88314b393eeSKent Overstreet 
88414b393eeSKent Overstreet 	h = bch2_trans_kmalloc(trans, sizeof(*h));
88514b393eeSKent Overstreet 	ret = PTR_ERR_OR_ZERO(h);
88614b393eeSKent Overstreet 	if (ret)
88714b393eeSKent Overstreet 		goto err;
88814b393eeSKent Overstreet 
88914b393eeSKent Overstreet 	h->fn = bch2_delete_dead_snapshots_hook;
89014b393eeSKent Overstreet 	bch2_trans_commit_hook(trans, h);
89114b393eeSKent Overstreet err:
89214b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
89314b393eeSKent Overstreet 	return ret;
89414b393eeSKent Overstreet }
89514b393eeSKent Overstreet 
8962027875bSKent Overstreet void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
8972027875bSKent Overstreet {
8982027875bSKent Overstreet 	struct bch_fs *c = container_of(work, struct bch_fs,
8992027875bSKent Overstreet 				snapshot_wait_for_pagecache_and_delete_work);
90091d961baSKent Overstreet 	snapshot_id_list s;
9012027875bSKent Overstreet 	u32 *id;
9022027875bSKent Overstreet 	int ret = 0;
9032027875bSKent Overstreet 
9042027875bSKent Overstreet 	while (!ret) {
9052027875bSKent Overstreet 		mutex_lock(&c->snapshots_unlinked_lock);
9062027875bSKent Overstreet 		s = c->snapshots_unlinked;
90791d961baSKent Overstreet 		darray_init(&c->snapshots_unlinked);
9082027875bSKent Overstreet 		mutex_unlock(&c->snapshots_unlinked_lock);
9092027875bSKent Overstreet 
9102027875bSKent Overstreet 		if (!s.nr)
9112027875bSKent Overstreet 			break;
9122027875bSKent Overstreet 
9132027875bSKent Overstreet 		bch2_evict_subvolume_inodes(c, &s);
9142027875bSKent Overstreet 
91591d961baSKent Overstreet 		for (id = s.data; id < s.data + s.nr; id++) {
9162027875bSKent Overstreet 			ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL,
9172027875bSKent Overstreet 				      bch2_subvolume_delete(&trans, *id));
9182027875bSKent Overstreet 			if (ret) {
919d4bf5eecSKent Overstreet 				bch_err(c, "error deleting subvolume %u: %s", *id, bch2_err_str(ret));
9202027875bSKent Overstreet 				break;
9212027875bSKent Overstreet 			}
9222027875bSKent Overstreet 		}
9232027875bSKent Overstreet 
92491d961baSKent Overstreet 		darray_exit(&s);
9252027875bSKent Overstreet 	}
9262027875bSKent Overstreet 
9272027875bSKent Overstreet 	percpu_ref_put(&c->writes);
9282027875bSKent Overstreet }
9292027875bSKent Overstreet 
9302027875bSKent Overstreet struct subvolume_unlink_hook {
9312027875bSKent Overstreet 	struct btree_trans_commit_hook	h;
9322027875bSKent Overstreet 	u32				subvol;
9332027875bSKent Overstreet };
9342027875bSKent Overstreet 
9352027875bSKent Overstreet int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans *trans,
9362027875bSKent Overstreet 						      struct btree_trans_commit_hook *_h)
9372027875bSKent Overstreet {
9382027875bSKent Overstreet 	struct subvolume_unlink_hook *h = container_of(_h, struct subvolume_unlink_hook, h);
9392027875bSKent Overstreet 	struct bch_fs *c = trans->c;
9402027875bSKent Overstreet 	int ret = 0;
9412027875bSKent Overstreet 
9422027875bSKent Overstreet 	mutex_lock(&c->snapshots_unlinked_lock);
9432027875bSKent Overstreet 	if (!snapshot_list_has_id(&c->snapshots_unlinked, h->subvol))
944597dee1cSKent Overstreet 		ret = snapshot_list_add(c, &c->snapshots_unlinked, h->subvol);
9452027875bSKent Overstreet 	mutex_unlock(&c->snapshots_unlinked_lock);
9462027875bSKent Overstreet 
9472027875bSKent Overstreet 	if (ret)
9482027875bSKent Overstreet 		return ret;
9492027875bSKent Overstreet 
950a3d7afa5SKent Overstreet 	if (unlikely(!percpu_ref_tryget_live(&c->writes)))
9512027875bSKent Overstreet 		return -EROFS;
9522027875bSKent Overstreet 
9532027875bSKent Overstreet 	if (!queue_work(system_long_wq, &c->snapshot_wait_for_pagecache_and_delete_work))
9542027875bSKent Overstreet 		percpu_ref_put(&c->writes);
9552027875bSKent Overstreet 	return 0;
9562027875bSKent Overstreet }
9572027875bSKent Overstreet 
9582027875bSKent Overstreet int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid)
9592027875bSKent Overstreet {
9602027875bSKent Overstreet 	struct btree_iter iter;
9612027875bSKent Overstreet 	struct bkey_s_c k;
9622027875bSKent Overstreet 	struct bkey_i_subvolume *n;
9632027875bSKent Overstreet 	struct subvolume_unlink_hook *h;
9642027875bSKent Overstreet 	int ret = 0;
9652027875bSKent Overstreet 
9662027875bSKent Overstreet 	bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes,
9672027875bSKent Overstreet 			     POS(0, subvolid),
9682027875bSKent Overstreet 			     BTREE_ITER_CACHED|
9692027875bSKent Overstreet 			     BTREE_ITER_INTENT);
9702027875bSKent Overstreet 	k = bch2_btree_iter_peek_slot(&iter);
9712027875bSKent Overstreet 	ret = bkey_err(k);
9722027875bSKent Overstreet 	if (ret)
9732027875bSKent Overstreet 		goto err;
9742027875bSKent Overstreet 
9752027875bSKent Overstreet 	if (k.k->type != KEY_TYPE_subvolume) {
9762027875bSKent Overstreet 		bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid);
9772027875bSKent Overstreet 		ret = -EIO;
9782027875bSKent Overstreet 		goto err;
9792027875bSKent Overstreet 	}
9802027875bSKent Overstreet 
9812027875bSKent Overstreet 	n = bch2_trans_kmalloc(trans, sizeof(*n));
9822027875bSKent Overstreet 	ret = PTR_ERR_OR_ZERO(n);
9832027875bSKent Overstreet 	if (ret)
9842027875bSKent Overstreet 		goto err;
9852027875bSKent Overstreet 
9862027875bSKent Overstreet 	bkey_reassemble(&n->k_i, k);
9872027875bSKent Overstreet 	SET_BCH_SUBVOLUME_UNLINKED(&n->v, true);
9882027875bSKent Overstreet 
9892027875bSKent Overstreet 	ret = bch2_trans_update(trans, &iter, &n->k_i, 0);
9902027875bSKent Overstreet 	if (ret)
9912027875bSKent Overstreet 		goto err;
9922027875bSKent Overstreet 
9932027875bSKent Overstreet 	h = bch2_trans_kmalloc(trans, sizeof(*h));
9942027875bSKent Overstreet 	ret = PTR_ERR_OR_ZERO(h);
9952027875bSKent Overstreet 	if (ret)
9962027875bSKent Overstreet 		goto err;
9972027875bSKent Overstreet 
9982027875bSKent Overstreet 	h->h.fn		= bch2_subvolume_wait_for_pagecache_and_delete_hook;
9992027875bSKent Overstreet 	h->subvol	= subvolid;
10002027875bSKent Overstreet 	bch2_trans_commit_hook(trans, &h->h);
10012027875bSKent Overstreet err:
10022027875bSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
10032027875bSKent Overstreet 	return ret;
10042027875bSKent Overstreet }
10052027875bSKent Overstreet 
100614b393eeSKent Overstreet int bch2_subvolume_create(struct btree_trans *trans, u64 inode,
100714b393eeSKent Overstreet 			  u32 src_subvolid,
100814b393eeSKent Overstreet 			  u32 *new_subvolid,
100914b393eeSKent Overstreet 			  u32 *new_snapshotid,
101014b393eeSKent Overstreet 			  bool ro)
101114b393eeSKent Overstreet {
1012ca130b9cSKent Overstreet 	struct bch_fs *c = trans->c;
101314b393eeSKent Overstreet 	struct btree_iter dst_iter, src_iter = (struct btree_iter) { NULL };
101414b393eeSKent Overstreet 	struct bkey_i_subvolume *new_subvol = NULL;
101514b393eeSKent Overstreet 	struct bkey_i_subvolume *src_subvol = NULL;
101614b393eeSKent Overstreet 	struct bkey_s_c k;
101714b393eeSKent Overstreet 	u32 parent = 0, new_nodes[2], snapshot_subvols[2];
101814b393eeSKent Overstreet 	int ret = 0;
101914b393eeSKent Overstreet 
102014b393eeSKent Overstreet 	for_each_btree_key(trans, dst_iter, BTREE_ID_subvolumes, SUBVOL_POS_MIN,
102114b393eeSKent Overstreet 			   BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) {
102214b393eeSKent Overstreet 		if (bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0)
102314b393eeSKent Overstreet 			break;
1024ca130b9cSKent Overstreet 
1025ca130b9cSKent Overstreet 		/*
1026ca130b9cSKent Overstreet 		 * bch2_subvolume_delete() doesn't flush the btree key cache -
1027ca130b9cSKent Overstreet 		 * ideally it would but that's tricky
1028ca130b9cSKent Overstreet 		 */
1029ca130b9cSKent Overstreet 		if (bkey_deleted(k.k) &&
1030ca130b9cSKent Overstreet 		    !bch2_btree_key_cache_find(c, BTREE_ID_subvolumes, dst_iter.pos))
103114b393eeSKent Overstreet 			goto found_slot;
103214b393eeSKent Overstreet 	}
103314b393eeSKent Overstreet 
103414b393eeSKent Overstreet 	if (!ret)
1035098ef98dSKent Overstreet 		ret = -BCH_ERR_ENOSPC_subvolume_create;
103614b393eeSKent Overstreet 	goto err;
103714b393eeSKent Overstreet found_slot:
103814b393eeSKent Overstreet 	snapshot_subvols[0] = dst_iter.pos.offset;
103914b393eeSKent Overstreet 	snapshot_subvols[1] = src_subvolid;
104014b393eeSKent Overstreet 
104114b393eeSKent Overstreet 	if (src_subvolid) {
104214b393eeSKent Overstreet 		/* Creating a snapshot: */
104314b393eeSKent Overstreet 		src_subvol = bch2_trans_kmalloc(trans, sizeof(*src_subvol));
104414b393eeSKent Overstreet 		ret = PTR_ERR_OR_ZERO(src_subvol);
104514b393eeSKent Overstreet 		if (ret)
104614b393eeSKent Overstreet 			goto err;
104714b393eeSKent Overstreet 
104814b393eeSKent Overstreet 		bch2_trans_iter_init(trans, &src_iter, BTREE_ID_subvolumes,
104914b393eeSKent Overstreet 				     POS(0, src_subvolid),
105014b393eeSKent Overstreet 				     BTREE_ITER_CACHED|
105114b393eeSKent Overstreet 				     BTREE_ITER_INTENT);
105214b393eeSKent Overstreet 		k = bch2_btree_iter_peek_slot(&src_iter);
105314b393eeSKent Overstreet 		ret = bkey_err(k);
105414b393eeSKent Overstreet 		if (ret)
105514b393eeSKent Overstreet 			goto err;
105614b393eeSKent Overstreet 
105714b393eeSKent Overstreet 		if (k.k->type != KEY_TYPE_subvolume) {
1058ca130b9cSKent Overstreet 			bch_err(c, "subvolume %u not found", src_subvolid);
105914b393eeSKent Overstreet 			ret = -ENOENT;
106014b393eeSKent Overstreet 			goto err;
106114b393eeSKent Overstreet 		}
106214b393eeSKent Overstreet 
106314b393eeSKent Overstreet 		bkey_reassemble(&src_subvol->k_i, k);
106414b393eeSKent Overstreet 		parent = le32_to_cpu(src_subvol->v.snapshot);
106514b393eeSKent Overstreet 	}
106614b393eeSKent Overstreet 
106714b393eeSKent Overstreet 	ret = bch2_snapshot_node_create(trans, parent, new_nodes,
106814b393eeSKent Overstreet 					snapshot_subvols,
106914b393eeSKent Overstreet 					src_subvolid ? 2 : 1);
107014b393eeSKent Overstreet 	if (ret)
107114b393eeSKent Overstreet 		goto err;
107214b393eeSKent Overstreet 
107314b393eeSKent Overstreet 	if (src_subvolid) {
107414b393eeSKent Overstreet 		src_subvol->v.snapshot = cpu_to_le32(new_nodes[1]);
107594a3e1a6SKent Overstreet 		ret = bch2_trans_update(trans, &src_iter, &src_subvol->k_i, 0);
107694a3e1a6SKent Overstreet 		if (ret)
107794a3e1a6SKent Overstreet 			goto err;
107814b393eeSKent Overstreet 	}
107914b393eeSKent Overstreet 
108014b393eeSKent Overstreet 	new_subvol = bch2_trans_kmalloc(trans, sizeof(*new_subvol));
108114b393eeSKent Overstreet 	ret = PTR_ERR_OR_ZERO(new_subvol);
108214b393eeSKent Overstreet 	if (ret)
108314b393eeSKent Overstreet 		goto err;
108414b393eeSKent Overstreet 
108514b393eeSKent Overstreet 	bkey_subvolume_init(&new_subvol->k_i);
108614b393eeSKent Overstreet 	new_subvol->v.flags	= 0;
108714b393eeSKent Overstreet 	new_subvol->v.snapshot	= cpu_to_le32(new_nodes[0]);
108814b393eeSKent Overstreet 	new_subvol->v.inode	= cpu_to_le64(inode);
108914b393eeSKent Overstreet 	SET_BCH_SUBVOLUME_RO(&new_subvol->v, ro);
109014b393eeSKent Overstreet 	SET_BCH_SUBVOLUME_SNAP(&new_subvol->v, src_subvolid != 0);
109114b393eeSKent Overstreet 	new_subvol->k.p		= dst_iter.pos;
109294a3e1a6SKent Overstreet 	ret = bch2_trans_update(trans, &dst_iter, &new_subvol->k_i, 0);
109394a3e1a6SKent Overstreet 	if (ret)
109494a3e1a6SKent Overstreet 		goto err;
109514b393eeSKent Overstreet 
109614b393eeSKent Overstreet 	*new_subvolid	= new_subvol->k.p.offset;
109714b393eeSKent Overstreet 	*new_snapshotid	= new_nodes[0];
109814b393eeSKent Overstreet err:
109914b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &src_iter);
110014b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &dst_iter);
110114b393eeSKent Overstreet 	return ret;
110214b393eeSKent Overstreet }
110314b393eeSKent Overstreet 
110414b393eeSKent Overstreet int bch2_fs_subvolumes_init(struct bch_fs *c)
110514b393eeSKent Overstreet {
110614b393eeSKent Overstreet 	INIT_WORK(&c->snapshot_delete_work, bch2_delete_dead_snapshots_work);
11072027875bSKent Overstreet 	INIT_WORK(&c->snapshot_wait_for_pagecache_and_delete_work,
11082027875bSKent Overstreet 		  bch2_subvolume_wait_for_pagecache_and_delete);
11092027875bSKent Overstreet 	mutex_init(&c->snapshots_unlinked_lock);
111014b393eeSKent Overstreet 	return 0;
111114b393eeSKent Overstreet }
1112