xref: /linux/fs/bcachefs/fs-common.c (revision 9862022d09f785088619fd3c14063592fddc2aa5)
196385742SKent Overstreet // SPDX-License-Identifier: GPL-2.0
296385742SKent Overstreet 
396385742SKent Overstreet #include "bcachefs.h"
496385742SKent Overstreet #include "acl.h"
596385742SKent Overstreet #include "btree_update.h"
696385742SKent Overstreet #include "dirent.h"
796385742SKent Overstreet #include "fs-common.h"
896385742SKent Overstreet #include "inode.h"
96fed42bbSKent Overstreet #include "subvolume.h"
1096385742SKent Overstreet #include "xattr.h"
1196385742SKent Overstreet 
1296385742SKent Overstreet #include <linux/posix_acl.h>
1396385742SKent Overstreet 
1442d23732SKent Overstreet static inline int is_subdir_for_nlink(struct bch_inode_unpacked *inode)
1542d23732SKent Overstreet {
1642d23732SKent Overstreet 	return S_ISDIR(inode->bi_mode) && !inode->bi_subvol;
1742d23732SKent Overstreet }
1842d23732SKent Overstreet 
196fed42bbSKent Overstreet int bch2_create_trans(struct btree_trans *trans,
206fed42bbSKent Overstreet 		      subvol_inum dir,
2196385742SKent Overstreet 		      struct bch_inode_unpacked *dir_u,
2296385742SKent Overstreet 		      struct bch_inode_unpacked *new_inode,
2396385742SKent Overstreet 		      const struct qstr *name,
2496385742SKent Overstreet 		      uid_t uid, gid_t gid, umode_t mode, dev_t rdev,
2596385742SKent Overstreet 		      struct posix_acl *default_acl,
266fed42bbSKent Overstreet 		      struct posix_acl *acl,
2742d23732SKent Overstreet 		      subvol_inum snapshot_src,
286fed42bbSKent Overstreet 		      unsigned flags)
2996385742SKent Overstreet {
3096385742SKent Overstreet 	struct bch_fs *c = trans->c;
3167e0dd8fSKent Overstreet 	struct btree_iter dir_iter = { NULL };
3267e0dd8fSKent Overstreet 	struct btree_iter inode_iter = { NULL };
336fed42bbSKent Overstreet 	subvol_inum new_inum = dir;
34ab2a29ccSKent Overstreet 	u64 now = bch2_current_time(c);
35bff796aeSKent Overstreet 	u64 cpu = raw_smp_processor_id();
366fed42bbSKent Overstreet 	u64 dir_target;
376fed42bbSKent Overstreet 	u32 snapshot;
3842d23732SKent Overstreet 	unsigned dir_type = mode_to_type(mode);
3996385742SKent Overstreet 	int ret;
4096385742SKent Overstreet 
416fed42bbSKent Overstreet 	ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot);
426fed42bbSKent Overstreet 	if (ret)
436fed42bbSKent Overstreet 		goto err;
446fed42bbSKent Overstreet 
455dd8c60eSKent Overstreet 	ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_intent);
468b53852dSKent Overstreet 	if (ret)
478b53852dSKent Overstreet 		goto err;
4896385742SKent Overstreet 
4942d23732SKent Overstreet 	if (!(flags & BCH_CREATE_SNAPSHOT)) {
5042d23732SKent Overstreet 		/* Normal create path - allocate a new inode: */
5196385742SKent Overstreet 		bch2_inode_init_late(new_inode, now, uid, gid, mode, rdev, dir_u);
5296385742SKent Overstreet 
5342d23732SKent Overstreet 		if (flags & BCH_CREATE_TMPFILE)
54103ffe9aSKent Overstreet 			new_inode->bi_flags |= BCH_INODE_unlinked;
5596385742SKent Overstreet 
566fed42bbSKent Overstreet 		ret = bch2_inode_create(trans, &inode_iter, new_inode, snapshot, cpu);
5796385742SKent Overstreet 		if (ret)
588b53852dSKent Overstreet 			goto err;
5996385742SKent Overstreet 
6042d23732SKent Overstreet 		snapshot_src = (subvol_inum) { 0 };
6142d23732SKent Overstreet 	} else {
6242d23732SKent Overstreet 		/*
6342d23732SKent Overstreet 		 * Creating a snapshot - we're not allocating a new inode, but
6442d23732SKent Overstreet 		 * we do have to lookup the root inode of the subvolume we're
6542d23732SKent Overstreet 		 * snapshotting and update it (in the new snapshot):
6642d23732SKent Overstreet 		 */
6742d23732SKent Overstreet 
6842d23732SKent Overstreet 		if (!snapshot_src.inum) {
6942d23732SKent Overstreet 			/* Inode wasn't specified, just snapshot: */
7097996ddfSKent Overstreet 			struct bch_subvolume s;
7142d23732SKent Overstreet 
7297996ddfSKent Overstreet 			ret = bch2_subvolume_get(trans, snapshot_src.subvol, true,
735dd8c60eSKent Overstreet 						 BTREE_ITER_cached, &s);
7442d23732SKent Overstreet 			if (ret)
7542d23732SKent Overstreet 				goto err;
7697996ddfSKent Overstreet 
7797996ddfSKent Overstreet 			snapshot_src.inum = le64_to_cpu(s.inode);
7842d23732SKent Overstreet 		}
7942d23732SKent Overstreet 
8042d23732SKent Overstreet 		ret = bch2_inode_peek(trans, &inode_iter, new_inode, snapshot_src,
815dd8c60eSKent Overstreet 				      BTREE_ITER_intent);
8242d23732SKent Overstreet 		if (ret)
8342d23732SKent Overstreet 			goto err;
8442d23732SKent Overstreet 
8542d23732SKent Overstreet 		if (new_inode->bi_subvol != snapshot_src.subvol) {
8642d23732SKent Overstreet 			/* Not a subvolume root: */
8742d23732SKent Overstreet 			ret = -EINVAL;
8842d23732SKent Overstreet 			goto err;
8942d23732SKent Overstreet 		}
9042d23732SKent Overstreet 
9142d23732SKent Overstreet 		/*
9242d23732SKent Overstreet 		 * If we're not root, we have to own the subvolume being
9342d23732SKent Overstreet 		 * snapshotted:
9442d23732SKent Overstreet 		 */
9542d23732SKent Overstreet 		if (uid && new_inode->bi_uid != uid) {
9642d23732SKent Overstreet 			ret = -EPERM;
9742d23732SKent Overstreet 			goto err;
9842d23732SKent Overstreet 		}
9942d23732SKent Overstreet 
10042d23732SKent Overstreet 		flags |= BCH_CREATE_SUBVOL;
10142d23732SKent Overstreet 	}
10242d23732SKent Overstreet 
1036fed42bbSKent Overstreet 	new_inum.inum	= new_inode->bi_inum;
1046fed42bbSKent Overstreet 	dir_target	= new_inode->bi_inum;
1056fed42bbSKent Overstreet 
10642d23732SKent Overstreet 	if (flags & BCH_CREATE_SUBVOL) {
10742d23732SKent Overstreet 		u32 new_subvol, dir_snapshot;
10842d23732SKent Overstreet 
10942d23732SKent Overstreet 		ret = bch2_subvolume_create(trans, new_inode->bi_inum,
110b8628a25SKent Overstreet 					    dir.subvol,
11142d23732SKent Overstreet 					    snapshot_src.subvol,
11242d23732SKent Overstreet 					    &new_subvol, &snapshot,
11342d23732SKent Overstreet 					    (flags & BCH_CREATE_SNAPSHOT_RO) != 0);
11442d23732SKent Overstreet 		if (ret)
11542d23732SKent Overstreet 			goto err;
11642d23732SKent Overstreet 
11742d23732SKent Overstreet 		new_inode->bi_parent_subvol	= dir.subvol;
11842d23732SKent Overstreet 		new_inode->bi_subvol		= new_subvol;
11942d23732SKent Overstreet 		new_inum.subvol			= new_subvol;
12042d23732SKent Overstreet 		dir_target			= new_subvol;
12142d23732SKent Overstreet 		dir_type			= DT_SUBVOL;
12242d23732SKent Overstreet 
12342d23732SKent Overstreet 		ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &dir_snapshot);
12442d23732SKent Overstreet 		if (ret)
12542d23732SKent Overstreet 			goto err;
12642d23732SKent Overstreet 
12742d23732SKent Overstreet 		bch2_btree_iter_set_snapshot(&dir_iter, dir_snapshot);
12842d23732SKent Overstreet 		ret = bch2_btree_iter_traverse(&dir_iter);
12942d23732SKent Overstreet 		if (ret)
13042d23732SKent Overstreet 			goto err;
13142d23732SKent Overstreet 	}
13242d23732SKent Overstreet 
13342d23732SKent Overstreet 	if (!(flags & BCH_CREATE_SNAPSHOT)) {
13496385742SKent Overstreet 		if (default_acl) {
1356fed42bbSKent Overstreet 			ret = bch2_set_acl_trans(trans, new_inum, new_inode,
13696385742SKent Overstreet 						 default_acl, ACL_TYPE_DEFAULT);
13796385742SKent Overstreet 			if (ret)
1388b53852dSKent Overstreet 				goto err;
13996385742SKent Overstreet 		}
14096385742SKent Overstreet 
14196385742SKent Overstreet 		if (acl) {
1426fed42bbSKent Overstreet 			ret = bch2_set_acl_trans(trans, new_inum, new_inode,
14396385742SKent Overstreet 						 acl, ACL_TYPE_ACCESS);
14496385742SKent Overstreet 			if (ret)
1458b53852dSKent Overstreet 				goto err;
14696385742SKent Overstreet 		}
14742d23732SKent Overstreet 	}
14896385742SKent Overstreet 
14942d23732SKent Overstreet 	if (!(flags & BCH_CREATE_TMPFILE)) {
15096385742SKent Overstreet 		struct bch_hash_info dir_hash = bch2_hash_info_init(c, dir_u);
15142d23732SKent Overstreet 		u64 dir_offset;
15296385742SKent Overstreet 
15342d23732SKent Overstreet 		if (is_subdir_for_nlink(new_inode))
15496385742SKent Overstreet 			dir_u->bi_nlink++;
1556fed42bbSKent Overstreet 		dir_u->bi_mtime = dir_u->bi_ctime = now;
15696385742SKent Overstreet 
15767e0dd8fSKent Overstreet 		ret = bch2_inode_write(trans, &dir_iter, dir_u);
15896385742SKent Overstreet 		if (ret)
1598b53852dSKent Overstreet 			goto err;
16096385742SKent Overstreet 
1616fed42bbSKent Overstreet 		ret = bch2_dirent_create(trans, dir, &dir_hash,
1626fed42bbSKent Overstreet 					 dir_type,
1636fed42bbSKent Overstreet 					 name,
1646fed42bbSKent Overstreet 					 dir_target,
165ab2a29ccSKent Overstreet 					 &dir_offset,
1665dd8c60eSKent Overstreet 					 STR_HASH_must_create);
16796385742SKent Overstreet 		if (ret)
1688b53852dSKent Overstreet 			goto err;
169ab2a29ccSKent Overstreet 
170ab2a29ccSKent Overstreet 		new_inode->bi_dir		= dir_u->bi_inum;
171ab2a29ccSKent Overstreet 		new_inode->bi_dir_offset	= dir_offset;
172ab2a29ccSKent Overstreet 	}
173ab2a29ccSKent Overstreet 
1745dd8c60eSKent Overstreet 	inode_iter.flags &= ~BTREE_ITER_all_snapshots;
1756fed42bbSKent Overstreet 	bch2_btree_iter_set_snapshot(&inode_iter, snapshot);
176e6ae2727SKent Overstreet 
17767e0dd8fSKent Overstreet 	ret   = bch2_btree_iter_traverse(&inode_iter) ?:
17867e0dd8fSKent Overstreet 		bch2_inode_write(trans, &inode_iter, new_inode);
1798b53852dSKent Overstreet err:
18067e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &inode_iter);
18167e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &dir_iter);
1828b53852dSKent Overstreet 	return ret;
18396385742SKent Overstreet }
18496385742SKent Overstreet 
1856fed42bbSKent Overstreet int bch2_link_trans(struct btree_trans *trans,
1866fed42bbSKent Overstreet 		    subvol_inum dir,  struct bch_inode_unpacked *dir_u,
1876fed42bbSKent Overstreet 		    subvol_inum inum, struct bch_inode_unpacked *inode_u,
1886fed42bbSKent Overstreet 		    const struct qstr *name)
18996385742SKent Overstreet {
190ab2a29ccSKent Overstreet 	struct bch_fs *c = trans->c;
19167e0dd8fSKent Overstreet 	struct btree_iter dir_iter = { NULL };
19267e0dd8fSKent Overstreet 	struct btree_iter inode_iter = { NULL };
19396385742SKent Overstreet 	struct bch_hash_info dir_hash;
194ab2a29ccSKent Overstreet 	u64 now = bch2_current_time(c);
195ab2a29ccSKent Overstreet 	u64 dir_offset = 0;
1968b53852dSKent Overstreet 	int ret;
19796385742SKent Overstreet 
1986fed42bbSKent Overstreet 	if (dir.subvol != inum.subvol)
1996fed42bbSKent Overstreet 		return -EXDEV;
2006fed42bbSKent Overstreet 
2015dd8c60eSKent Overstreet 	ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum, BTREE_ITER_intent);
2028b53852dSKent Overstreet 	if (ret)
203*9862022dSYouling Tang 		return ret;
20496385742SKent Overstreet 
20596385742SKent Overstreet 	inode_u->bi_ctime = now;
206962ad1a7SKent Overstreet 	ret = bch2_inode_nlink_inc(inode_u);
207962ad1a7SKent Overstreet 	if (ret)
208*9862022dSYouling Tang 		goto err;
20996385742SKent Overstreet 
2105dd8c60eSKent Overstreet 	ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_intent);
2118b53852dSKent Overstreet 	if (ret)
2128b53852dSKent Overstreet 		goto err;
21363fbf458SKent Overstreet 
214bf9cb250SKent Overstreet 	if (bch2_reinherit_attrs(inode_u, dir_u)) {
215bf9cb250SKent Overstreet 		ret = -EXDEV;
216bf9cb250SKent Overstreet 		goto err;
217bf9cb250SKent Overstreet 	}
218bf9cb250SKent Overstreet 
219184b1dc1SJustin Husted 	dir_u->bi_mtime = dir_u->bi_ctime = now;
22063fbf458SKent Overstreet 
221ab2a29ccSKent Overstreet 	dir_hash = bch2_hash_info_init(c, dir_u);
22263fbf458SKent Overstreet 
2236fed42bbSKent Overstreet 	ret = bch2_dirent_create(trans, dir, &dir_hash,
22496385742SKent Overstreet 				 mode_to_type(inode_u->bi_mode),
2256fed42bbSKent Overstreet 				 name, inum.inum, &dir_offset,
2265dd8c60eSKent Overstreet 				 STR_HASH_must_create);
227ab2a29ccSKent Overstreet 	if (ret)
228ab2a29ccSKent Overstreet 		goto err;
229ab2a29ccSKent Overstreet 
2306fed42bbSKent Overstreet 	inode_u->bi_dir		= dir.inum;
231ab2a29ccSKent Overstreet 	inode_u->bi_dir_offset	= dir_offset;
232ab2a29ccSKent Overstreet 
23367e0dd8fSKent Overstreet 	ret =   bch2_inode_write(trans, &dir_iter, dir_u) ?:
23467e0dd8fSKent Overstreet 		bch2_inode_write(trans, &inode_iter, inode_u);
2358b53852dSKent Overstreet err:
23667e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &dir_iter);
23767e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &inode_iter);
2388b53852dSKent Overstreet 	return ret;
23996385742SKent Overstreet }
24096385742SKent Overstreet 
24196385742SKent Overstreet int bch2_unlink_trans(struct btree_trans *trans,
2426fed42bbSKent Overstreet 		      subvol_inum dir,
2436fed42bbSKent Overstreet 		      struct bch_inode_unpacked *dir_u,
24496385742SKent Overstreet 		      struct bch_inode_unpacked *inode_u,
24542d23732SKent Overstreet 		      const struct qstr *name,
246835cd3e1SKent Overstreet 		      bool deleting_subvol)
24796385742SKent Overstreet {
248ab2a29ccSKent Overstreet 	struct bch_fs *c = trans->c;
24967e0dd8fSKent Overstreet 	struct btree_iter dir_iter = { NULL };
25067e0dd8fSKent Overstreet 	struct btree_iter dirent_iter = { NULL };
25167e0dd8fSKent Overstreet 	struct btree_iter inode_iter = { NULL };
25296385742SKent Overstreet 	struct bch_hash_info dir_hash;
2536fed42bbSKent Overstreet 	subvol_inum inum;
2546fed42bbSKent Overstreet 	u64 now = bch2_current_time(c);
25542d23732SKent Overstreet 	struct bkey_s_c k;
2568b53852dSKent Overstreet 	int ret;
25796385742SKent Overstreet 
2585dd8c60eSKent Overstreet 	ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_intent);
2598b53852dSKent Overstreet 	if (ret)
2608b53852dSKent Overstreet 		goto err;
26196385742SKent Overstreet 
262ab2a29ccSKent Overstreet 	dir_hash = bch2_hash_info_init(c, dir_u);
26396385742SKent Overstreet 
2645b6271b5SKent Overstreet 	ret = bch2_dirent_lookup_trans(trans, &dirent_iter, dir, &dir_hash,
2655dd8c60eSKent Overstreet 				       name, &inum, BTREE_ITER_intent);
2668b53852dSKent Overstreet 	if (ret)
2678b53852dSKent Overstreet 		goto err;
26896385742SKent Overstreet 
2696fed42bbSKent Overstreet 	ret = bch2_inode_peek(trans, &inode_iter, inode_u, inum,
2705dd8c60eSKent Overstreet 			      BTREE_ITER_intent);
2718b53852dSKent Overstreet 	if (ret)
2728b53852dSKent Overstreet 		goto err;
27396385742SKent Overstreet 
274835cd3e1SKent Overstreet 	if (!deleting_subvol && S_ISDIR(inode_u->bi_mode)) {
27542d23732SKent Overstreet 		ret = bch2_empty_dir_trans(trans, inum);
27642d23732SKent Overstreet 		if (ret)
27742d23732SKent Overstreet 			goto err;
27842d23732SKent Overstreet 	}
27942d23732SKent Overstreet 
280835cd3e1SKent Overstreet 	if (deleting_subvol && !inode_u->bi_subvol) {
281e47a390aSKent Overstreet 		ret = -BCH_ERR_ENOENT_not_subvol;
2827bd68c73SKent Overstreet 		goto err;
2837bd68c73SKent Overstreet 	}
2847bd68c73SKent Overstreet 
285835cd3e1SKent Overstreet 	if (inode_u->bi_subvol) {
286835cd3e1SKent Overstreet 		/* Recursive subvolume destroy not allowed (yet?) */
287835cd3e1SKent Overstreet 		ret = bch2_subvol_has_children(trans, inode_u->bi_subvol);
288835cd3e1SKent Overstreet 		if (ret)
289835cd3e1SKent Overstreet 			goto err;
290835cd3e1SKent Overstreet 	}
291835cd3e1SKent Overstreet 
292835cd3e1SKent Overstreet 	if (deleting_subvol || inode_u->bi_subvol) {
2932027875bSKent Overstreet 		ret = bch2_subvolume_unlink(trans, inode_u->bi_subvol);
29442d23732SKent Overstreet 		if (ret)
29542d23732SKent Overstreet 			goto err;
29642d23732SKent Overstreet 
29742d23732SKent Overstreet 		k = bch2_btree_iter_peek_slot(&dirent_iter);
29842d23732SKent Overstreet 		ret = bkey_err(k);
29942d23732SKent Overstreet 		if (ret)
30042d23732SKent Overstreet 			goto err;
30142d23732SKent Overstreet 
30242d23732SKent Overstreet 		/*
30342d23732SKent Overstreet 		 * If we're deleting a subvolume, we need to really delete the
30442d23732SKent Overstreet 		 * dirent, not just emit a whiteout in the current snapshot:
30542d23732SKent Overstreet 		 */
30642d23732SKent Overstreet 		bch2_btree_iter_set_snapshot(&dirent_iter, k.k->p.snapshot);
30742d23732SKent Overstreet 		ret = bch2_btree_iter_traverse(&dirent_iter);
30842d23732SKent Overstreet 		if (ret)
30942d23732SKent Overstreet 			goto err;
3107bd68c73SKent Overstreet 	} else {
311962ad1a7SKent Overstreet 		bch2_inode_nlink_dec(trans, inode_u);
31242d23732SKent Overstreet 	}
31342d23732SKent Overstreet 
3146fed42bbSKent Overstreet 	if (inode_u->bi_dir		== dirent_iter.pos.inode &&
3156fed42bbSKent Overstreet 	    inode_u->bi_dir_offset	== dirent_iter.pos.offset) {
316d3ff7fecSKent Overstreet 		inode_u->bi_dir		= 0;
317d3ff7fecSKent Overstreet 		inode_u->bi_dir_offset	= 0;
318d3ff7fecSKent Overstreet 	}
319d3ff7fecSKent Overstreet 
32096385742SKent Overstreet 	dir_u->bi_mtime = dir_u->bi_ctime = inode_u->bi_ctime = now;
32142d23732SKent Overstreet 	dir_u->bi_nlink -= is_subdir_for_nlink(inode_u);
32296385742SKent Overstreet 
32342d23732SKent Overstreet 	ret =   bch2_hash_delete_at(trans, bch2_dirent_hash_desc,
32442d23732SKent Overstreet 				    &dir_hash, &dirent_iter,
3255dd8c60eSKent Overstreet 				    BTREE_UPDATE_internal_snapshot_node) ?:
32667e0dd8fSKent Overstreet 		bch2_inode_write(trans, &dir_iter, dir_u) ?:
32767e0dd8fSKent Overstreet 		bch2_inode_write(trans, &inode_iter, inode_u);
3288b53852dSKent Overstreet err:
32967e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &inode_iter);
33067e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &dirent_iter);
33167e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &dir_iter);
3328b53852dSKent Overstreet 	return ret;
33396385742SKent Overstreet }
33496385742SKent Overstreet 
33596385742SKent Overstreet bool bch2_reinherit_attrs(struct bch_inode_unpacked *dst_u,
33696385742SKent Overstreet 			  struct bch_inode_unpacked *src_u)
33796385742SKent Overstreet {
33896385742SKent Overstreet 	u64 src, dst;
33996385742SKent Overstreet 	unsigned id;
34096385742SKent Overstreet 	bool ret = false;
34196385742SKent Overstreet 
34296385742SKent Overstreet 	for (id = 0; id < Inode_opt_nr; id++) {
343991ba021SKent Overstreet 		/* Skip attributes that were explicitly set on this inode */
34496385742SKent Overstreet 		if (dst_u->bi_fields_set & (1 << id))
34596385742SKent Overstreet 			continue;
34696385742SKent Overstreet 
34796385742SKent Overstreet 		src = bch2_inode_opt_get(src_u, id);
34896385742SKent Overstreet 		dst = bch2_inode_opt_get(dst_u, id);
34996385742SKent Overstreet 
35096385742SKent Overstreet 		if (src == dst)
35196385742SKent Overstreet 			continue;
35296385742SKent Overstreet 
35396385742SKent Overstreet 		bch2_inode_opt_set(dst_u, id, src);
35496385742SKent Overstreet 		ret = true;
35596385742SKent Overstreet 	}
35696385742SKent Overstreet 
35796385742SKent Overstreet 	return ret;
35896385742SKent Overstreet }
35996385742SKent Overstreet 
360b8628a25SKent Overstreet static int subvol_update_parent(struct btree_trans *trans, u32 subvol, u32 new_parent)
361b8628a25SKent Overstreet {
362b8628a25SKent Overstreet 	struct btree_iter iter;
363b8628a25SKent Overstreet 	struct bkey_i_subvolume *s =
364b8628a25SKent Overstreet 		bch2_bkey_get_mut_typed(trans, &iter,
365b8628a25SKent Overstreet 			BTREE_ID_subvolumes, POS(0, subvol),
3665dd8c60eSKent Overstreet 			BTREE_ITER_cached, subvolume);
367b8628a25SKent Overstreet 	int ret = PTR_ERR_OR_ZERO(s);
368b8628a25SKent Overstreet 	if (ret)
369b8628a25SKent Overstreet 		return ret;
370b8628a25SKent Overstreet 
371b8628a25SKent Overstreet 	s->v.fs_path_parent = cpu_to_le32(new_parent);
372b8628a25SKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
373b8628a25SKent Overstreet 	return 0;
374b8628a25SKent Overstreet }
375b8628a25SKent Overstreet 
37696385742SKent Overstreet int bch2_rename_trans(struct btree_trans *trans,
3776fed42bbSKent Overstreet 		      subvol_inum src_dir, struct bch_inode_unpacked *src_dir_u,
3786fed42bbSKent Overstreet 		      subvol_inum dst_dir, struct bch_inode_unpacked *dst_dir_u,
37996385742SKent Overstreet 		      struct bch_inode_unpacked *src_inode_u,
38096385742SKent Overstreet 		      struct bch_inode_unpacked *dst_inode_u,
38196385742SKent Overstreet 		      const struct qstr *src_name,
38296385742SKent Overstreet 		      const struct qstr *dst_name,
38396385742SKent Overstreet 		      enum bch_rename_mode mode)
38496385742SKent Overstreet {
385ab2a29ccSKent Overstreet 	struct bch_fs *c = trans->c;
38667e0dd8fSKent Overstreet 	struct btree_iter src_dir_iter = { NULL };
38767e0dd8fSKent Overstreet 	struct btree_iter dst_dir_iter = { NULL };
38867e0dd8fSKent Overstreet 	struct btree_iter src_inode_iter = { NULL };
38967e0dd8fSKent Overstreet 	struct btree_iter dst_inode_iter = { NULL };
39096385742SKent Overstreet 	struct bch_hash_info src_hash, dst_hash;
3916fed42bbSKent Overstreet 	subvol_inum src_inum, dst_inum;
3926fed42bbSKent Overstreet 	u64 src_offset, dst_offset;
393ab2a29ccSKent Overstreet 	u64 now = bch2_current_time(c);
39496385742SKent Overstreet 	int ret;
39596385742SKent Overstreet 
39667e0dd8fSKent Overstreet 	ret = bch2_inode_peek(trans, &src_dir_iter, src_dir_u, src_dir,
3975dd8c60eSKent Overstreet 			      BTREE_ITER_intent);
3988b53852dSKent Overstreet 	if (ret)
3998b53852dSKent Overstreet 		goto err;
40096385742SKent Overstreet 
401ab2a29ccSKent Overstreet 	src_hash = bch2_hash_info_init(c, src_dir_u);
40296385742SKent Overstreet 
4036fed42bbSKent Overstreet 	if (dst_dir.inum	!= src_dir.inum ||
4046fed42bbSKent Overstreet 	    dst_dir.subvol	!= src_dir.subvol) {
40567e0dd8fSKent Overstreet 		ret = bch2_inode_peek(trans, &dst_dir_iter, dst_dir_u, dst_dir,
4065dd8c60eSKent Overstreet 				      BTREE_ITER_intent);
4078b53852dSKent Overstreet 		if (ret)
4088b53852dSKent Overstreet 			goto err;
40996385742SKent Overstreet 
410ab2a29ccSKent Overstreet 		dst_hash = bch2_hash_info_init(c, dst_dir_u);
41196385742SKent Overstreet 	} else {
41296385742SKent Overstreet 		dst_dir_u = src_dir_u;
41396385742SKent Overstreet 		dst_hash = src_hash;
41496385742SKent Overstreet 	}
41596385742SKent Overstreet 
41696385742SKent Overstreet 	ret = bch2_dirent_rename(trans,
41796385742SKent Overstreet 				 src_dir, &src_hash,
41896385742SKent Overstreet 				 dst_dir, &dst_hash,
4196fed42bbSKent Overstreet 				 src_name, &src_inum, &src_offset,
4206fed42bbSKent Overstreet 				 dst_name, &dst_inum, &dst_offset,
42196385742SKent Overstreet 				 mode);
42296385742SKent Overstreet 	if (ret)
4238b53852dSKent Overstreet 		goto err;
42496385742SKent Overstreet 
4256fed42bbSKent Overstreet 	ret = bch2_inode_peek(trans, &src_inode_iter, src_inode_u, src_inum,
4265dd8c60eSKent Overstreet 			      BTREE_ITER_intent);
4278b53852dSKent Overstreet 	if (ret)
4288b53852dSKent Overstreet 		goto err;
42996385742SKent Overstreet 
4306fed42bbSKent Overstreet 	if (dst_inum.inum) {
4316fed42bbSKent Overstreet 		ret = bch2_inode_peek(trans, &dst_inode_iter, dst_inode_u, dst_inum,
4325dd8c60eSKent Overstreet 				      BTREE_ITER_intent);
4338b53852dSKent Overstreet 		if (ret)
4348b53852dSKent Overstreet 			goto err;
43596385742SKent Overstreet 	}
43696385742SKent Overstreet 
437b8628a25SKent Overstreet 	if (src_inode_u->bi_subvol &&
438b8628a25SKent Overstreet 	    dst_dir.subvol != src_inode_u->bi_parent_subvol) {
439b8628a25SKent Overstreet 		ret = subvol_update_parent(trans, src_inode_u->bi_subvol, dst_dir.subvol);
440b8628a25SKent Overstreet 		if (ret)
441b8628a25SKent Overstreet 			goto err;
442b8628a25SKent Overstreet 	}
443b8628a25SKent Overstreet 
444b8628a25SKent Overstreet 	if (mode == BCH_RENAME_EXCHANGE &&
445b8628a25SKent Overstreet 	    dst_inode_u->bi_subvol &&
446b8628a25SKent Overstreet 	    src_dir.subvol != dst_inode_u->bi_parent_subvol) {
447b8628a25SKent Overstreet 		ret = subvol_update_parent(trans, dst_inode_u->bi_subvol, src_dir.subvol);
448b8628a25SKent Overstreet 		if (ret)
449b8628a25SKent Overstreet 			goto err;
450b8628a25SKent Overstreet 	}
451b8628a25SKent Overstreet 
4527f76b08aSKent Overstreet 	/* Can't move across subvolumes, unless it's a subvolume root: */
4537f76b08aSKent Overstreet 	if (src_dir.subvol != dst_dir.subvol &&
4547f76b08aSKent Overstreet 	    (!src_inode_u->bi_subvol ||
4557f76b08aSKent Overstreet 	     (dst_inum.inum && !dst_inode_u->bi_subvol))) {
4567f76b08aSKent Overstreet 		ret = -EXDEV;
4577f76b08aSKent Overstreet 		goto err;
4587f76b08aSKent Overstreet 	}
4597f76b08aSKent Overstreet 
4607f76b08aSKent Overstreet 	if (src_inode_u->bi_parent_subvol)
4617f76b08aSKent Overstreet 		src_inode_u->bi_parent_subvol = dst_dir.subvol;
4627f76b08aSKent Overstreet 
4637f76b08aSKent Overstreet 	if ((mode == BCH_RENAME_EXCHANGE) &&
4647f76b08aSKent Overstreet 	    dst_inode_u->bi_parent_subvol)
4657f76b08aSKent Overstreet 		dst_inode_u->bi_parent_subvol = src_dir.subvol;
4667f76b08aSKent Overstreet 
467ab2a29ccSKent Overstreet 	src_inode_u->bi_dir		= dst_dir_u->bi_inum;
468ab2a29ccSKent Overstreet 	src_inode_u->bi_dir_offset	= dst_offset;
469ab2a29ccSKent Overstreet 
470ab2a29ccSKent Overstreet 	if (mode == BCH_RENAME_EXCHANGE) {
471ab2a29ccSKent Overstreet 		dst_inode_u->bi_dir		= src_dir_u->bi_inum;
472ab2a29ccSKent Overstreet 		dst_inode_u->bi_dir_offset	= src_offset;
473ab2a29ccSKent Overstreet 	}
47416ac8c95SKent Overstreet 
47516ac8c95SKent Overstreet 	if (mode == BCH_RENAME_OVERWRITE &&
47616ac8c95SKent Overstreet 	    dst_inode_u->bi_dir		== dst_dir_u->bi_inum &&
47716ac8c95SKent Overstreet 	    dst_inode_u->bi_dir_offset	== src_offset) {
47816ac8c95SKent Overstreet 		dst_inode_u->bi_dir		= 0;
47916ac8c95SKent Overstreet 		dst_inode_u->bi_dir_offset	= 0;
48016ac8c95SKent Overstreet 	}
481ab2a29ccSKent Overstreet 
48296385742SKent Overstreet 	if (mode == BCH_RENAME_OVERWRITE) {
48396385742SKent Overstreet 		if (S_ISDIR(src_inode_u->bi_mode) !=
4848b53852dSKent Overstreet 		    S_ISDIR(dst_inode_u->bi_mode)) {
4858b53852dSKent Overstreet 			ret = -ENOTDIR;
4868b53852dSKent Overstreet 			goto err;
4878b53852dSKent Overstreet 		}
48896385742SKent Overstreet 
489835cd3e1SKent Overstreet 		if (S_ISDIR(dst_inode_u->bi_mode)) {
490835cd3e1SKent Overstreet 			ret = bch2_empty_dir_trans(trans, dst_inum);
491835cd3e1SKent Overstreet 			if (ret)
4928b53852dSKent Overstreet 				goto err;
4938b53852dSKent Overstreet 		}
49496385742SKent Overstreet 	}
49596385742SKent Overstreet 
49696385742SKent Overstreet 	if (bch2_reinherit_attrs(src_inode_u, dst_dir_u) &&
4978b53852dSKent Overstreet 	    S_ISDIR(src_inode_u->bi_mode)) {
4988b53852dSKent Overstreet 		ret = -EXDEV;
4998b53852dSKent Overstreet 		goto err;
5008b53852dSKent Overstreet 	}
50196385742SKent Overstreet 
50296385742SKent Overstreet 	if (mode == BCH_RENAME_EXCHANGE &&
50396385742SKent Overstreet 	    bch2_reinherit_attrs(dst_inode_u, src_dir_u) &&
5048b53852dSKent Overstreet 	    S_ISDIR(dst_inode_u->bi_mode)) {
5058b53852dSKent Overstreet 		ret = -EXDEV;
5068b53852dSKent Overstreet 		goto err;
5078b53852dSKent Overstreet 	}
50896385742SKent Overstreet 
50942d23732SKent Overstreet 	if (is_subdir_for_nlink(src_inode_u)) {
51096385742SKent Overstreet 		src_dir_u->bi_nlink--;
51196385742SKent Overstreet 		dst_dir_u->bi_nlink++;
51296385742SKent Overstreet 	}
51396385742SKent Overstreet 
51442d23732SKent Overstreet 	if (dst_inum.inum && is_subdir_for_nlink(dst_inode_u)) {
51596385742SKent Overstreet 		dst_dir_u->bi_nlink--;
51696385742SKent Overstreet 		src_dir_u->bi_nlink += mode == BCH_RENAME_EXCHANGE;
51796385742SKent Overstreet 	}
51896385742SKent Overstreet 
51996385742SKent Overstreet 	if (mode == BCH_RENAME_OVERWRITE)
520962ad1a7SKent Overstreet 		bch2_inode_nlink_dec(trans, dst_inode_u);
52196385742SKent Overstreet 
52296385742SKent Overstreet 	src_dir_u->bi_mtime		= now;
52396385742SKent Overstreet 	src_dir_u->bi_ctime		= now;
52496385742SKent Overstreet 
5256fed42bbSKent Overstreet 	if (src_dir.inum != dst_dir.inum) {
52696385742SKent Overstreet 		dst_dir_u->bi_mtime	= now;
52796385742SKent Overstreet 		dst_dir_u->bi_ctime	= now;
52896385742SKent Overstreet 	}
52996385742SKent Overstreet 
53096385742SKent Overstreet 	src_inode_u->bi_ctime		= now;
53196385742SKent Overstreet 
5326fed42bbSKent Overstreet 	if (dst_inum.inum)
53396385742SKent Overstreet 		dst_inode_u->bi_ctime	= now;
53496385742SKent Overstreet 
53567e0dd8fSKent Overstreet 	ret =   bch2_inode_write(trans, &src_dir_iter, src_dir_u) ?:
5366fed42bbSKent Overstreet 		(src_dir.inum != dst_dir.inum
53767e0dd8fSKent Overstreet 		 ? bch2_inode_write(trans, &dst_dir_iter, dst_dir_u)
53896385742SKent Overstreet 		 : 0) ?:
53967e0dd8fSKent Overstreet 		bch2_inode_write(trans, &src_inode_iter, src_inode_u) ?:
5406fed42bbSKent Overstreet 		(dst_inum.inum
54167e0dd8fSKent Overstreet 		 ? bch2_inode_write(trans, &dst_inode_iter, dst_inode_u)
54296385742SKent Overstreet 		 : 0);
5438b53852dSKent Overstreet err:
54467e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &dst_inode_iter);
54567e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &src_inode_iter);
54667e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &dst_dir_iter);
54767e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &src_dir_iter);
5488b53852dSKent Overstreet 	return ret;
54996385742SKent Overstreet }
550