xref: /linux/fs/bcachefs/subvolume.c (revision 64304aaf4ef3d14c46d711a35a7b78bb5790350a)
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"
98e877caaSKent Overstreet #include "snapshot.h"
1014b393eeSKent Overstreet #include "subvolume.h"
1114b393eeSKent Overstreet 
12f26c67f4SKent Overstreet #include <linux/random.h>
13f26c67f4SKent Overstreet 
14653693beSKent Overstreet static int bch2_subvolume_delete(struct btree_trans *, u32);
15653693beSKent Overstreet 
164ab35c34SKent Overstreet static int check_subvol(struct btree_trans *trans,
176738dd19SKent Overstreet 			struct btree_iter *iter,
186738dd19SKent Overstreet 			struct bkey_s_c k)
194ab35c34SKent Overstreet {
201c59b483SKent Overstreet 	struct bch_fs *c = trans->c;
214ab35c34SKent Overstreet 	struct bkey_s_c_subvolume subvol;
2235f1a503SKent Overstreet 	struct bch_snapshot snapshot;
2335f1a503SKent Overstreet 	unsigned snapid;
241c59b483SKent Overstreet 	int ret = 0;
254ab35c34SKent Overstreet 
264ab35c34SKent Overstreet 	if (k.k->type != KEY_TYPE_subvolume)
274ab35c34SKent Overstreet 		return 0;
284ab35c34SKent Overstreet 
294ab35c34SKent Overstreet 	subvol = bkey_s_c_to_subvolume(k);
3035f1a503SKent Overstreet 	snapid = le32_to_cpu(subvol.v->snapshot);
318e877caaSKent Overstreet 	ret = bch2_snapshot_lookup(trans, snapid, &snapshot);
3235f1a503SKent Overstreet 
331c59b483SKent Overstreet 	if (bch2_err_matches(ret, ENOENT))
341c59b483SKent Overstreet 		bch_err(c, "subvolume %llu points to nonexistent snapshot %u",
3535f1a503SKent Overstreet 			k.k->p.offset, snapid);
3635f1a503SKent Overstreet 	if (ret)
3735f1a503SKent Overstreet 		return ret;
384ab35c34SKent Overstreet 
394ab35c34SKent Overstreet 	if (BCH_SUBVOLUME_UNLINKED(subvol.v)) {
404ab35c34SKent Overstreet 		ret = bch2_subvolume_delete(trans, iter->pos.offset);
41e46c181aSKent Overstreet 		bch_err_msg(c, ret, "deleting subvolume %llu", iter->pos.offset);
42653693beSKent Overstreet 		return ret ?: -BCH_ERR_transaction_restart_nested;
434ab35c34SKent Overstreet 	}
444ab35c34SKent Overstreet 
454c20278eSKent Overstreet 	struct bch_inode_unpacked inode;
464c20278eSKent Overstreet 	struct btree_iter inode_iter = {};
474c20278eSKent Overstreet 	ret = bch2_inode_peek_nowarn(trans, &inode_iter, &inode,
484c20278eSKent Overstreet 				    (subvol_inum) { k.k->p.offset, le64_to_cpu(subvol.v->inode) },
494c20278eSKent Overstreet 				    0);
504c20278eSKent Overstreet 	bch2_trans_iter_exit(trans, &inode_iter);
514c20278eSKent Overstreet 
524c20278eSKent Overstreet 	if (ret && !bch2_err_matches(ret, ENOENT))
534c20278eSKent Overstreet 		return ret;
544c20278eSKent Overstreet 
554c20278eSKent Overstreet 	if (fsck_err_on(ret, c, subvol_to_missing_root,
564c20278eSKent Overstreet 			"subvolume %llu points to missing subvolume root %llu:%u",
574c20278eSKent Overstreet 			k.k->p.offset, le64_to_cpu(subvol.v->inode),
584c20278eSKent Overstreet 			le32_to_cpu(subvol.v->snapshot))) {
594c20278eSKent Overstreet 		ret = bch2_subvolume_delete(trans, iter->pos.offset);
604c20278eSKent Overstreet 		bch_err_msg(c, ret, "deleting subvolume %llu", iter->pos.offset);
614c20278eSKent Overstreet 		return ret ?: -BCH_ERR_transaction_restart_nested;
624c20278eSKent Overstreet 	}
634c20278eSKent Overstreet 
644c20278eSKent Overstreet 	if (fsck_err_on(inode.bi_subvol != subvol.k->p.offset,
654c20278eSKent Overstreet 			c, subvol_root_wrong_bi_subvol,
664c20278eSKent Overstreet 			"subvol root %llu:%u has wrong bi_subvol field: got %u, should be %llu",
674c20278eSKent Overstreet 			inode.bi_inum, inode_iter.k.p.snapshot,
684c20278eSKent Overstreet 			inode.bi_subvol, subvol.k->p.offset)) {
694c20278eSKent Overstreet 		inode.bi_subvol = subvol.k->p.offset;
704c20278eSKent Overstreet 		ret = __bch2_fsck_write_inode(trans, &inode, le32_to_cpu(subvol.v->snapshot));
714c20278eSKent Overstreet 		if (ret)
724c20278eSKent Overstreet 			goto err;
734c20278eSKent Overstreet 	}
744c20278eSKent Overstreet 
751c59b483SKent Overstreet 	if (!BCH_SUBVOLUME_SNAP(subvol.v)) {
761c59b483SKent Overstreet 		u32 snapshot_root = bch2_snapshot_root(c, le32_to_cpu(subvol.v->snapshot));
778479938dSKent Overstreet 		u32 snapshot_tree;
781c59b483SKent Overstreet 		struct bch_snapshot_tree st;
791c59b483SKent Overstreet 
808479938dSKent Overstreet 		rcu_read_lock();
818479938dSKent Overstreet 		snapshot_tree = snapshot_t(c, snapshot_root)->tree;
828479938dSKent Overstreet 		rcu_read_unlock();
838479938dSKent Overstreet 
84cb1b479dSKent Overstreet 		ret = bch2_snapshot_tree_lookup(trans, snapshot_tree, &st);
851c59b483SKent Overstreet 
861c59b483SKent Overstreet 		bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), c,
871c59b483SKent Overstreet 				"%s: snapshot tree %u not found", __func__, snapshot_tree);
881c59b483SKent Overstreet 
891c59b483SKent Overstreet 		if (ret)
901c59b483SKent Overstreet 			return ret;
911c59b483SKent Overstreet 
92b65db750SKent Overstreet 		if (fsck_err_on(le32_to_cpu(st.master_subvol) != subvol.k->p.offset,
93b65db750SKent Overstreet 				c, subvol_not_master_and_not_snapshot,
941c59b483SKent Overstreet 				"subvolume %llu is not set as snapshot but is not master subvolume",
951c59b483SKent Overstreet 				k.k->p.offset)) {
961c59b483SKent Overstreet 			struct bkey_i_subvolume *s =
970fb3355dSKent Overstreet 				bch2_bkey_make_mut_typed(trans, iter, &subvol.s_c, 0, subvolume);
981c59b483SKent Overstreet 			ret = PTR_ERR_OR_ZERO(s);
991c59b483SKent Overstreet 			if (ret)
1001c59b483SKent Overstreet 				return ret;
1011c59b483SKent Overstreet 
1021c59b483SKent Overstreet 			SET_BCH_SUBVOLUME_SNAP(&s->v, true);
1031c59b483SKent Overstreet 		}
1041c59b483SKent Overstreet 	}
1051c59b483SKent Overstreet 
1064c20278eSKent Overstreet err:
1071c59b483SKent Overstreet fsck_err:
1081c59b483SKent Overstreet 	return ret;
1094ab35c34SKent Overstreet }
1104ab35c34SKent Overstreet 
111067d228bSKent Overstreet int bch2_check_subvols(struct bch_fs *c)
1124ab35c34SKent Overstreet {
11380eab7a7SKent Overstreet 	int ret = bch2_trans_run(c,
1146bd68ec2SKent Overstreet 		for_each_btree_key_commit(trans, iter,
1156738dd19SKent Overstreet 				BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k,
1163f0e297dSKent Overstreet 				NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
1176bd68ec2SKent Overstreet 			check_subvol(trans, &iter, k)));
1181bb3c2a9SKent Overstreet 	bch_err_fn(c, ret);
1194ab35c34SKent Overstreet 	return ret;
1204ab35c34SKent Overstreet }
1214ab35c34SKent Overstreet 
12214b393eeSKent Overstreet /* Subvolumes: */
12314b393eeSKent Overstreet 
124b65db750SKent Overstreet int bch2_subvolume_invalid(struct bch_fs *c, struct bkey_s_c k,
1251f70225dSNathan Chancellor 			   enum bkey_invalid_flags flags, struct printbuf *err)
12614b393eeSKent Overstreet {
127b65db750SKent Overstreet 	int ret = 0;
12814b393eeSKent Overstreet 
129b65db750SKent Overstreet 	bkey_fsck_err_on(bkey_lt(k.k->p, SUBVOL_POS_MIN) ||
130b65db750SKent Overstreet 			 bkey_gt(k.k->p, SUBVOL_POS_MAX), c, err,
131b65db750SKent Overstreet 			 subvol_pos_bad,
132b65db750SKent Overstreet 			 "invalid pos");
133b65db750SKent Overstreet fsck_err:
134b65db750SKent Overstreet 	return ret;
13514b393eeSKent Overstreet }
13614b393eeSKent Overstreet 
13714b393eeSKent Overstreet void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c,
13814b393eeSKent Overstreet 			    struct bkey_s_c k)
13914b393eeSKent Overstreet {
14014b393eeSKent Overstreet 	struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k);
14114b393eeSKent Overstreet 
142401ec4dbSKent Overstreet 	prt_printf(out, "root %llu snapshot id %u",
14314b393eeSKent Overstreet 		   le64_to_cpu(s.v->inode),
14414b393eeSKent Overstreet 		   le32_to_cpu(s.v->snapshot));
145653693beSKent Overstreet 
146*64304aafSKent Overstreet 	if (bkey_val_bytes(s.k) > offsetof(struct bch_subvolume, creation_parent))
147*64304aafSKent Overstreet 		prt_printf(out, " creation_parent %u", le32_to_cpu(s.v->creation_parent));
14814b393eeSKent Overstreet }
14914b393eeSKent Overstreet 
15098638ffaSKent Overstreet static __always_inline int
15198638ffaSKent Overstreet bch2_subvolume_get_inlined(struct btree_trans *trans, unsigned subvol,
15297996ddfSKent Overstreet 			   bool inconsistent_if_not_found,
15397996ddfSKent Overstreet 			   int iter_flags,
15497996ddfSKent Overstreet 			   struct bch_subvolume *s)
15514b393eeSKent Overstreet {
156bcb79a51SKent Overstreet 	int ret = bch2_bkey_get_val_typed(trans, BTREE_ID_subvolumes, POS(0, subvol),
157bcb79a51SKent Overstreet 					  iter_flags, subvolume, s);
1581c59b483SKent Overstreet 	bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT) &&
1591c59b483SKent Overstreet 				inconsistent_if_not_found,
160bcb79a51SKent Overstreet 				trans->c, "missing subvolume %u", subvol);
16197996ddfSKent Overstreet 	return ret;
16214b393eeSKent Overstreet }
16314b393eeSKent Overstreet 
16498638ffaSKent Overstreet int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol,
16598638ffaSKent Overstreet 		       bool inconsistent_if_not_found,
16698638ffaSKent Overstreet 		       int iter_flags,
16798638ffaSKent Overstreet 		       struct bch_subvolume *s)
16898638ffaSKent Overstreet {
16998638ffaSKent Overstreet 	return bch2_subvolume_get_inlined(trans, subvol, inconsistent_if_not_found, iter_flags, s);
17098638ffaSKent Overstreet }
17198638ffaSKent Overstreet 
1720d72ab35SKent Overstreet int bch2_subvol_is_ro_trans(struct btree_trans *trans, u32 subvol)
1730d72ab35SKent Overstreet {
1740d72ab35SKent Overstreet 	struct bch_subvolume s;
1750d72ab35SKent Overstreet 	int ret = bch2_subvolume_get_inlined(trans, subvol, true, 0, &s);
1760d72ab35SKent Overstreet 	if (ret)
1770d72ab35SKent Overstreet 		return ret;
1780d72ab35SKent Overstreet 
1790d72ab35SKent Overstreet 	if (BCH_SUBVOLUME_RO(&s))
1800d72ab35SKent Overstreet 		return -EROFS;
1810d72ab35SKent Overstreet 	return 0;
1820d72ab35SKent Overstreet }
1830d72ab35SKent Overstreet 
1840d72ab35SKent Overstreet int bch2_subvol_is_ro(struct bch_fs *c, u32 subvol)
1850d72ab35SKent Overstreet {
1860d72ab35SKent Overstreet 	return bch2_trans_do(c, NULL, NULL, 0,
1870d72ab35SKent Overstreet 		bch2_subvol_is_ro_trans(trans, subvol));
1880d72ab35SKent Overstreet }
1890d72ab35SKent Overstreet 
1909ca4853bSKent Overstreet int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot,
1919ca4853bSKent Overstreet 			     struct bch_subvolume *subvol)
1929ca4853bSKent Overstreet {
1939ca4853bSKent Overstreet 	struct bch_snapshot snap;
1949ca4853bSKent Overstreet 
1958e877caaSKent Overstreet 	return  bch2_snapshot_lookup(trans, snapshot, &snap) ?:
1969ca4853bSKent Overstreet 		bch2_subvolume_get(trans, le32_to_cpu(snap.subvol), true, 0, subvol);
1979ca4853bSKent Overstreet }
1989ca4853bSKent Overstreet 
1998e877caaSKent Overstreet int bch2_subvolume_get_snapshot(struct btree_trans *trans, u32 subvolid,
20097996ddfSKent Overstreet 				u32 *snapid)
20197996ddfSKent Overstreet {
202653693beSKent Overstreet 	struct btree_iter iter;
2038e877caaSKent Overstreet 	struct bkey_s_c_subvolume subvol;
20497996ddfSKent Overstreet 	int ret;
20597996ddfSKent Overstreet 
2068e877caaSKent Overstreet 	subvol = bch2_bkey_get_iter_typed(trans, &iter,
2078e877caaSKent Overstreet 					  BTREE_ID_subvolumes, POS(0, subvolid),
2088e877caaSKent Overstreet 					  BTREE_ITER_CACHED|BTREE_ITER_WITH_UPDATES,
2098e877caaSKent Overstreet 					  subvolume);
2108e877caaSKent Overstreet 	ret = bkey_err(subvol);
2118e877caaSKent Overstreet 	bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), trans->c,
2128e877caaSKent Overstreet 				"missing subvolume %u", subvolid);
213653693beSKent Overstreet 
214653693beSKent Overstreet 	if (likely(!ret))
2158e877caaSKent Overstreet 		*snapid = le32_to_cpu(subvol.v->snapshot);
216653693beSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
21714b393eeSKent Overstreet 	return ret;
21814b393eeSKent Overstreet }
21914b393eeSKent Overstreet 
220653693beSKent Overstreet static int bch2_subvolume_reparent(struct btree_trans *trans,
221653693beSKent Overstreet 				   struct btree_iter *iter,
222653693beSKent Overstreet 				   struct bkey_s_c k,
223653693beSKent Overstreet 				   u32 old_parent, u32 new_parent)
224653693beSKent Overstreet {
225653693beSKent Overstreet 	struct bkey_i_subvolume *s;
226653693beSKent Overstreet 	int ret;
227653693beSKent Overstreet 
228653693beSKent Overstreet 	if (k.k->type != KEY_TYPE_subvolume)
229653693beSKent Overstreet 		return 0;
230653693beSKent Overstreet 
231*64304aafSKent Overstreet 	if (bkey_val_bytes(k.k) > offsetof(struct bch_subvolume, creation_parent) &&
232*64304aafSKent Overstreet 	    le32_to_cpu(bkey_s_c_to_subvolume(k).v->creation_parent) != old_parent)
233653693beSKent Overstreet 		return 0;
234653693beSKent Overstreet 
2350fb3355dSKent Overstreet 	s = bch2_bkey_make_mut_typed(trans, iter, &k, 0, subvolume);
236653693beSKent Overstreet 	ret = PTR_ERR_OR_ZERO(s);
237653693beSKent Overstreet 	if (ret)
238653693beSKent Overstreet 		return ret;
239653693beSKent Overstreet 
240*64304aafSKent Overstreet 	s->v.creation_parent = cpu_to_le32(new_parent);
241653693beSKent Overstreet 	return 0;
242653693beSKent Overstreet }
243653693beSKent Overstreet 
244653693beSKent Overstreet /*
2458e877caaSKent Overstreet  * Separate from the snapshot tree in the snapshots btree, we record the tree
2468e877caaSKent Overstreet  * structure of how snapshot subvolumes were created - the parent subvolume of
2478e877caaSKent Overstreet  * each snapshot subvolume.
2488e877caaSKent Overstreet  *
2498e877caaSKent Overstreet  * When a subvolume is deleted, we scan for child subvolumes and reparant them,
2508e877caaSKent Overstreet  * to avoid dangling references:
251653693beSKent Overstreet  */
252653693beSKent Overstreet static int bch2_subvolumes_reparent(struct btree_trans *trans, u32 subvolid_to_delete)
253653693beSKent Overstreet {
254653693beSKent Overstreet 	struct bch_subvolume s;
255653693beSKent Overstreet 
256653693beSKent Overstreet 	return lockrestart_do(trans,
257653693beSKent Overstreet 			bch2_subvolume_get(trans, subvolid_to_delete, true,
258653693beSKent Overstreet 				   BTREE_ITER_CACHED, &s)) ?:
259653693beSKent Overstreet 		for_each_btree_key_commit(trans, iter,
260653693beSKent Overstreet 				BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k,
261cb52d23eSKent Overstreet 				NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
262653693beSKent Overstreet 			bch2_subvolume_reparent(trans, &iter, k,
263*64304aafSKent Overstreet 					subvolid_to_delete, le32_to_cpu(s.creation_parent)));
264653693beSKent Overstreet }
265653693beSKent Overstreet 
2662027875bSKent Overstreet /*
2672027875bSKent Overstreet  * Delete subvolume, mark snapshot ID as deleted, queue up snapshot
2682027875bSKent Overstreet  * deletion/cleanup:
2692027875bSKent Overstreet  */
270653693beSKent Overstreet static int __bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
27114b393eeSKent Overstreet {
27214b393eeSKent Overstreet 	struct btree_iter iter;
27314b393eeSKent Overstreet 	struct bkey_s_c_subvolume subvol;
27414b393eeSKent Overstreet 	u32 snapid;
27514b393eeSKent Overstreet 	int ret = 0;
27614b393eeSKent Overstreet 
277bcb79a51SKent Overstreet 	subvol = bch2_bkey_get_iter_typed(trans, &iter,
278bcb79a51SKent Overstreet 				BTREE_ID_subvolumes, POS(0, subvolid),
279bcb79a51SKent Overstreet 				BTREE_ITER_CACHED|BTREE_ITER_INTENT,
280bcb79a51SKent Overstreet 				subvolume);
281bcb79a51SKent Overstreet 	ret = bkey_err(subvol);
2821c59b483SKent Overstreet 	bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), trans->c,
2831c59b483SKent Overstreet 				"missing subvolume %u", subvolid);
28414b393eeSKent Overstreet 	if (ret)
285bcb79a51SKent Overstreet 		return ret;
28614b393eeSKent Overstreet 
28714b393eeSKent Overstreet 	snapid = le32_to_cpu(subvol.v->snapshot);
28814b393eeSKent Overstreet 
289b0b5bbf9SKent Overstreet 	ret =   bch2_btree_delete_at(trans, &iter, 0) ?:
290b0b5bbf9SKent Overstreet 		bch2_snapshot_node_set_deleted(trans, snapid);
29114b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
29214b393eeSKent Overstreet 	return ret;
29314b393eeSKent Overstreet }
29414b393eeSKent Overstreet 
295653693beSKent Overstreet static int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid)
296653693beSKent Overstreet {
297653693beSKent Overstreet 	return bch2_subvolumes_reparent(trans, subvolid) ?:
298cb52d23eSKent Overstreet 		commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
299653693beSKent Overstreet 			  __bch2_subvolume_delete(trans, subvolid));
300653693beSKent Overstreet }
301653693beSKent Overstreet 
30273bd774dSKent Overstreet static void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work)
3032027875bSKent Overstreet {
3042027875bSKent Overstreet 	struct bch_fs *c = container_of(work, struct bch_fs,
3052027875bSKent Overstreet 				snapshot_wait_for_pagecache_and_delete_work);
30691d961baSKent Overstreet 	snapshot_id_list s;
3072027875bSKent Overstreet 	u32 *id;
3082027875bSKent Overstreet 	int ret = 0;
3092027875bSKent Overstreet 
3102027875bSKent Overstreet 	while (!ret) {
3112027875bSKent Overstreet 		mutex_lock(&c->snapshots_unlinked_lock);
3122027875bSKent Overstreet 		s = c->snapshots_unlinked;
31391d961baSKent Overstreet 		darray_init(&c->snapshots_unlinked);
3142027875bSKent Overstreet 		mutex_unlock(&c->snapshots_unlinked_lock);
3152027875bSKent Overstreet 
3162027875bSKent Overstreet 		if (!s.nr)
3172027875bSKent Overstreet 			break;
3182027875bSKent Overstreet 
3192027875bSKent Overstreet 		bch2_evict_subvolume_inodes(c, &s);
3202027875bSKent Overstreet 
32191d961baSKent Overstreet 		for (id = s.data; id < s.data + s.nr; id++) {
3226bd68ec2SKent Overstreet 			ret = bch2_trans_run(c, bch2_subvolume_delete(trans, *id));
323e46c181aSKent Overstreet 			bch_err_msg(c, ret, "deleting subvolume %u", *id);
324cf904c8dSKent Overstreet 			if (ret)
3252027875bSKent Overstreet 				break;
3262027875bSKent Overstreet 		}
3272027875bSKent Overstreet 
32891d961baSKent Overstreet 		darray_exit(&s);
3292027875bSKent Overstreet 	}
3302027875bSKent Overstreet 
331d94189adSKent Overstreet 	bch2_write_ref_put(c, BCH_WRITE_REF_snapshot_delete_pagecache);
3322027875bSKent Overstreet }
3332027875bSKent Overstreet 
3342027875bSKent Overstreet struct subvolume_unlink_hook {
3352027875bSKent Overstreet 	struct btree_trans_commit_hook	h;
3362027875bSKent Overstreet 	u32				subvol;
3372027875bSKent Overstreet };
3382027875bSKent Overstreet 
33973bd774dSKent Overstreet static int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans *trans,
3402027875bSKent Overstreet 						      struct btree_trans_commit_hook *_h)
3412027875bSKent Overstreet {
3422027875bSKent Overstreet 	struct subvolume_unlink_hook *h = container_of(_h, struct subvolume_unlink_hook, h);
3432027875bSKent Overstreet 	struct bch_fs *c = trans->c;
3442027875bSKent Overstreet 	int ret = 0;
3452027875bSKent Overstreet 
3462027875bSKent Overstreet 	mutex_lock(&c->snapshots_unlinked_lock);
3472027875bSKent Overstreet 	if (!snapshot_list_has_id(&c->snapshots_unlinked, h->subvol))
348597dee1cSKent Overstreet 		ret = snapshot_list_add(c, &c->snapshots_unlinked, h->subvol);
3492027875bSKent Overstreet 	mutex_unlock(&c->snapshots_unlinked_lock);
3502027875bSKent Overstreet 
3512027875bSKent Overstreet 	if (ret)
3522027875bSKent Overstreet 		return ret;
3532027875bSKent Overstreet 
354d94189adSKent Overstreet 	if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_snapshot_delete_pagecache))
3552027875bSKent Overstreet 		return -EROFS;
3562027875bSKent Overstreet 
3578bff9875SBrian Foster 	if (!queue_work(c->write_ref_wq, &c->snapshot_wait_for_pagecache_and_delete_work))
358d94189adSKent Overstreet 		bch2_write_ref_put(c, BCH_WRITE_REF_snapshot_delete_pagecache);
3592027875bSKent Overstreet 	return 0;
3602027875bSKent Overstreet }
3612027875bSKent Overstreet 
3622027875bSKent Overstreet int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid)
3632027875bSKent Overstreet {
3642027875bSKent Overstreet 	struct btree_iter iter;
3652027875bSKent Overstreet 	struct bkey_i_subvolume *n;
3662027875bSKent Overstreet 	struct subvolume_unlink_hook *h;
3672027875bSKent Overstreet 	int ret = 0;
3682027875bSKent Overstreet 
369f12a798aSKent Overstreet 	h = bch2_trans_kmalloc(trans, sizeof(*h));
370f12a798aSKent Overstreet 	ret = PTR_ERR_OR_ZERO(h);
371f12a798aSKent Overstreet 	if (ret)
372f12a798aSKent Overstreet 		return ret;
373f12a798aSKent Overstreet 
374f12a798aSKent Overstreet 	h->h.fn		= bch2_subvolume_wait_for_pagecache_and_delete_hook;
375f12a798aSKent Overstreet 	h->subvol	= subvolid;
376f12a798aSKent Overstreet 	bch2_trans_commit_hook(trans, &h->h);
377f12a798aSKent Overstreet 
37834dfa5dbSKent Overstreet 	n = bch2_bkey_get_mut_typed(trans, &iter,
37934dfa5dbSKent Overstreet 			BTREE_ID_subvolumes, POS(0, subvolid),
38034dfa5dbSKent Overstreet 			BTREE_ITER_CACHED, subvolume);
381994ba475SKent Overstreet 	ret = PTR_ERR_OR_ZERO(n);
382994ba475SKent Overstreet 	if (unlikely(ret)) {
3831c59b483SKent Overstreet 		bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), trans->c,
3841c59b483SKent Overstreet 					"missing subvolume %u", subvolid);
385f12a798aSKent Overstreet 		return ret;
3862027875bSKent Overstreet 	}
3872027875bSKent Overstreet 
3882027875bSKent Overstreet 	SET_BCH_SUBVOLUME_UNLINKED(&n->v, true);
3892027875bSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
3902027875bSKent Overstreet 	return ret;
3912027875bSKent Overstreet }
3922027875bSKent Overstreet 
39314b393eeSKent Overstreet int bch2_subvolume_create(struct btree_trans *trans, u64 inode,
39414b393eeSKent Overstreet 			  u32 src_subvolid,
39514b393eeSKent Overstreet 			  u32 *new_subvolid,
39614b393eeSKent Overstreet 			  u32 *new_snapshotid,
39714b393eeSKent Overstreet 			  bool ro)
39814b393eeSKent Overstreet {
399653693beSKent Overstreet 	struct bch_fs *c = trans->c;
40014b393eeSKent Overstreet 	struct btree_iter dst_iter, src_iter = (struct btree_iter) { NULL };
40114b393eeSKent Overstreet 	struct bkey_i_subvolume *new_subvol = NULL;
40214b393eeSKent Overstreet 	struct bkey_i_subvolume *src_subvol = NULL;
40314b393eeSKent Overstreet 	u32 parent = 0, new_nodes[2], snapshot_subvols[2];
40414b393eeSKent Overstreet 	int ret = 0;
40514b393eeSKent Overstreet 
40651e84d3bSKent Overstreet 	ret = bch2_bkey_get_empty_slot(trans, &dst_iter,
40751e84d3bSKent Overstreet 				BTREE_ID_subvolumes, POS(0, U32_MAX));
40851e84d3bSKent Overstreet 	if (ret == -BCH_ERR_ENOSPC_btree_slot)
409098ef98dSKent Overstreet 		ret = -BCH_ERR_ENOSPC_subvolume_create;
41051e84d3bSKent Overstreet 	if (ret)
41151e84d3bSKent Overstreet 		return ret;
41251e84d3bSKent Overstreet 
41314b393eeSKent Overstreet 	snapshot_subvols[0] = dst_iter.pos.offset;
41414b393eeSKent Overstreet 	snapshot_subvols[1] = src_subvolid;
41514b393eeSKent Overstreet 
41614b393eeSKent Overstreet 	if (src_subvolid) {
41714b393eeSKent Overstreet 		/* Creating a snapshot: */
41814b393eeSKent Overstreet 
41934dfa5dbSKent Overstreet 		src_subvol = bch2_bkey_get_mut_typed(trans, &src_iter,
42034dfa5dbSKent Overstreet 				BTREE_ID_subvolumes, POS(0, src_subvolid),
42134dfa5dbSKent Overstreet 				BTREE_ITER_CACHED, subvolume);
422994ba475SKent Overstreet 		ret = PTR_ERR_OR_ZERO(src_subvol);
423994ba475SKent Overstreet 		if (unlikely(ret)) {
424e47a390aSKent Overstreet 			bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), c,
425994ba475SKent Overstreet 						"subvolume %u not found", src_subvolid);
42614b393eeSKent Overstreet 			goto err;
42714b393eeSKent Overstreet 		}
42814b393eeSKent Overstreet 
42914b393eeSKent Overstreet 		parent = le32_to_cpu(src_subvol->v.snapshot);
43014b393eeSKent Overstreet 	}
43114b393eeSKent Overstreet 
43214b393eeSKent Overstreet 	ret = bch2_snapshot_node_create(trans, parent, new_nodes,
43314b393eeSKent Overstreet 					snapshot_subvols,
43414b393eeSKent Overstreet 					src_subvolid ? 2 : 1);
43514b393eeSKent Overstreet 	if (ret)
43614b393eeSKent Overstreet 		goto err;
43714b393eeSKent Overstreet 
43814b393eeSKent Overstreet 	if (src_subvolid) {
43914b393eeSKent Overstreet 		src_subvol->v.snapshot = cpu_to_le32(new_nodes[1]);
44094a3e1a6SKent Overstreet 		ret = bch2_trans_update(trans, &src_iter, &src_subvol->k_i, 0);
44194a3e1a6SKent Overstreet 		if (ret)
44294a3e1a6SKent Overstreet 			goto err;
44314b393eeSKent Overstreet 	}
44414b393eeSKent Overstreet 
445f8cb35fdSKent Overstreet 	new_subvol = bch2_bkey_alloc(trans, &dst_iter, 0, subvolume);
44614b393eeSKent Overstreet 	ret = PTR_ERR_OR_ZERO(new_subvol);
44714b393eeSKent Overstreet 	if (ret)
44814b393eeSKent Overstreet 		goto err;
44914b393eeSKent Overstreet 
45014b393eeSKent Overstreet 	new_subvol->v.flags		= 0;
45114b393eeSKent Overstreet 	new_subvol->v.snapshot		= cpu_to_le32(new_nodes[0]);
45214b393eeSKent Overstreet 	new_subvol->v.inode		= cpu_to_le64(inode);
453*64304aafSKent Overstreet 	new_subvol->v.creation_parent	= cpu_to_le32(src_subvolid);
454653693beSKent Overstreet 	new_subvol->v.otime.lo		= cpu_to_le64(bch2_current_time(c));
455653693beSKent Overstreet 	new_subvol->v.otime.hi		= 0;
456653693beSKent Overstreet 
45714b393eeSKent Overstreet 	SET_BCH_SUBVOLUME_RO(&new_subvol->v, ro);
45814b393eeSKent Overstreet 	SET_BCH_SUBVOLUME_SNAP(&new_subvol->v, src_subvolid != 0);
45914b393eeSKent Overstreet 
46014b393eeSKent Overstreet 	*new_subvolid	= new_subvol->k.p.offset;
46114b393eeSKent Overstreet 	*new_snapshotid	= new_nodes[0];
46214b393eeSKent Overstreet err:
46314b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &src_iter);
46414b393eeSKent Overstreet 	bch2_trans_iter_exit(trans, &dst_iter);
46514b393eeSKent Overstreet 	return ret;
46614b393eeSKent Overstreet }
46714b393eeSKent Overstreet 
46814b393eeSKent Overstreet int bch2_fs_subvolumes_init(struct bch_fs *c)
46914b393eeSKent Overstreet {
47014b393eeSKent Overstreet 	INIT_WORK(&c->snapshot_delete_work, bch2_delete_dead_snapshots_work);
4712027875bSKent Overstreet 	INIT_WORK(&c->snapshot_wait_for_pagecache_and_delete_work,
4722027875bSKent Overstreet 		  bch2_subvolume_wait_for_pagecache_and_delete);
4732027875bSKent Overstreet 	mutex_init(&c->snapshots_unlinked_lock);
47414b393eeSKent Overstreet 	return 0;
47514b393eeSKent Overstreet }
476