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