~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/bcachefs/dirent.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 
  3 #include "bcachefs.h"
  4 #include "bkey_buf.h"
  5 #include "bkey_methods.h"
  6 #include "btree_update.h"
  7 #include "extents.h"
  8 #include "dirent.h"
  9 #include "fs.h"
 10 #include "keylist.h"
 11 #include "str_hash.h"
 12 #include "subvolume.h"
 13 
 14 #include <linux/dcache.h>
 15 
 16 static unsigned bch2_dirent_name_bytes(struct bkey_s_c_dirent d)
 17 {
 18         if (bkey_val_bytes(d.k) < offsetof(struct bch_dirent, d_name))
 19                 return 0;
 20 
 21         unsigned bkey_u64s = bkey_val_u64s(d.k);
 22         unsigned bkey_bytes = bkey_u64s * sizeof(u64);
 23         u64 last_u64 = ((u64*)d.v)[bkey_u64s - 1];
 24 #if CPU_BIG_ENDIAN
 25         unsigned trailing_nuls = last_u64 ? __builtin_ctzll(last_u64) / 8 : 64 / 8;
 26 #else
 27         unsigned trailing_nuls = last_u64 ? __builtin_clzll(last_u64) / 8 : 64 / 8;
 28 #endif
 29 
 30         return bkey_bytes -
 31                 offsetof(struct bch_dirent, d_name) -
 32                 trailing_nuls;
 33 }
 34 
 35 struct qstr bch2_dirent_get_name(struct bkey_s_c_dirent d)
 36 {
 37         return (struct qstr) QSTR_INIT(d.v->d_name, bch2_dirent_name_bytes(d));
 38 }
 39 
 40 static u64 bch2_dirent_hash(const struct bch_hash_info *info,
 41                             const struct qstr *name)
 42 {
 43         struct bch_str_hash_ctx ctx;
 44 
 45         bch2_str_hash_init(&ctx, info);
 46         bch2_str_hash_update(&ctx, info, name->name, name->len);
 47 
 48         /* [0,2) reserved for dots */
 49         return max_t(u64, bch2_str_hash_end(&ctx, info), 2);
 50 }
 51 
 52 static u64 dirent_hash_key(const struct bch_hash_info *info, const void *key)
 53 {
 54         return bch2_dirent_hash(info, key);
 55 }
 56 
 57 static u64 dirent_hash_bkey(const struct bch_hash_info *info, struct bkey_s_c k)
 58 {
 59         struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
 60         struct qstr name = bch2_dirent_get_name(d);
 61 
 62         return bch2_dirent_hash(info, &name);
 63 }
 64 
 65 static bool dirent_cmp_key(struct bkey_s_c _l, const void *_r)
 66 {
 67         struct bkey_s_c_dirent l = bkey_s_c_to_dirent(_l);
 68         const struct qstr l_name = bch2_dirent_get_name(l);
 69         const struct qstr *r_name = _r;
 70 
 71         return !qstr_eq(l_name, *r_name);
 72 }
 73 
 74 static bool dirent_cmp_bkey(struct bkey_s_c _l, struct bkey_s_c _r)
 75 {
 76         struct bkey_s_c_dirent l = bkey_s_c_to_dirent(_l);
 77         struct bkey_s_c_dirent r = bkey_s_c_to_dirent(_r);
 78         const struct qstr l_name = bch2_dirent_get_name(l);
 79         const struct qstr r_name = bch2_dirent_get_name(r);
 80 
 81         return !qstr_eq(l_name, r_name);
 82 }
 83 
 84 static bool dirent_is_visible(subvol_inum inum, struct bkey_s_c k)
 85 {
 86         struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
 87 
 88         if (d.v->d_type == DT_SUBVOL)
 89                 return le32_to_cpu(d.v->d_parent_subvol) == inum.subvol;
 90         return true;
 91 }
 92 
 93 const struct bch_hash_desc bch2_dirent_hash_desc = {
 94         .btree_id       = BTREE_ID_dirents,
 95         .key_type       = KEY_TYPE_dirent,
 96         .hash_key       = dirent_hash_key,
 97         .hash_bkey      = dirent_hash_bkey,
 98         .cmp_key        = dirent_cmp_key,
 99         .cmp_bkey       = dirent_cmp_bkey,
100         .is_visible     = dirent_is_visible,
101 };
102 
103 int bch2_dirent_validate(struct bch_fs *c, struct bkey_s_c k,
104                          enum bch_validate_flags flags)
105 {
106         struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
107         struct qstr d_name = bch2_dirent_get_name(d);
108         int ret = 0;
109 
110         bkey_fsck_err_on(!d_name.len,
111                          c, dirent_empty_name,
112                          "empty name");
113 
114         bkey_fsck_err_on(bkey_val_u64s(k.k) > dirent_val_u64s(d_name.len),
115                          c, dirent_val_too_big,
116                          "value too big (%zu > %u)",
117                          bkey_val_u64s(k.k), dirent_val_u64s(d_name.len));
118 
119         /*
120          * Check new keys don't exceed the max length
121          * (older keys may be larger.)
122          */
123         bkey_fsck_err_on((flags & BCH_VALIDATE_commit) && d_name.len > BCH_NAME_MAX,
124                          c, dirent_name_too_long,
125                          "dirent name too big (%u > %u)",
126                          d_name.len, BCH_NAME_MAX);
127 
128         bkey_fsck_err_on(d_name.len != strnlen(d_name.name, d_name.len),
129                          c, dirent_name_embedded_nul,
130                          "dirent has stray data after name's NUL");
131 
132         bkey_fsck_err_on((d_name.len == 1 && !memcmp(d_name.name, ".", 1)) ||
133                          (d_name.len == 2 && !memcmp(d_name.name, "..", 2)),
134                          c, dirent_name_dot_or_dotdot,
135                          "invalid name");
136 
137         bkey_fsck_err_on(memchr(d_name.name, '/', d_name.len),
138                          c, dirent_name_has_slash,
139                          "name with /");
140 
141         bkey_fsck_err_on(d.v->d_type != DT_SUBVOL &&
142                          le64_to_cpu(d.v->d_inum) == d.k->p.inode,
143                          c, dirent_to_itself,
144                          "dirent points to own directory");
145 fsck_err:
146         return ret;
147 }
148 
149 void bch2_dirent_to_text(struct printbuf *out, struct bch_fs *c, struct bkey_s_c k)
150 {
151         struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
152         struct qstr d_name = bch2_dirent_get_name(d);
153 
154         prt_printf(out, "%.*s -> ", d_name.len, d_name.name);
155 
156         if (d.v->d_type != DT_SUBVOL)
157                 prt_printf(out, "%llu", le64_to_cpu(d.v->d_inum));
158         else
159                 prt_printf(out, "%u -> %u",
160                            le32_to_cpu(d.v->d_parent_subvol),
161                            le32_to_cpu(d.v->d_child_subvol));
162 
163         prt_printf(out, " type %s", bch2_d_type_str(d.v->d_type));
164 }
165 
166 static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans,
167                                 subvol_inum dir, u8 type,
168                                 const struct qstr *name, u64 dst)
169 {
170         struct bkey_i_dirent *dirent;
171         unsigned u64s = BKEY_U64s + dirent_val_u64s(name->len);
172 
173         if (name->len > BCH_NAME_MAX)
174                 return ERR_PTR(-ENAMETOOLONG);
175 
176         BUG_ON(u64s > U8_MAX);
177 
178         dirent = bch2_trans_kmalloc(trans, u64s * sizeof(u64));
179         if (IS_ERR(dirent))
180                 return dirent;
181 
182         bkey_dirent_init(&dirent->k_i);
183         dirent->k.u64s = u64s;
184 
185         if (type != DT_SUBVOL) {
186                 dirent->v.d_inum = cpu_to_le64(dst);
187         } else {
188                 dirent->v.d_parent_subvol = cpu_to_le32(dir.subvol);
189                 dirent->v.d_child_subvol = cpu_to_le32(dst);
190         }
191 
192         dirent->v.d_type = type;
193 
194         memcpy(dirent->v.d_name, name->name, name->len);
195         memset(dirent->v.d_name + name->len, 0,
196                bkey_val_bytes(&dirent->k) -
197                offsetof(struct bch_dirent, d_name) -
198                name->len);
199 
200         EBUG_ON(bch2_dirent_name_bytes(dirent_i_to_s_c(dirent)) != name->len);
201 
202         return dirent;
203 }
204 
205 int bch2_dirent_create_snapshot(struct btree_trans *trans,
206                         u32 dir_subvol, u64 dir, u32 snapshot,
207                         const struct bch_hash_info *hash_info,
208                         u8 type, const struct qstr *name, u64 dst_inum,
209                         u64 *dir_offset,
210                         enum btree_iter_update_trigger_flags flags)
211 {
212         subvol_inum dir_inum = { .subvol = dir_subvol, .inum = dir };
213         struct bkey_i_dirent *dirent;
214         int ret;
215 
216         dirent = dirent_create_key(trans, dir_inum, type, name, dst_inum);
217         ret = PTR_ERR_OR_ZERO(dirent);
218         if (ret)
219                 return ret;
220 
221         dirent->k.p.inode       = dir;
222         dirent->k.p.snapshot    = snapshot;
223 
224         ret = bch2_hash_set_in_snapshot(trans, bch2_dirent_hash_desc, hash_info,
225                                         dir_inum, snapshot, &dirent->k_i,
226                                         flags|BTREE_UPDATE_internal_snapshot_node);
227         *dir_offset = dirent->k.p.offset;
228 
229         return ret;
230 }
231 
232 int bch2_dirent_create(struct btree_trans *trans, subvol_inum dir,
233                        const struct bch_hash_info *hash_info,
234                        u8 type, const struct qstr *name, u64 dst_inum,
235                        u64 *dir_offset,
236                        enum btree_iter_update_trigger_flags flags)
237 {
238         struct bkey_i_dirent *dirent;
239         int ret;
240 
241         dirent = dirent_create_key(trans, dir, type, name, dst_inum);
242         ret = PTR_ERR_OR_ZERO(dirent);
243         if (ret)
244                 return ret;
245 
246         ret = bch2_hash_set(trans, bch2_dirent_hash_desc, hash_info,
247                             dir, &dirent->k_i, flags);
248         *dir_offset = dirent->k.p.offset;
249 
250         return ret;
251 }
252 
253 static void dirent_copy_target(struct bkey_i_dirent *dst,
254                                struct bkey_s_c_dirent src)
255 {
256         dst->v.d_inum = src.v->d_inum;
257         dst->v.d_type = src.v->d_type;
258 }
259 
260 int bch2_dirent_read_target(struct btree_trans *trans, subvol_inum dir,
261                             struct bkey_s_c_dirent d, subvol_inum *target)
262 {
263         struct bch_subvolume s;
264         int ret = 0;
265 
266         if (d.v->d_type == DT_SUBVOL &&
267             le32_to_cpu(d.v->d_parent_subvol) != dir.subvol)
268                 return 1;
269 
270         if (likely(d.v->d_type != DT_SUBVOL)) {
271                 target->subvol  = dir.subvol;
272                 target->inum    = le64_to_cpu(d.v->d_inum);
273         } else {
274                 target->subvol  = le32_to_cpu(d.v->d_child_subvol);
275 
276                 ret = bch2_subvolume_get(trans, target->subvol, true, BTREE_ITER_cached, &s);
277 
278                 target->inum    = le64_to_cpu(s.inode);
279         }
280 
281         return ret;
282 }
283 
284 int bch2_dirent_rename(struct btree_trans *trans,
285                 subvol_inum src_dir, struct bch_hash_info *src_hash,
286                 subvol_inum dst_dir, struct bch_hash_info *dst_hash,
287                 const struct qstr *src_name, subvol_inum *src_inum, u64 *src_offset,
288                 const struct qstr *dst_name, subvol_inum *dst_inum, u64 *dst_offset,
289                 enum bch_rename_mode mode)
290 {
291         struct btree_iter src_iter = { NULL };
292         struct btree_iter dst_iter = { NULL };
293         struct bkey_s_c old_src, old_dst = bkey_s_c_null;
294         struct bkey_i_dirent *new_src = NULL, *new_dst = NULL;
295         struct bpos dst_pos =
296                 POS(dst_dir.inum, bch2_dirent_hash(dst_hash, dst_name));
297         unsigned src_update_flags = 0;
298         bool delete_src, delete_dst;
299         int ret = 0;
300 
301         memset(src_inum, 0, sizeof(*src_inum));
302         memset(dst_inum, 0, sizeof(*dst_inum));
303 
304         /* Lookup src: */
305         old_src = bch2_hash_lookup(trans, &src_iter, bch2_dirent_hash_desc,
306                                    src_hash, src_dir, src_name,
307                                    BTREE_ITER_intent);
308         ret = bkey_err(old_src);
309         if (ret)
310                 goto out;
311 
312         ret = bch2_dirent_read_target(trans, src_dir,
313                         bkey_s_c_to_dirent(old_src), src_inum);
314         if (ret)
315                 goto out;
316 
317         /* Lookup dst: */
318         if (mode == BCH_RENAME) {
319                 /*
320                  * Note that we're _not_ checking if the target already exists -
321                  * we're relying on the VFS to do that check for us for
322                  * correctness:
323                  */
324                 ret = bch2_hash_hole(trans, &dst_iter, bch2_dirent_hash_desc,
325                                      dst_hash, dst_dir, dst_name);
326                 if (ret)
327                         goto out;
328         } else {
329                 old_dst = bch2_hash_lookup(trans, &dst_iter, bch2_dirent_hash_desc,
330                                             dst_hash, dst_dir, dst_name,
331                                             BTREE_ITER_intent);
332                 ret = bkey_err(old_dst);
333                 if (ret)
334                         goto out;
335 
336                 ret = bch2_dirent_read_target(trans, dst_dir,
337                                 bkey_s_c_to_dirent(old_dst), dst_inum);
338                 if (ret)
339                         goto out;
340         }
341 
342         if (mode != BCH_RENAME_EXCHANGE)
343                 *src_offset = dst_iter.pos.offset;
344 
345         /* Create new dst key: */
346         new_dst = dirent_create_key(trans, dst_dir, 0, dst_name, 0);
347         ret = PTR_ERR_OR_ZERO(new_dst);
348         if (ret)
349                 goto out;
350 
351         dirent_copy_target(new_dst, bkey_s_c_to_dirent(old_src));
352         new_dst->k.p = dst_iter.pos;
353 
354         /* Create new src key: */
355         if (mode == BCH_RENAME_EXCHANGE) {
356                 new_src = dirent_create_key(trans, src_dir, 0, src_name, 0);
357                 ret = PTR_ERR_OR_ZERO(new_src);
358                 if (ret)
359                         goto out;
360 
361                 dirent_copy_target(new_src, bkey_s_c_to_dirent(old_dst));
362                 new_src->k.p = src_iter.pos;
363         } else {
364                 new_src = bch2_trans_kmalloc(trans, sizeof(struct bkey_i));
365                 ret = PTR_ERR_OR_ZERO(new_src);
366                 if (ret)
367                         goto out;
368 
369                 bkey_init(&new_src->k);
370                 new_src->k.p = src_iter.pos;
371 
372                 if (bkey_le(dst_pos, src_iter.pos) &&
373                     bkey_lt(src_iter.pos, dst_iter.pos)) {
374                         /*
375                          * We have a hash collision for the new dst key,
376                          * and new_src - the key we're deleting - is between
377                          * new_dst's hashed slot and the slot we're going to be
378                          * inserting it into - oops.  This will break the hash
379                          * table if we don't deal with it:
380                          */
381                         if (mode == BCH_RENAME) {
382                                 /*
383                                  * If we're not overwriting, we can just insert
384                                  * new_dst at the src position:
385                                  */
386                                 new_src = new_dst;
387                                 new_src->k.p = src_iter.pos;
388                                 goto out_set_src;
389                         } else {
390                                 /* If we're overwriting, we can't insert new_dst
391                                  * at a different slot because it has to
392                                  * overwrite old_dst - just make sure to use a
393                                  * whiteout when deleting src:
394                                  */
395                                 new_src->k.type = KEY_TYPE_hash_whiteout;
396                         }
397                 } else {
398                         /* Check if we need a whiteout to delete src: */
399                         ret = bch2_hash_needs_whiteout(trans, bch2_dirent_hash_desc,
400                                                        src_hash, &src_iter);
401                         if (ret < 0)
402                                 goto out;
403 
404                         if (ret)
405                                 new_src->k.type = KEY_TYPE_hash_whiteout;
406                 }
407         }
408 
409         if (new_dst->v.d_type == DT_SUBVOL)
410                 new_dst->v.d_parent_subvol = cpu_to_le32(dst_dir.subvol);
411 
412         if ((mode == BCH_RENAME_EXCHANGE) &&
413             new_src->v.d_type == DT_SUBVOL)
414                 new_src->v.d_parent_subvol = cpu_to_le32(src_dir.subvol);
415 
416         ret = bch2_trans_update(trans, &dst_iter, &new_dst->k_i, 0);
417         if (ret)
418                 goto out;
419 out_set_src:
420         /*
421          * If we're deleting a subvolume we need to really delete the dirent,
422          * not just emit a whiteout in the current snapshot - there can only be
423          * single dirent that points to a given subvolume.
424          *
425          * IOW, we don't maintain multiple versions in different snapshots of
426          * dirents that point to subvolumes - dirents that point to subvolumes
427          * are only visible in one particular subvolume so it's not necessary,
428          * and it would be particularly confusing for fsck to have to deal with.
429          */
430         delete_src = bkey_s_c_to_dirent(old_src).v->d_type == DT_SUBVOL &&
431                 new_src->k.p.snapshot != old_src.k->p.snapshot;
432 
433         delete_dst = old_dst.k &&
434                 bkey_s_c_to_dirent(old_dst).v->d_type == DT_SUBVOL &&
435                 new_dst->k.p.snapshot != old_dst.k->p.snapshot;
436 
437         if (!delete_src || !bkey_deleted(&new_src->k)) {
438                 ret = bch2_trans_update(trans, &src_iter, &new_src->k_i, src_update_flags);
439                 if (ret)
440                         goto out;
441         }
442 
443         if (delete_src) {
444                 bch2_btree_iter_set_snapshot(&src_iter, old_src.k->p.snapshot);
445                 ret =   bch2_btree_iter_traverse(&src_iter) ?:
446                         bch2_btree_delete_at(trans, &src_iter, BTREE_UPDATE_internal_snapshot_node);
447                 if (ret)
448                         goto out;
449         }
450 
451         if (delete_dst) {
452                 bch2_btree_iter_set_snapshot(&dst_iter, old_dst.k->p.snapshot);
453                 ret =   bch2_btree_iter_traverse(&dst_iter) ?:
454                         bch2_btree_delete_at(trans, &dst_iter, BTREE_UPDATE_internal_snapshot_node);
455                 if (ret)
456                         goto out;
457         }
458 
459         if (mode == BCH_RENAME_EXCHANGE)
460                 *src_offset = new_src->k.p.offset;
461         *dst_offset = new_dst->k.p.offset;
462 out:
463         bch2_trans_iter_exit(trans, &src_iter);
464         bch2_trans_iter_exit(trans, &dst_iter);
465         return ret;
466 }
467 
468 int bch2_dirent_lookup_trans(struct btree_trans *trans,
469                              struct btree_iter *iter,
470                              subvol_inum dir,
471                              const struct bch_hash_info *hash_info,
472                              const struct qstr *name, subvol_inum *inum,
473                              unsigned flags)
474 {
475         struct bkey_s_c k = bch2_hash_lookup(trans, iter, bch2_dirent_hash_desc,
476                                              hash_info, dir, name, flags);
477         int ret = bkey_err(k);
478         if (ret)
479                 goto err;
480 
481         ret = bch2_dirent_read_target(trans, dir, bkey_s_c_to_dirent(k), inum);
482         if (ret > 0)
483                 ret = -ENOENT;
484 err:
485         if (ret)
486                 bch2_trans_iter_exit(trans, iter);
487         return ret;
488 }
489 
490 u64 bch2_dirent_lookup(struct bch_fs *c, subvol_inum dir,
491                        const struct bch_hash_info *hash_info,
492                        const struct qstr *name, subvol_inum *inum)
493 {
494         struct btree_trans *trans = bch2_trans_get(c);
495         struct btree_iter iter = { NULL };
496 
497         int ret = lockrestart_do(trans,
498                 bch2_dirent_lookup_trans(trans, &iter, dir, hash_info, name, inum, 0));
499         bch2_trans_iter_exit(trans, &iter);
500         bch2_trans_put(trans);
501         return ret;
502 }
503 
504 int bch2_empty_dir_snapshot(struct btree_trans *trans, u64 dir, u32 subvol, u32 snapshot)
505 {
506         struct btree_iter iter;
507         struct bkey_s_c k;
508         int ret;
509 
510         for_each_btree_key_upto_norestart(trans, iter, BTREE_ID_dirents,
511                            SPOS(dir, 0, snapshot),
512                            POS(dir, U64_MAX), 0, k, ret)
513                 if (k.k->type == KEY_TYPE_dirent) {
514                         struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
515                         if (d.v->d_type == DT_SUBVOL && le32_to_cpu(d.v->d_parent_subvol) != subvol)
516                                 continue;
517                         ret = -BCH_ERR_ENOTEMPTY_dir_not_empty;
518                         break;
519                 }
520         bch2_trans_iter_exit(trans, &iter);
521 
522         return ret;
523 }
524 
525 int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir)
526 {
527         u32 snapshot;
528 
529         return bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot) ?:
530                 bch2_empty_dir_snapshot(trans, dir.inum, dir.subvol, snapshot);
531 }
532 
533 static int bch2_dir_emit(struct dir_context *ctx, struct bkey_s_c_dirent d, subvol_inum target)
534 {
535         struct qstr name = bch2_dirent_get_name(d);
536         /*
537          * Although not required by the kernel code, updating ctx->pos is needed
538          * for the bcachefs FUSE driver. Without this update, the FUSE
539          * implementation will be stuck in an infinite loop when reading
540          * directories (via the bcachefs_fuse_readdir callback).
541          * In kernel space, ctx->pos is updated by the VFS code.
542          */
543         ctx->pos = d.k->p.offset;
544         bool ret = dir_emit(ctx, name.name,
545                       name.len,
546                       target.inum,
547                       vfs_d_type(d.v->d_type));
548         if (ret)
549                 ctx->pos = d.k->p.offset + 1;
550         return ret;
551 }
552 
553 int bch2_readdir(struct bch_fs *c, subvol_inum inum, struct dir_context *ctx)
554 {
555         struct btree_trans *trans = bch2_trans_get(c);
556         struct btree_iter iter;
557         struct bkey_s_c k;
558         subvol_inum target;
559         u32 snapshot;
560         struct bkey_buf sk;
561         int ret;
562 
563         bch2_bkey_buf_init(&sk);
564 retry:
565         bch2_trans_begin(trans);
566 
567         ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
568         if (ret)
569                 goto err;
570 
571         for_each_btree_key_upto_norestart(trans, iter, BTREE_ID_dirents,
572                            SPOS(inum.inum, ctx->pos, snapshot),
573                            POS(inum.inum, U64_MAX), 0, k, ret) {
574                 if (k.k->type != KEY_TYPE_dirent)
575                         continue;
576 
577                 /* dir_emit() can fault and block: */
578                 bch2_bkey_buf_reassemble(&sk, c, k);
579                 struct bkey_s_c_dirent dirent = bkey_i_to_s_c_dirent(sk.k);
580 
581                 ret = bch2_dirent_read_target(trans, inum, dirent, &target);
582                 if (ret < 0)
583                         break;
584                 if (ret)
585                         continue;
586 
587                 /*
588                  * read_target looks up subvolumes, we can overflow paths if the
589                  * directory has many subvolumes in it
590                  *
591                  * XXX: btree_trans_too_many_iters() is something we'd like to
592                  * get rid of, and there's no good reason to be using it here
593                  * except that we don't yet have a for_each_btree_key() helper
594                  * that does subvolume_get_snapshot().
595                  */
596                 ret =   drop_locks_do(trans,
597                                 bch2_dir_emit(ctx, dirent, target)) ?:
598                         btree_trans_too_many_iters(trans);
599                 if (ret) {
600                         ret = ret < 0 ? ret : 0;
601                         break;
602                 }
603         }
604         bch2_trans_iter_exit(trans, &iter);
605 err:
606         if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
607                 goto retry;
608 
609         bch2_trans_put(trans);
610         bch2_bkey_buf_exit(&sk, c);
611 
612         return ret;
613 }
614 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php