xref: /linux/fs/bcachefs/dirent.c (revision 42b16d3ac371a2fac9b6f08fd75f23f34ba3955a)
11c6fdbd8SKent Overstreet // SPDX-License-Identifier: GPL-2.0
21c6fdbd8SKent Overstreet 
31c6fdbd8SKent Overstreet #include "bcachefs.h"
4462f494bSKent Overstreet #include "bkey_buf.h"
51c6fdbd8SKent Overstreet #include "bkey_methods.h"
61c6fdbd8SKent Overstreet #include "btree_update.h"
71c6fdbd8SKent Overstreet #include "extents.h"
81c6fdbd8SKent Overstreet #include "dirent.h"
91c6fdbd8SKent Overstreet #include "fs.h"
101c6fdbd8SKent Overstreet #include "keylist.h"
111c6fdbd8SKent Overstreet #include "str_hash.h"
126fed42bbSKent Overstreet #include "subvolume.h"
131c6fdbd8SKent Overstreet 
141c6fdbd8SKent Overstreet #include <linux/dcache.h>
151c6fdbd8SKent Overstreet 
bch2_dirent_name_bytes(struct bkey_s_c_dirent d)1601a7e74fSJoshua Ashton static unsigned bch2_dirent_name_bytes(struct bkey_s_c_dirent d)
171c6fdbd8SKent Overstreet {
182195b755SKent Overstreet 	if (bkey_val_bytes(d.k) < offsetof(struct bch_dirent, d_name))
192195b755SKent Overstreet 		return 0;
202195b755SKent Overstreet 
2129c336afSJoshua Ashton 	unsigned bkey_u64s = bkey_val_u64s(d.k);
2229c336afSJoshua Ashton 	unsigned bkey_bytes = bkey_u64s * sizeof(u64);
2329c336afSJoshua Ashton 	u64 last_u64 = ((u64*)d.v)[bkey_u64s - 1];
2429c336afSJoshua Ashton #if CPU_BIG_ENDIAN
2529c336afSJoshua Ashton 	unsigned trailing_nuls = last_u64 ? __builtin_ctzll(last_u64) / 8 : 64 / 8;
2629c336afSJoshua Ashton #else
2729c336afSJoshua Ashton 	unsigned trailing_nuls = last_u64 ? __builtin_clzll(last_u64) / 8 : 64 / 8;
2829c336afSJoshua Ashton #endif
291c6fdbd8SKent Overstreet 
3029c336afSJoshua Ashton 	return bkey_bytes -
3129c336afSJoshua Ashton 		offsetof(struct bch_dirent, d_name) -
3229c336afSJoshua Ashton 		trailing_nuls;
331c6fdbd8SKent Overstreet }
341c6fdbd8SKent Overstreet 
bch2_dirent_get_name(struct bkey_s_c_dirent d)3501a7e74fSJoshua Ashton struct qstr bch2_dirent_get_name(struct bkey_s_c_dirent d)
3601a7e74fSJoshua Ashton {
3701a7e74fSJoshua Ashton 	return (struct qstr) QSTR_INIT(d.v->d_name, bch2_dirent_name_bytes(d));
3801a7e74fSJoshua Ashton }
3901a7e74fSJoshua Ashton 
bch2_dirent_hash(const struct bch_hash_info * info,const struct qstr * name)401c6fdbd8SKent Overstreet static u64 bch2_dirent_hash(const struct bch_hash_info *info,
411c6fdbd8SKent Overstreet 			    const struct qstr *name)
421c6fdbd8SKent Overstreet {
431c6fdbd8SKent Overstreet 	struct bch_str_hash_ctx ctx;
441c6fdbd8SKent Overstreet 
451c6fdbd8SKent Overstreet 	bch2_str_hash_init(&ctx, info);
461c6fdbd8SKent Overstreet 	bch2_str_hash_update(&ctx, info, name->name, name->len);
471c6fdbd8SKent Overstreet 
481c6fdbd8SKent Overstreet 	/* [0,2) reserved for dots */
491c6fdbd8SKent Overstreet 	return max_t(u64, bch2_str_hash_end(&ctx, info), 2);
501c6fdbd8SKent Overstreet }
511c6fdbd8SKent Overstreet 
dirent_hash_key(const struct bch_hash_info * info,const void * key)521c6fdbd8SKent Overstreet static u64 dirent_hash_key(const struct bch_hash_info *info, const void *key)
531c6fdbd8SKent Overstreet {
541c6fdbd8SKent Overstreet 	return bch2_dirent_hash(info, key);
551c6fdbd8SKent Overstreet }
561c6fdbd8SKent Overstreet 
dirent_hash_bkey(const struct bch_hash_info * info,struct bkey_s_c k)571c6fdbd8SKent Overstreet static u64 dirent_hash_bkey(const struct bch_hash_info *info, struct bkey_s_c k)
581c6fdbd8SKent Overstreet {
591c6fdbd8SKent Overstreet 	struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
6001a7e74fSJoshua Ashton 	struct qstr name = bch2_dirent_get_name(d);
611c6fdbd8SKent Overstreet 
621c6fdbd8SKent Overstreet 	return bch2_dirent_hash(info, &name);
631c6fdbd8SKent Overstreet }
641c6fdbd8SKent Overstreet 
dirent_cmp_key(struct bkey_s_c _l,const void * _r)651c6fdbd8SKent Overstreet static bool dirent_cmp_key(struct bkey_s_c _l, const void *_r)
661c6fdbd8SKent Overstreet {
671c6fdbd8SKent Overstreet 	struct bkey_s_c_dirent l = bkey_s_c_to_dirent(_l);
6801a7e74fSJoshua Ashton 	const struct qstr l_name = bch2_dirent_get_name(l);
6901a7e74fSJoshua Ashton 	const struct qstr *r_name = _r;
701c6fdbd8SKent Overstreet 
71038fecc0SKent Overstreet 	return !qstr_eq(l_name, *r_name);
721c6fdbd8SKent Overstreet }
731c6fdbd8SKent Overstreet 
dirent_cmp_bkey(struct bkey_s_c _l,struct bkey_s_c _r)741c6fdbd8SKent Overstreet static bool dirent_cmp_bkey(struct bkey_s_c _l, struct bkey_s_c _r)
751c6fdbd8SKent Overstreet {
761c6fdbd8SKent Overstreet 	struct bkey_s_c_dirent l = bkey_s_c_to_dirent(_l);
771c6fdbd8SKent Overstreet 	struct bkey_s_c_dirent r = bkey_s_c_to_dirent(_r);
7801a7e74fSJoshua Ashton 	const struct qstr l_name = bch2_dirent_get_name(l);
7901a7e74fSJoshua Ashton 	const struct qstr r_name = bch2_dirent_get_name(r);
801c6fdbd8SKent Overstreet 
81038fecc0SKent Overstreet 	return !qstr_eq(l_name, r_name);
821c6fdbd8SKent Overstreet }
831c6fdbd8SKent Overstreet 
dirent_is_visible(subvol_inum inum,struct bkey_s_c k)844db65027SKent Overstreet static bool dirent_is_visible(subvol_inum inum, struct bkey_s_c k)
854db65027SKent Overstreet {
864db65027SKent Overstreet 	struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
874db65027SKent Overstreet 
884db65027SKent Overstreet 	if (d.v->d_type == DT_SUBVOL)
894db65027SKent Overstreet 		return le32_to_cpu(d.v->d_parent_subvol) == inum.subvol;
904db65027SKent Overstreet 	return true;
914db65027SKent Overstreet }
924db65027SKent Overstreet 
931c6fdbd8SKent Overstreet const struct bch_hash_desc bch2_dirent_hash_desc = {
9441f8b09eSKent Overstreet 	.btree_id	= BTREE_ID_dirents,
9526609b61SKent Overstreet 	.key_type	= KEY_TYPE_dirent,
961c6fdbd8SKent Overstreet 	.hash_key	= dirent_hash_key,
971c6fdbd8SKent Overstreet 	.hash_bkey	= dirent_hash_bkey,
981c6fdbd8SKent Overstreet 	.cmp_key	= dirent_cmp_key,
991c6fdbd8SKent Overstreet 	.cmp_bkey	= dirent_cmp_bkey,
1004db65027SKent Overstreet 	.is_visible	= dirent_is_visible,
1011c6fdbd8SKent Overstreet };
1021c6fdbd8SKent Overstreet 
bch2_dirent_validate(struct bch_fs * c,struct bkey_s_c k,enum bch_validate_flags flags)103*d97de0d0SKent Overstreet int bch2_dirent_validate(struct bch_fs *c, struct bkey_s_c k,
104*d97de0d0SKent Overstreet 			 enum bch_validate_flags flags)
1051c6fdbd8SKent Overstreet {
10626609b61SKent Overstreet 	struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
10701a7e74fSJoshua Ashton 	struct qstr d_name = bch2_dirent_get_name(d);
108b65db750SKent Overstreet 	int ret = 0;
1091c6fdbd8SKent Overstreet 
110*d97de0d0SKent Overstreet 	bkey_fsck_err_on(!d_name.len,
111*d97de0d0SKent Overstreet 			 c, dirent_empty_name,
112b65db750SKent Overstreet 			 "empty name");
1131c6fdbd8SKent Overstreet 
114*d97de0d0SKent Overstreet 	bkey_fsck_err_on(bkey_val_u64s(k.k) > dirent_val_u64s(d_name.len),
115*d97de0d0SKent Overstreet 			 c, dirent_val_too_big,
116b65db750SKent Overstreet 			 "value too big (%zu > %u)",
11701a7e74fSJoshua Ashton 			 bkey_val_u64s(k.k), dirent_val_u64s(d_name.len));
1181c6fdbd8SKent Overstreet 
119a125c074SJoshua Ashton 	/*
120a125c074SJoshua Ashton 	 * Check new keys don't exceed the max length
121a125c074SJoshua Ashton 	 * (older keys may be larger.)
122a125c074SJoshua Ashton 	 */
123*d97de0d0SKent Overstreet 	bkey_fsck_err_on((flags & BCH_VALIDATE_commit) && d_name.len > BCH_NAME_MAX,
124*d97de0d0SKent Overstreet 			 c, dirent_name_too_long,
125b65db750SKent Overstreet 			 "dirent name too big (%u > %u)",
12601a7e74fSJoshua Ashton 			 d_name.len, BCH_NAME_MAX);
1271c6fdbd8SKent Overstreet 
128*d97de0d0SKent Overstreet 	bkey_fsck_err_on(d_name.len != strnlen(d_name.name, d_name.len),
129*d97de0d0SKent Overstreet 			 c, dirent_name_embedded_nul,
130b65db750SKent Overstreet 			 "dirent has stray data after name's NUL");
13129c336afSJoshua Ashton 
132b65db750SKent Overstreet 	bkey_fsck_err_on((d_name.len == 1 && !memcmp(d_name.name, ".", 1)) ||
133*d97de0d0SKent Overstreet 			 (d_name.len == 2 && !memcmp(d_name.name, "..", 2)),
134*d97de0d0SKent Overstreet 			 c, dirent_name_dot_or_dotdot,
135b65db750SKent Overstreet 			 "invalid name");
136b6d4f474SKent Overstreet 
137*d97de0d0SKent Overstreet 	bkey_fsck_err_on(memchr(d_name.name, '/', d_name.len),
138*d97de0d0SKent Overstreet 			 c, dirent_name_has_slash,
139b65db750SKent Overstreet 			 "name with /");
140b6d4f474SKent Overstreet 
141b65db750SKent Overstreet 	bkey_fsck_err_on(d.v->d_type != DT_SUBVOL &&
142*d97de0d0SKent Overstreet 			 le64_to_cpu(d.v->d_inum) == d.k->p.inode,
143*d97de0d0SKent Overstreet 			 c, dirent_to_itself,
144b65db750SKent Overstreet 			 "dirent points to own directory");
145b65db750SKent Overstreet fsck_err:
146b65db750SKent Overstreet 	return ret;
1471c6fdbd8SKent Overstreet }
1481c6fdbd8SKent Overstreet 
bch2_dirent_to_text(struct printbuf * out,struct bch_fs * c,struct bkey_s_c k)1493f305e04SKent Overstreet void bch2_dirent_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c k)
1501c6fdbd8SKent Overstreet {
15126609b61SKent Overstreet 	struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
15201a7e74fSJoshua Ashton 	struct qstr d_name = bch2_dirent_get_name(d);
1531c6fdbd8SKent Overstreet 
1543f305e04SKent Overstreet 	prt_printf(out, "%.*s -> ", d_name.len, d_name.name);
1553f305e04SKent Overstreet 
1563f305e04SKent Overstreet 	if (d.v->d_type != DT_SUBVOL)
1573f305e04SKent Overstreet 		prt_printf(out, "%llu", le64_to_cpu(d.v->d_inum));
1583f305e04SKent Overstreet 	else
1593f305e04SKent Overstreet 		prt_printf(out, "%u -> %u",
1603f305e04SKent Overstreet 			   le32_to_cpu(d.v->d_parent_subvol),
1613f305e04SKent Overstreet 			   le32_to_cpu(d.v->d_child_subvol));
1623f305e04SKent Overstreet 
1633f305e04SKent Overstreet 	prt_printf(out, " type %s", bch2_d_type_str(d.v->d_type));
1641c6fdbd8SKent Overstreet }
1651c6fdbd8SKent Overstreet 
dirent_create_key(struct btree_trans * trans,subvol_inum dir,u8 type,const struct qstr * name,u64 dst)1661c6fdbd8SKent Overstreet static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans,
1674db65027SKent Overstreet 				subvol_inum dir, u8 type,
1684db65027SKent Overstreet 				const struct qstr *name, u64 dst)
1691c6fdbd8SKent Overstreet {
1701c6fdbd8SKent Overstreet 	struct bkey_i_dirent *dirent;
1711c6fdbd8SKent Overstreet 	unsigned u64s = BKEY_U64s + dirent_val_u64s(name->len);
1721c6fdbd8SKent Overstreet 
1731c6fdbd8SKent Overstreet 	if (name->len > BCH_NAME_MAX)
1741c6fdbd8SKent Overstreet 		return ERR_PTR(-ENAMETOOLONG);
1751c6fdbd8SKent Overstreet 
1761c6fdbd8SKent Overstreet 	BUG_ON(u64s > U8_MAX);
1771c6fdbd8SKent Overstreet 
1781c6fdbd8SKent Overstreet 	dirent = bch2_trans_kmalloc(trans, u64s * sizeof(u64));
1791c6fdbd8SKent Overstreet 	if (IS_ERR(dirent))
1801c6fdbd8SKent Overstreet 		return dirent;
1811c6fdbd8SKent Overstreet 
1821c6fdbd8SKent Overstreet 	bkey_dirent_init(&dirent->k_i);
1831c6fdbd8SKent Overstreet 	dirent->k.u64s = u64s;
1844db65027SKent Overstreet 
1854db65027SKent Overstreet 	if (type != DT_SUBVOL) {
1861c6fdbd8SKent Overstreet 		dirent->v.d_inum = cpu_to_le64(dst);
1874db65027SKent Overstreet 	} else {
1884db65027SKent Overstreet 		dirent->v.d_parent_subvol = cpu_to_le32(dir.subvol);
1894db65027SKent Overstreet 		dirent->v.d_child_subvol = cpu_to_le32(dst);
1904db65027SKent Overstreet 	}
1914db65027SKent Overstreet 
1921c6fdbd8SKent Overstreet 	dirent->v.d_type = type;
1931c6fdbd8SKent Overstreet 
1941c6fdbd8SKent Overstreet 	memcpy(dirent->v.d_name, name->name, name->len);
1951c6fdbd8SKent Overstreet 	memset(dirent->v.d_name + name->len, 0,
1961c6fdbd8SKent Overstreet 	       bkey_val_bytes(&dirent->k) -
1971c6fdbd8SKent Overstreet 	       offsetof(struct bch_dirent, d_name) -
1981c6fdbd8SKent Overstreet 	       name->len);
1991c6fdbd8SKent Overstreet 
2001c6fdbd8SKent Overstreet 	EBUG_ON(bch2_dirent_name_bytes(dirent_i_to_s_c(dirent)) != name->len);
2011c6fdbd8SKent Overstreet 
2021c6fdbd8SKent Overstreet 	return dirent;
2031c6fdbd8SKent Overstreet }
2041c6fdbd8SKent Overstreet 
bch2_dirent_create_snapshot(struct btree_trans * trans,u32 dir_subvol,u64 dir,u32 snapshot,const struct bch_hash_info * hash_info,u8 type,const struct qstr * name,u64 dst_inum,u64 * dir_offset,enum btree_iter_update_trigger_flags flags)205d296e7b1SKent Overstreet int bch2_dirent_create_snapshot(struct btree_trans *trans,
20656e23047SKent Overstreet 			u32 dir_subvol, u64 dir, u32 snapshot,
207d296e7b1SKent Overstreet 			const struct bch_hash_info *hash_info,
208d296e7b1SKent Overstreet 			u8 type, const struct qstr *name, u64 dst_inum,
209d296e7b1SKent Overstreet 			u64 *dir_offset,
2105dd8c60eSKent Overstreet 			enum btree_iter_update_trigger_flags flags)
211d296e7b1SKent Overstreet {
21256e23047SKent Overstreet 	subvol_inum dir_inum = { .subvol = dir_subvol, .inum = dir };
213d296e7b1SKent Overstreet 	struct bkey_i_dirent *dirent;
214d296e7b1SKent Overstreet 	int ret;
215d296e7b1SKent Overstreet 
21656e23047SKent Overstreet 	dirent = dirent_create_key(trans, dir_inum, type, name, dst_inum);
217d296e7b1SKent Overstreet 	ret = PTR_ERR_OR_ZERO(dirent);
218d296e7b1SKent Overstreet 	if (ret)
219d296e7b1SKent Overstreet 		return ret;
220d296e7b1SKent Overstreet 
221d296e7b1SKent Overstreet 	dirent->k.p.inode	= dir;
222d296e7b1SKent Overstreet 	dirent->k.p.snapshot	= snapshot;
223d296e7b1SKent Overstreet 
22423f25223SKent Overstreet 	ret = bch2_hash_set_in_snapshot(trans, bch2_dirent_hash_desc, hash_info,
2255dd8c60eSKent Overstreet 					dir_inum, snapshot, &dirent->k_i,
2265dd8c60eSKent Overstreet 					flags|BTREE_UPDATE_internal_snapshot_node);
227d296e7b1SKent Overstreet 	*dir_offset = dirent->k.p.offset;
228d296e7b1SKent Overstreet 
229d296e7b1SKent Overstreet 	return ret;
230d296e7b1SKent Overstreet }
231d296e7b1SKent Overstreet 
bch2_dirent_create(struct btree_trans * trans,subvol_inum dir,const struct bch_hash_info * hash_info,u8 type,const struct qstr * name,u64 dst_inum,u64 * dir_offset,enum btree_iter_update_trigger_flags flags)2326fed42bbSKent Overstreet int bch2_dirent_create(struct btree_trans *trans, subvol_inum dir,
2336fed42bbSKent Overstreet 		       const struct bch_hash_info *hash_info,
2341c6fdbd8SKent Overstreet 		       u8 type, const struct qstr *name, u64 dst_inum,
2355927310dSKent Overstreet 		       u64 *dir_offset,
2365dd8c60eSKent Overstreet 		       enum btree_iter_update_trigger_flags flags)
2371c6fdbd8SKent Overstreet {
2381c6fdbd8SKent Overstreet 	struct bkey_i_dirent *dirent;
2391c6fdbd8SKent Overstreet 	int ret;
2401c6fdbd8SKent Overstreet 
2414db65027SKent Overstreet 	dirent = dirent_create_key(trans, dir, type, name, dst_inum);
2421c6fdbd8SKent Overstreet 	ret = PTR_ERR_OR_ZERO(dirent);
2431c6fdbd8SKent Overstreet 	if (ret)
2441c6fdbd8SKent Overstreet 		return ret;
2451c6fdbd8SKent Overstreet 
246ab2a29ccSKent Overstreet 	ret = bch2_hash_set(trans, bch2_dirent_hash_desc, hash_info,
2475dd8c60eSKent Overstreet 			    dir, &dirent->k_i, flags);
248ab2a29ccSKent Overstreet 	*dir_offset = dirent->k.p.offset;
249ab2a29ccSKent Overstreet 
250ab2a29ccSKent Overstreet 	return ret;
2511c6fdbd8SKent Overstreet }
2521c6fdbd8SKent Overstreet 
dirent_copy_target(struct bkey_i_dirent * dst,struct bkey_s_c_dirent src)2531c6fdbd8SKent Overstreet static void dirent_copy_target(struct bkey_i_dirent *dst,
2541c6fdbd8SKent Overstreet 			       struct bkey_s_c_dirent src)
2551c6fdbd8SKent Overstreet {
2561c6fdbd8SKent Overstreet 	dst->v.d_inum = src.v->d_inum;
2571c6fdbd8SKent Overstreet 	dst->v.d_type = src.v->d_type;
2581c6fdbd8SKent Overstreet }
2591c6fdbd8SKent Overstreet 
bch2_dirent_read_target(struct btree_trans * trans,subvol_inum dir,struct bkey_s_c_dirent d,subvol_inum * target)26085e95ca7SKent Overstreet int bch2_dirent_read_target(struct btree_trans *trans, subvol_inum dir,
2614db65027SKent Overstreet 			    struct bkey_s_c_dirent d, subvol_inum *target)
262b9e1adf5SKent Overstreet {
263bd547c8aSKent Overstreet 	struct bch_subvolume s;
264b9e1adf5SKent Overstreet 	int ret = 0;
265b9e1adf5SKent Overstreet 
2664db65027SKent Overstreet 	if (d.v->d_type == DT_SUBVOL &&
26773bd774dSKent Overstreet 	    le32_to_cpu(d.v->d_parent_subvol) != dir.subvol)
2684db65027SKent Overstreet 		return 1;
269b9e1adf5SKent Overstreet 
270b9e1adf5SKent Overstreet 	if (likely(d.v->d_type != DT_SUBVOL)) {
2716fed42bbSKent Overstreet 		target->subvol	= dir.subvol;
2724db65027SKent Overstreet 		target->inum	= le64_to_cpu(d.v->d_inum);
2734db65027SKent Overstreet 	} else {
2744db65027SKent Overstreet 		target->subvol	= le32_to_cpu(d.v->d_child_subvol);
2754db65027SKent Overstreet 
2765dd8c60eSKent Overstreet 		ret = bch2_subvolume_get(trans, target->subvol, true, BTREE_ITER_cached, &s);
2774db65027SKent Overstreet 
2784db65027SKent Overstreet 		target->inum	= le64_to_cpu(s.inode);
2794db65027SKent Overstreet 	}
2806fed42bbSKent Overstreet 
2816fed42bbSKent Overstreet 	return ret;
282b9e1adf5SKent Overstreet }
283b9e1adf5SKent Overstreet 
bch2_dirent_rename(struct btree_trans * trans,subvol_inum src_dir,struct bch_hash_info * src_hash,subvol_inum dst_dir,struct bch_hash_info * dst_hash,const struct qstr * src_name,subvol_inum * src_inum,u64 * src_offset,const struct qstr * dst_name,subvol_inum * dst_inum,u64 * dst_offset,enum bch_rename_mode mode)2841c6fdbd8SKent Overstreet int bch2_dirent_rename(struct btree_trans *trans,
2856fed42bbSKent Overstreet 		subvol_inum src_dir, struct bch_hash_info *src_hash,
2866fed42bbSKent Overstreet 		subvol_inum dst_dir, struct bch_hash_info *dst_hash,
2876fed42bbSKent Overstreet 		const struct qstr *src_name, subvol_inum *src_inum, u64 *src_offset,
2886fed42bbSKent Overstreet 		const struct qstr *dst_name, subvol_inum *dst_inum, u64 *dst_offset,
2891c6fdbd8SKent Overstreet 		enum bch_rename_mode mode)
2901c6fdbd8SKent Overstreet {
29167e0dd8fSKent Overstreet 	struct btree_iter src_iter = { NULL };
29267e0dd8fSKent Overstreet 	struct btree_iter dst_iter = { NULL };
2932a863c6cSKent Overstreet 	struct bkey_s_c old_src, old_dst = bkey_s_c_null;
2941c6fdbd8SKent Overstreet 	struct bkey_i_dirent *new_src = NULL, *new_dst = NULL;
29596385742SKent Overstreet 	struct bpos dst_pos =
2966fed42bbSKent Overstreet 		POS(dst_dir.inum, bch2_dirent_hash(dst_hash, dst_name));
2977f76b08aSKent Overstreet 	unsigned src_update_flags = 0;
2987f76b08aSKent Overstreet 	bool delete_src, delete_dst;
299163e885aSKent Overstreet 	int ret = 0;
3001c6fdbd8SKent Overstreet 
3016fed42bbSKent Overstreet 	memset(src_inum, 0, sizeof(*src_inum));
3026fed42bbSKent Overstreet 	memset(dst_inum, 0, sizeof(*dst_inum));
30396385742SKent Overstreet 
3041c6fdbd8SKent Overstreet 	/* Lookup src: */
305ac01928bSKent Overstreet 	old_src = bch2_hash_lookup(trans, &src_iter, bch2_dirent_hash_desc,
30696385742SKent Overstreet 				   src_hash, src_dir, src_name,
3075dd8c60eSKent Overstreet 				   BTREE_ITER_intent);
3088b3e9bd6SKent Overstreet 	ret = bkey_err(old_src);
3098b3e9bd6SKent Overstreet 	if (ret)
3108b3e9bd6SKent Overstreet 		goto out;
3118b3e9bd6SKent Overstreet 
3126fed42bbSKent Overstreet 	ret = bch2_dirent_read_target(trans, src_dir,
3136fed42bbSKent Overstreet 			bkey_s_c_to_dirent(old_src), src_inum);
3146fed42bbSKent Overstreet 	if (ret)
3156fed42bbSKent Overstreet 		goto out;
3161c6fdbd8SKent Overstreet 
3174db65027SKent Overstreet 	/* Lookup dst: */
3184db65027SKent Overstreet 	if (mode == BCH_RENAME) {
3194db65027SKent Overstreet 		/*
3204db65027SKent Overstreet 		 * Note that we're _not_ checking if the target already exists -
3214db65027SKent Overstreet 		 * we're relying on the VFS to do that check for us for
3224db65027SKent Overstreet 		 * correctness:
3234db65027SKent Overstreet 		 */
3244db65027SKent Overstreet 		ret = bch2_hash_hole(trans, &dst_iter, bch2_dirent_hash_desc,
3254db65027SKent Overstreet 				     dst_hash, dst_dir, dst_name);
3264db65027SKent Overstreet 		if (ret)
3274db65027SKent Overstreet 			goto out;
3284db65027SKent Overstreet 	} else {
329ac01928bSKent Overstreet 		old_dst = bch2_hash_lookup(trans, &dst_iter, bch2_dirent_hash_desc,
3304db65027SKent Overstreet 					    dst_hash, dst_dir, dst_name,
3315dd8c60eSKent Overstreet 					    BTREE_ITER_intent);
3324db65027SKent Overstreet 		ret = bkey_err(old_dst);
3334db65027SKent Overstreet 		if (ret)
3344db65027SKent Overstreet 			goto out;
3354db65027SKent Overstreet 
3364db65027SKent Overstreet 		ret = bch2_dirent_read_target(trans, dst_dir,
3374db65027SKent Overstreet 				bkey_s_c_to_dirent(old_dst), dst_inum);
3384db65027SKent Overstreet 		if (ret)
3394db65027SKent Overstreet 			goto out;
3404db65027SKent Overstreet 	}
3414db65027SKent Overstreet 
3424db65027SKent Overstreet 	if (mode != BCH_RENAME_EXCHANGE)
3434db65027SKent Overstreet 		*src_offset = dst_iter.pos.offset;
3444db65027SKent Overstreet 
3451c6fdbd8SKent Overstreet 	/* Create new dst key: */
3464db65027SKent Overstreet 	new_dst = dirent_create_key(trans, dst_dir, 0, dst_name, 0);
347163e885aSKent Overstreet 	ret = PTR_ERR_OR_ZERO(new_dst);
348163e885aSKent Overstreet 	if (ret)
349163e885aSKent Overstreet 		goto out;
3501c6fdbd8SKent Overstreet 
3511c6fdbd8SKent Overstreet 	dirent_copy_target(new_dst, bkey_s_c_to_dirent(old_src));
35267e0dd8fSKent Overstreet 	new_dst->k.p = dst_iter.pos;
3531c6fdbd8SKent Overstreet 
3541c6fdbd8SKent Overstreet 	/* Create new src key: */
3551c6fdbd8SKent Overstreet 	if (mode == BCH_RENAME_EXCHANGE) {
3564db65027SKent Overstreet 		new_src = dirent_create_key(trans, src_dir, 0, src_name, 0);
357163e885aSKent Overstreet 		ret = PTR_ERR_OR_ZERO(new_src);
358163e885aSKent Overstreet 		if (ret)
359163e885aSKent Overstreet 			goto out;
3601c6fdbd8SKent Overstreet 
3611c6fdbd8SKent Overstreet 		dirent_copy_target(new_src, bkey_s_c_to_dirent(old_dst));
36267e0dd8fSKent Overstreet 		new_src->k.p = src_iter.pos;
3631c6fdbd8SKent Overstreet 	} else {
3641c6fdbd8SKent Overstreet 		new_src = bch2_trans_kmalloc(trans, sizeof(struct bkey_i));
365163e885aSKent Overstreet 		ret = PTR_ERR_OR_ZERO(new_src);
366163e885aSKent Overstreet 		if (ret)
367163e885aSKent Overstreet 			goto out;
368163e885aSKent Overstreet 
3691c6fdbd8SKent Overstreet 		bkey_init(&new_src->k);
37067e0dd8fSKent Overstreet 		new_src->k.p = src_iter.pos;
3711c6fdbd8SKent Overstreet 
372e88a75ebSKent Overstreet 		if (bkey_le(dst_pos, src_iter.pos) &&
373e88a75ebSKent Overstreet 		    bkey_lt(src_iter.pos, dst_iter.pos)) {
3741c6fdbd8SKent Overstreet 			/*
3751c6fdbd8SKent Overstreet 			 * We have a hash collision for the new dst key,
3761c6fdbd8SKent Overstreet 			 * and new_src - the key we're deleting - is between
3771c6fdbd8SKent Overstreet 			 * new_dst's hashed slot and the slot we're going to be
3781c6fdbd8SKent Overstreet 			 * inserting it into - oops.  This will break the hash
3791c6fdbd8SKent Overstreet 			 * table if we don't deal with it:
3801c6fdbd8SKent Overstreet 			 */
3811c6fdbd8SKent Overstreet 			if (mode == BCH_RENAME) {
3821c6fdbd8SKent Overstreet 				/*
3831c6fdbd8SKent Overstreet 				 * If we're not overwriting, we can just insert
3841c6fdbd8SKent Overstreet 				 * new_dst at the src position:
3851c6fdbd8SKent Overstreet 				 */
3864db65027SKent Overstreet 				new_src = new_dst;
3874db65027SKent Overstreet 				new_src->k.p = src_iter.pos;
3884db65027SKent Overstreet 				goto out_set_src;
3891c6fdbd8SKent Overstreet 			} else {
3901c6fdbd8SKent Overstreet 				/* If we're overwriting, we can't insert new_dst
3911c6fdbd8SKent Overstreet 				 * at a different slot because it has to
3921c6fdbd8SKent Overstreet 				 * overwrite old_dst - just make sure to use a
3931c6fdbd8SKent Overstreet 				 * whiteout when deleting src:
3941c6fdbd8SKent Overstreet 				 */
39579f88ebaSKent Overstreet 				new_src->k.type = KEY_TYPE_hash_whiteout;
3961c6fdbd8SKent Overstreet 			}
3971c6fdbd8SKent Overstreet 		} else {
3981c6fdbd8SKent Overstreet 			/* Check if we need a whiteout to delete src: */
3991c6fdbd8SKent Overstreet 			ret = bch2_hash_needs_whiteout(trans, bch2_dirent_hash_desc,
40067e0dd8fSKent Overstreet 						       src_hash, &src_iter);
4011c6fdbd8SKent Overstreet 			if (ret < 0)
402163e885aSKent Overstreet 				goto out;
4031c6fdbd8SKent Overstreet 
4041c6fdbd8SKent Overstreet 			if (ret)
40579f88ebaSKent Overstreet 				new_src->k.type = KEY_TYPE_hash_whiteout;
4061c6fdbd8SKent Overstreet 		}
4071c6fdbd8SKent Overstreet 	}
4081c6fdbd8SKent Overstreet 
4097f76b08aSKent Overstreet 	if (new_dst->v.d_type == DT_SUBVOL)
4107f76b08aSKent Overstreet 		new_dst->v.d_parent_subvol = cpu_to_le32(dst_dir.subvol);
4117f76b08aSKent Overstreet 
4127f76b08aSKent Overstreet 	if ((mode == BCH_RENAME_EXCHANGE) &&
4137f76b08aSKent Overstreet 	    new_src->v.d_type == DT_SUBVOL)
4147f76b08aSKent Overstreet 		new_src->v.d_parent_subvol = cpu_to_le32(src_dir.subvol);
4157f76b08aSKent Overstreet 
41694a3e1a6SKent Overstreet 	ret = bch2_trans_update(trans, &dst_iter, &new_dst->k_i, 0);
41794a3e1a6SKent Overstreet 	if (ret)
41894a3e1a6SKent Overstreet 		goto out;
4194db65027SKent Overstreet out_set_src:
4204db65027SKent Overstreet 	/*
4217f76b08aSKent Overstreet 	 * If we're deleting a subvolume we need to really delete the dirent,
4227f76b08aSKent Overstreet 	 * not just emit a whiteout in the current snapshot - there can only be
4237f76b08aSKent Overstreet 	 * single dirent that points to a given subvolume.
4247f76b08aSKent Overstreet 	 *
4257f76b08aSKent Overstreet 	 * IOW, we don't maintain multiple versions in different snapshots of
4267f76b08aSKent Overstreet 	 * dirents that point to subvolumes - dirents that point to subvolumes
4277f76b08aSKent Overstreet 	 * are only visible in one particular subvolume so it's not necessary,
4287f76b08aSKent Overstreet 	 * and it would be particularly confusing for fsck to have to deal with.
4294db65027SKent Overstreet 	 */
4307f76b08aSKent Overstreet 	delete_src = bkey_s_c_to_dirent(old_src).v->d_type == DT_SUBVOL &&
4317f76b08aSKent Overstreet 		new_src->k.p.snapshot != old_src.k->p.snapshot;
4324db65027SKent Overstreet 
4337f76b08aSKent Overstreet 	delete_dst = old_dst.k &&
4347f76b08aSKent Overstreet 		bkey_s_c_to_dirent(old_dst).v->d_type == DT_SUBVOL &&
4357f76b08aSKent Overstreet 		new_dst->k.p.snapshot != old_dst.k->p.snapshot;
4364db65027SKent Overstreet 
4377f76b08aSKent Overstreet 	if (!delete_src || !bkey_deleted(&new_src->k)) {
43894a3e1a6SKent Overstreet 		ret = bch2_trans_update(trans, &src_iter, &new_src->k_i, src_update_flags);
43994a3e1a6SKent Overstreet 		if (ret)
44094a3e1a6SKent Overstreet 			goto out;
4417f76b08aSKent Overstreet 	}
4427f76b08aSKent Overstreet 
4437f76b08aSKent Overstreet 	if (delete_src) {
4447f76b08aSKent Overstreet 		bch2_btree_iter_set_snapshot(&src_iter, old_src.k->p.snapshot);
4457f76b08aSKent Overstreet 		ret =   bch2_btree_iter_traverse(&src_iter) ?:
4465dd8c60eSKent Overstreet 			bch2_btree_delete_at(trans, &src_iter, BTREE_UPDATE_internal_snapshot_node);
4477f76b08aSKent Overstreet 		if (ret)
4487f76b08aSKent Overstreet 			goto out;
4497f76b08aSKent Overstreet 	}
4507f76b08aSKent Overstreet 
4517f76b08aSKent Overstreet 	if (delete_dst) {
4527f76b08aSKent Overstreet 		bch2_btree_iter_set_snapshot(&dst_iter, old_dst.k->p.snapshot);
4537f76b08aSKent Overstreet 		ret =   bch2_btree_iter_traverse(&dst_iter) ?:
4545dd8c60eSKent Overstreet 			bch2_btree_delete_at(trans, &dst_iter, BTREE_UPDATE_internal_snapshot_node);
4557f76b08aSKent Overstreet 		if (ret)
4567f76b08aSKent Overstreet 			goto out;
4577f76b08aSKent Overstreet 	}
4584db65027SKent Overstreet 
45916ac8c95SKent Overstreet 	if (mode == BCH_RENAME_EXCHANGE)
460ab2a29ccSKent Overstreet 		*src_offset = new_src->k.p.offset;
461ab2a29ccSKent Overstreet 	*dst_offset = new_dst->k.p.offset;
462163e885aSKent Overstreet out:
46367e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &src_iter);
46467e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &dst_iter);
465163e885aSKent Overstreet 	return ret;
4661c6fdbd8SKent Overstreet }
4671c6fdbd8SKent Overstreet 
bch2_dirent_lookup_trans(struct btree_trans * trans,struct btree_iter * iter,subvol_inum dir,const struct bch_hash_info * hash_info,const struct qstr * name,subvol_inum * inum,unsigned flags)4685b6271b5SKent Overstreet int bch2_dirent_lookup_trans(struct btree_trans *trans,
46967e0dd8fSKent Overstreet 			     struct btree_iter *iter,
4706fed42bbSKent Overstreet 			     subvol_inum dir,
47196385742SKent Overstreet 			     const struct bch_hash_info *hash_info,
4726fed42bbSKent Overstreet 			     const struct qstr *name, subvol_inum *inum,
473b9e1adf5SKent Overstreet 			     unsigned flags)
47496385742SKent Overstreet {
475ac01928bSKent Overstreet 	struct bkey_s_c k = bch2_hash_lookup(trans, iter, bch2_dirent_hash_desc,
4766fed42bbSKent Overstreet 					     hash_info, dir, name, flags);
477ac01928bSKent Overstreet 	int ret = bkey_err(k);
478496b7238SKent Overstreet 	if (ret)
479496b7238SKent Overstreet 		goto err;
480b9e1adf5SKent Overstreet 
4815b6271b5SKent Overstreet 	ret = bch2_dirent_read_target(trans, dir, bkey_s_c_to_dirent(k), inum);
4824db65027SKent Overstreet 	if (ret > 0)
4834db65027SKent Overstreet 		ret = -ENOENT;
484496b7238SKent Overstreet err:
485b9e1adf5SKent Overstreet 	if (ret)
486b9e1adf5SKent Overstreet 		bch2_trans_iter_exit(trans, iter);
487b9e1adf5SKent Overstreet 	return ret;
4881c6fdbd8SKent Overstreet }
4891c6fdbd8SKent Overstreet 
bch2_dirent_lookup(struct bch_fs * c,subvol_inum dir,const struct bch_hash_info * hash_info,const struct qstr * name,subvol_inum * inum)4906fed42bbSKent Overstreet u64 bch2_dirent_lookup(struct bch_fs *c, subvol_inum dir,
4911c6fdbd8SKent Overstreet 		       const struct bch_hash_info *hash_info,
4926fed42bbSKent Overstreet 		       const struct qstr *name, subvol_inum *inum)
4931c6fdbd8SKent Overstreet {
4946bd68ec2SKent Overstreet 	struct btree_trans *trans = bch2_trans_get(c);
495c8ef2dc2SKent Overstreet 	struct btree_iter iter = { NULL };
4966fed42bbSKent Overstreet 
497c8ef2dc2SKent Overstreet 	int ret = lockrestart_do(trans,
4985b6271b5SKent Overstreet 		bch2_dirent_lookup_trans(trans, &iter, dir, hash_info, name, inum, 0));
4996bd68ec2SKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
5006bd68ec2SKent Overstreet 	bch2_trans_put(trans);
5016fed42bbSKent Overstreet 	return ret;
5021c6fdbd8SKent Overstreet }
5031c6fdbd8SKent Overstreet 
bch2_empty_dir_snapshot(struct btree_trans * trans,u64 dir,u32 subvol,u32 snapshot)5040be5b38bSGuoyu Ou int bch2_empty_dir_snapshot(struct btree_trans *trans, u64 dir, u32 subvol, u32 snapshot)
5051c6fdbd8SKent Overstreet {
50667e0dd8fSKent Overstreet 	struct btree_iter iter;
5071c6fdbd8SKent Overstreet 	struct bkey_s_c k;
50894f651e2SKent Overstreet 	int ret;
5091c6fdbd8SKent Overstreet 
51085d8cf16SKent Overstreet 	for_each_btree_key_upto_norestart(trans, iter, BTREE_ID_dirents,
5116d1980f0SKent Overstreet 			   SPOS(dir, 0, snapshot),
5126d1980f0SKent Overstreet 			   POS(dir, U64_MAX), 0, k, ret)
51326609b61SKent Overstreet 		if (k.k->type == KEY_TYPE_dirent) {
5140be5b38bSGuoyu Ou 			struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
5150be5b38bSGuoyu Ou 			if (d.v->d_type == DT_SUBVOL && le32_to_cpu(d.v->d_parent_subvol) != subvol)
5160be5b38bSGuoyu Ou 				continue;
517835cd3e1SKent Overstreet 			ret = -BCH_ERR_ENOTEMPTY_dir_not_empty;
5181c6fdbd8SKent Overstreet 			break;
5191c6fdbd8SKent Overstreet 		}
52067e0dd8fSKent Overstreet 	bch2_trans_iter_exit(trans, &iter);
5211c6fdbd8SKent Overstreet 
5221c6fdbd8SKent Overstreet 	return ret;
5231c6fdbd8SKent Overstreet }
5241c6fdbd8SKent Overstreet 
bch2_empty_dir_trans(struct btree_trans * trans,subvol_inum dir)5256d1980f0SKent Overstreet int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir)
5266d1980f0SKent Overstreet {
5276d1980f0SKent Overstreet 	u32 snapshot;
5286d1980f0SKent Overstreet 
5296d1980f0SKent Overstreet 	return bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot) ?:
5300be5b38bSGuoyu Ou 		bch2_empty_dir_snapshot(trans, dir.inum, dir.subvol, snapshot);
5316d1980f0SKent Overstreet }
5326d1980f0SKent Overstreet 
bch2_dir_emit(struct dir_context * ctx,struct bkey_s_c_dirent d,subvol_inum target)5330c0cbfdbSKent Overstreet static int bch2_dir_emit(struct dir_context *ctx, struct bkey_s_c_dirent d, subvol_inum target)
5340c0cbfdbSKent Overstreet {
5350c0cbfdbSKent Overstreet 	struct qstr name = bch2_dirent_get_name(d);
536f8b01473SAriel Miculas 	/*
537f8b01473SAriel Miculas 	 * Although not required by the kernel code, updating ctx->pos is needed
538f8b01473SAriel Miculas 	 * for the bcachefs FUSE driver. Without this update, the FUSE
539f8b01473SAriel Miculas 	 * implementation will be stuck in an infinite loop when reading
540f8b01473SAriel Miculas 	 * directories (via the bcachefs_fuse_readdir callback).
541f8b01473SAriel Miculas 	 * In kernel space, ctx->pos is updated by the VFS code.
542f8b01473SAriel Miculas 	 */
543f8b01473SAriel Miculas 	ctx->pos = d.k->p.offset;
5440c0cbfdbSKent Overstreet 	bool ret = dir_emit(ctx, name.name,
5450c0cbfdbSKent Overstreet 		      name.len,
5460c0cbfdbSKent Overstreet 		      target.inum,
5470c0cbfdbSKent Overstreet 		      vfs_d_type(d.v->d_type));
5480c0cbfdbSKent Overstreet 	if (ret)
5490c0cbfdbSKent Overstreet 		ctx->pos = d.k->p.offset + 1;
5500c0cbfdbSKent Overstreet 	return ret;
5510c0cbfdbSKent Overstreet }
5520c0cbfdbSKent Overstreet 
bch2_readdir(struct bch_fs * c,subvol_inum inum,struct dir_context * ctx)5536fed42bbSKent Overstreet int bch2_readdir(struct bch_fs *c, subvol_inum inum, struct dir_context *ctx)
5546bd13057SKent Overstreet {
5556bd68ec2SKent Overstreet 	struct bkey_buf sk;
55667e0dd8fSKent Overstreet 	bch2_bkey_buf_init(&sk);
5571c6fdbd8SKent Overstreet 
5584db65027SKent Overstreet 	int ret = bch2_trans_run(c,
5596fed42bbSKent Overstreet 		for_each_btree_key_in_subvolume_upto(trans, iter, BTREE_ID_dirents,
560462f494bSKent Overstreet 				   POS(inum.inum, ctx->pos),
56194f651e2SKent Overstreet 				   POS(inum.inum, U64_MAX),
5621c6fdbd8SKent Overstreet 				   inum.subvol, 0, k, ({
563462f494bSKent Overstreet 			if (k.k->type != KEY_TYPE_dirent)
5646fed42bbSKent Overstreet 				continue;
5656bd68ec2SKent Overstreet 
5666fed42bbSKent Overstreet 			/* dir_emit() can fault and block: */
5676bd68ec2SKent Overstreet 			bch2_bkey_buf_reassemble(&sk, c, k);
5686fed42bbSKent Overstreet 			struct bkey_s_c_dirent dirent = bkey_i_to_s_c_dirent(sk.k);
5696fed42bbSKent Overstreet 
570424eb881SKent Overstreet 			subvol_inum target;
5716bd68ec2SKent Overstreet 			int ret2 = bch2_dirent_read_target(trans, inum, dirent, &target);
57285d8cf16SKent Overstreet 			if (ret2 > 0)
57385d8cf16SKent Overstreet 				continue;
57426609b61SKent Overstreet 
5751c6fdbd8SKent Overstreet 			ret2 ?: drop_locks_do(trans, bch2_dir_emit(ctx, dirent, target));
5761c6fdbd8SKent Overstreet 		})));
5770c0cbfdbSKent Overstreet 
5780c0cbfdbSKent Overstreet 	bch2_bkey_buf_exit(&sk, c);
5790c0cbfdbSKent Overstreet 
5801c6fdbd8SKent Overstreet 	return ret < 0 ? ret : 0;
5816bd68ec2SKent Overstreet }
5824db65027SKent Overstreet