]> git.sesse.net Git - bcachefs-tools-debian/blob - libbcachefs/dirent.c
610dd7425fb477e2ff9cf0fba1b7f5abd4a50181
[bcachefs-tools-debian] / libbcachefs / dirent.c
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 unsigned bch2_dirent_name_bytes(struct bkey_s_c_dirent d)
17 {
18         unsigned len = bkey_val_bytes(d.k) -
19                 offsetof(struct bch_dirent, d_name);
20
21         return strnlen(d.v->d_name, len);
22 }
23
24 static u64 bch2_dirent_hash(const struct bch_hash_info *info,
25                             const struct qstr *name)
26 {
27         struct bch_str_hash_ctx ctx;
28
29         bch2_str_hash_init(&ctx, info);
30         bch2_str_hash_update(&ctx, info, name->name, name->len);
31
32         /* [0,2) reserved for dots */
33         return max_t(u64, bch2_str_hash_end(&ctx, info), 2);
34 }
35
36 static u64 dirent_hash_key(const struct bch_hash_info *info, const void *key)
37 {
38         return bch2_dirent_hash(info, key);
39 }
40
41 static u64 dirent_hash_bkey(const struct bch_hash_info *info, struct bkey_s_c k)
42 {
43         struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
44         struct qstr name = QSTR_INIT(d.v->d_name, bch2_dirent_name_bytes(d));
45
46         return bch2_dirent_hash(info, &name);
47 }
48
49 static bool dirent_cmp_key(struct bkey_s_c _l, const void *_r)
50 {
51         struct bkey_s_c_dirent l = bkey_s_c_to_dirent(_l);
52         int len = bch2_dirent_name_bytes(l);
53         const struct qstr *r = _r;
54
55         return len - r->len ?: memcmp(l.v->d_name, r->name, len);
56 }
57
58 static bool dirent_cmp_bkey(struct bkey_s_c _l, struct bkey_s_c _r)
59 {
60         struct bkey_s_c_dirent l = bkey_s_c_to_dirent(_l);
61         struct bkey_s_c_dirent r = bkey_s_c_to_dirent(_r);
62         int l_len = bch2_dirent_name_bytes(l);
63         int r_len = bch2_dirent_name_bytes(r);
64
65         return l_len - r_len ?: memcmp(l.v->d_name, r.v->d_name, l_len);
66 }
67
68 static bool dirent_is_visible(subvol_inum inum, struct bkey_s_c k)
69 {
70         struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
71
72         if (d.v->d_type == DT_SUBVOL)
73                 return le32_to_cpu(d.v->d_parent_subvol) == inum.subvol;
74         return true;
75 }
76
77 const struct bch_hash_desc bch2_dirent_hash_desc = {
78         .btree_id       = BTREE_ID_dirents,
79         .key_type       = KEY_TYPE_dirent,
80         .hash_key       = dirent_hash_key,
81         .hash_bkey      = dirent_hash_bkey,
82         .cmp_key        = dirent_cmp_key,
83         .cmp_bkey       = dirent_cmp_bkey,
84         .is_visible     = dirent_is_visible,
85 };
86
87 int bch2_dirent_invalid(const struct bch_fs *c, struct bkey_s_c k,
88                         unsigned flags, struct printbuf *err)
89 {
90         struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
91         unsigned len;
92
93         len = bch2_dirent_name_bytes(d);
94         if (!len) {
95                 prt_printf(err, "empty name");
96                 return -BCH_ERR_invalid_bkey;
97         }
98
99         if (bkey_val_u64s(k.k) > dirent_val_u64s(len)) {
100                 prt_printf(err, "value too big (%zu > %u)",
101                        bkey_val_u64s(k.k), dirent_val_u64s(len));
102                 return -BCH_ERR_invalid_bkey;
103         }
104
105         if (len > BCH_NAME_MAX) {
106                 prt_printf(err, "dirent name too big (%u > %u)",
107                        len, BCH_NAME_MAX);
108                 return -BCH_ERR_invalid_bkey;
109         }
110
111         if (len == 1 && !memcmp(d.v->d_name, ".", 1)) {
112                 prt_printf(err, "invalid name");
113                 return -BCH_ERR_invalid_bkey;
114         }
115
116         if (len == 2 && !memcmp(d.v->d_name, "..", 2)) {
117                 prt_printf(err, "invalid name");
118                 return -BCH_ERR_invalid_bkey;
119         }
120
121         if (memchr(d.v->d_name, '/', len)) {
122                 prt_printf(err, "invalid name");
123                 return -BCH_ERR_invalid_bkey;
124         }
125
126         if (d.v->d_type != DT_SUBVOL &&
127             le64_to_cpu(d.v->d_inum) == d.k->p.inode) {
128                 prt_printf(err, "dirent points to own directory");
129                 return -BCH_ERR_invalid_bkey;
130         }
131
132         return 0;
133 }
134
135 void bch2_dirent_to_text(struct printbuf *out, struct bch_fs *c,
136                          struct bkey_s_c k)
137 {
138         struct bkey_s_c_dirent d = bkey_s_c_to_dirent(k);
139
140         prt_printf(out, "%.*s -> %llu type %s",
141                bch2_dirent_name_bytes(d),
142                d.v->d_name,
143                d.v->d_type != DT_SUBVOL
144                ? le64_to_cpu(d.v->d_inum)
145                : le32_to_cpu(d.v->d_child_subvol),
146                bch2_d_type_str(d.v->d_type));
147 }
148
149 static struct bkey_i_dirent *dirent_create_key(struct btree_trans *trans,
150                                 subvol_inum dir, u8 type,
151                                 const struct qstr *name, u64 dst)
152 {
153         struct bkey_i_dirent *dirent;
154         unsigned u64s = BKEY_U64s + dirent_val_u64s(name->len);
155
156         if (name->len > BCH_NAME_MAX)
157                 return ERR_PTR(-ENAMETOOLONG);
158
159         BUG_ON(u64s > U8_MAX);
160
161         dirent = bch2_trans_kmalloc(trans, u64s * sizeof(u64));
162         if (IS_ERR(dirent))
163                 return dirent;
164
165         bkey_dirent_init(&dirent->k_i);
166         dirent->k.u64s = u64s;
167
168         if (type != DT_SUBVOL) {
169                 dirent->v.d_inum = cpu_to_le64(dst);
170         } else {
171                 dirent->v.d_parent_subvol = cpu_to_le32(dir.subvol);
172                 dirent->v.d_child_subvol = cpu_to_le32(dst);
173         }
174
175         dirent->v.d_type = type;
176
177         memcpy(dirent->v.d_name, name->name, name->len);
178         memset(dirent->v.d_name + name->len, 0,
179                bkey_val_bytes(&dirent->k) -
180                offsetof(struct bch_dirent, d_name) -
181                name->len);
182
183         EBUG_ON(bch2_dirent_name_bytes(dirent_i_to_s_c(dirent)) != name->len);
184
185         return dirent;
186 }
187
188 int bch2_dirent_create(struct btree_trans *trans, subvol_inum dir,
189                        const struct bch_hash_info *hash_info,
190                        u8 type, const struct qstr *name, u64 dst_inum,
191                        u64 *dir_offset, int flags)
192 {
193         struct bkey_i_dirent *dirent;
194         int ret;
195
196         dirent = dirent_create_key(trans, dir, type, name, dst_inum);
197         ret = PTR_ERR_OR_ZERO(dirent);
198         if (ret)
199                 return ret;
200
201         ret = bch2_hash_set(trans, bch2_dirent_hash_desc, hash_info,
202                             dir, &dirent->k_i, flags);
203         *dir_offset = dirent->k.p.offset;
204
205         return ret;
206 }
207
208 static void dirent_copy_target(struct bkey_i_dirent *dst,
209                                struct bkey_s_c_dirent src)
210 {
211         dst->v.d_inum = src.v->d_inum;
212         dst->v.d_type = src.v->d_type;
213 }
214
215 int bch2_dirent_read_target(struct btree_trans *trans, subvol_inum dir,
216                             struct bkey_s_c_dirent d, subvol_inum *target)
217 {
218         struct bch_subvolume s;
219         int ret = 0;
220
221         if (d.v->d_type == DT_SUBVOL &&
222             d.v->d_parent_subvol != dir.subvol)
223                 return 1;
224
225         if (likely(d.v->d_type != DT_SUBVOL)) {
226                 target->subvol  = dir.subvol;
227                 target->inum    = le64_to_cpu(d.v->d_inum);
228         } else {
229                 target->subvol  = le32_to_cpu(d.v->d_child_subvol);
230
231                 ret = bch2_subvolume_get(trans, target->subvol, true, BTREE_ITER_CACHED, &s);
232
233                 target->inum    = le64_to_cpu(s.inode);
234         }
235
236         return ret;
237 }
238
239 int bch2_dirent_rename(struct btree_trans *trans,
240                 subvol_inum src_dir, struct bch_hash_info *src_hash,
241                 subvol_inum dst_dir, struct bch_hash_info *dst_hash,
242                 const struct qstr *src_name, subvol_inum *src_inum, u64 *src_offset,
243                 const struct qstr *dst_name, subvol_inum *dst_inum, u64 *dst_offset,
244                 enum bch_rename_mode mode)
245 {
246         struct btree_iter src_iter = { NULL };
247         struct btree_iter dst_iter = { NULL };
248         struct bkey_s_c old_src, old_dst = bkey_s_c_null;
249         struct bkey_i_dirent *new_src = NULL, *new_dst = NULL;
250         struct bpos dst_pos =
251                 POS(dst_dir.inum, bch2_dirent_hash(dst_hash, dst_name));
252         unsigned src_type = 0, dst_type = 0, src_update_flags = 0;
253         int ret = 0;
254
255         if (src_dir.subvol != dst_dir.subvol)
256                 return -EXDEV;
257
258         memset(src_inum, 0, sizeof(*src_inum));
259         memset(dst_inum, 0, sizeof(*dst_inum));
260
261         /* Lookup src: */
262         ret = bch2_hash_lookup(trans, &src_iter, bch2_dirent_hash_desc,
263                                src_hash, src_dir, src_name,
264                                BTREE_ITER_INTENT);
265         if (ret)
266                 goto out;
267
268         old_src = bch2_btree_iter_peek_slot(&src_iter);
269         ret = bkey_err(old_src);
270         if (ret)
271                 goto out;
272
273         ret = bch2_dirent_read_target(trans, src_dir,
274                         bkey_s_c_to_dirent(old_src), src_inum);
275         if (ret)
276                 goto out;
277
278         src_type = bkey_s_c_to_dirent(old_src).v->d_type;
279
280         if (src_type == DT_SUBVOL && mode == BCH_RENAME_EXCHANGE)
281                 return -EOPNOTSUPP;
282
283
284         /* Lookup dst: */
285         if (mode == BCH_RENAME) {
286                 /*
287                  * Note that we're _not_ checking if the target already exists -
288                  * we're relying on the VFS to do that check for us for
289                  * correctness:
290                  */
291                 ret = bch2_hash_hole(trans, &dst_iter, bch2_dirent_hash_desc,
292                                      dst_hash, dst_dir, dst_name);
293                 if (ret)
294                         goto out;
295         } else {
296                 ret = bch2_hash_lookup(trans, &dst_iter, bch2_dirent_hash_desc,
297                                        dst_hash, dst_dir, dst_name,
298                                        BTREE_ITER_INTENT);
299                 if (ret)
300                         goto out;
301
302                 old_dst = bch2_btree_iter_peek_slot(&dst_iter);
303                 ret = bkey_err(old_dst);
304                 if (ret)
305                         goto out;
306
307                 ret = bch2_dirent_read_target(trans, dst_dir,
308                                 bkey_s_c_to_dirent(old_dst), dst_inum);
309                 if (ret)
310                         goto out;
311
312                 dst_type = bkey_s_c_to_dirent(old_dst).v->d_type;
313
314                 if (dst_type == DT_SUBVOL)
315                         return -EOPNOTSUPP;
316         }
317
318         if (mode != BCH_RENAME_EXCHANGE)
319                 *src_offset = dst_iter.pos.offset;
320
321         /* Create new dst key: */
322         new_dst = dirent_create_key(trans, dst_dir, 0, dst_name, 0);
323         ret = PTR_ERR_OR_ZERO(new_dst);
324         if (ret)
325                 goto out;
326
327         dirent_copy_target(new_dst, bkey_s_c_to_dirent(old_src));
328         new_dst->k.p = dst_iter.pos;
329
330         /* Create new src key: */
331         if (mode == BCH_RENAME_EXCHANGE) {
332                 new_src = dirent_create_key(trans, src_dir, 0, src_name, 0);
333                 ret = PTR_ERR_OR_ZERO(new_src);
334                 if (ret)
335                         goto out;
336
337                 dirent_copy_target(new_src, bkey_s_c_to_dirent(old_dst));
338                 new_src->k.p = src_iter.pos;
339         } else {
340                 new_src = bch2_trans_kmalloc(trans, sizeof(struct bkey_i));
341                 ret = PTR_ERR_OR_ZERO(new_src);
342                 if (ret)
343                         goto out;
344
345                 bkey_init(&new_src->k);
346                 new_src->k.p = src_iter.pos;
347
348                 if (bkey_le(dst_pos, src_iter.pos) &&
349                     bkey_lt(src_iter.pos, dst_iter.pos)) {
350                         /*
351                          * We have a hash collision for the new dst key,
352                          * and new_src - the key we're deleting - is between
353                          * new_dst's hashed slot and the slot we're going to be
354                          * inserting it into - oops.  This will break the hash
355                          * table if we don't deal with it:
356                          */
357                         if (mode == BCH_RENAME) {
358                                 /*
359                                  * If we're not overwriting, we can just insert
360                                  * new_dst at the src position:
361                                  */
362                                 new_src = new_dst;
363                                 new_src->k.p = src_iter.pos;
364                                 goto out_set_src;
365                         } else {
366                                 /* If we're overwriting, we can't insert new_dst
367                                  * at a different slot because it has to
368                                  * overwrite old_dst - just make sure to use a
369                                  * whiteout when deleting src:
370                                  */
371                                 new_src->k.type = KEY_TYPE_hash_whiteout;
372                         }
373                 } else {
374                         /* Check if we need a whiteout to delete src: */
375                         ret = bch2_hash_needs_whiteout(trans, bch2_dirent_hash_desc,
376                                                        src_hash, &src_iter);
377                         if (ret < 0)
378                                 goto out;
379
380                         if (ret)
381                                 new_src->k.type = KEY_TYPE_hash_whiteout;
382                 }
383         }
384
385         ret = bch2_trans_update(trans, &dst_iter, &new_dst->k_i, 0);
386         if (ret)
387                 goto out;
388 out_set_src:
389
390         /*
391          * If we're deleting a subvolume, we need to really delete the dirent,
392          * not just emit a whiteout in the current snapshot:
393          */
394         if (src_type == DT_SUBVOL) {
395                 bch2_btree_iter_set_snapshot(&src_iter, old_src.k->p.snapshot);
396                 ret = bch2_btree_iter_traverse(&src_iter);
397                 if (ret)
398                         goto out;
399
400                 new_src->k.p = src_iter.pos;
401                 src_update_flags |= BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE;
402         }
403
404         ret = bch2_trans_update(trans, &src_iter, &new_src->k_i, src_update_flags);
405         if (ret)
406                 goto out;
407
408         if (mode == BCH_RENAME_EXCHANGE)
409                 *src_offset = new_src->k.p.offset;
410         *dst_offset = new_dst->k.p.offset;
411 out:
412         bch2_trans_iter_exit(trans, &src_iter);
413         bch2_trans_iter_exit(trans, &dst_iter);
414         return ret;
415 }
416
417 int __bch2_dirent_lookup_trans(struct btree_trans *trans,
418                                struct btree_iter *iter,
419                                subvol_inum dir,
420                                const struct bch_hash_info *hash_info,
421                                const struct qstr *name, subvol_inum *inum,
422                                unsigned flags)
423 {
424         struct bkey_s_c k;
425         struct bkey_s_c_dirent d;
426         u32 snapshot;
427         int ret;
428
429         ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot);
430         if (ret)
431                 return ret;
432
433         ret = bch2_hash_lookup(trans, iter, bch2_dirent_hash_desc,
434                                hash_info, dir, name, flags);
435         if (ret)
436                 return ret;
437
438         k = bch2_btree_iter_peek_slot(iter);
439         ret = bkey_err(k);
440         if (ret)
441                 goto err;
442
443         d = bkey_s_c_to_dirent(k);
444
445         ret = bch2_dirent_read_target(trans, dir, d, inum);
446         if (ret > 0)
447                 ret = -ENOENT;
448 err:
449         if (ret)
450                 bch2_trans_iter_exit(trans, iter);
451
452         return ret;
453 }
454
455 u64 bch2_dirent_lookup(struct bch_fs *c, subvol_inum dir,
456                        const struct bch_hash_info *hash_info,
457                        const struct qstr *name, subvol_inum *inum)
458 {
459         struct btree_trans trans;
460         struct btree_iter iter;
461         int ret;
462
463         bch2_trans_init(&trans, c, 0, 0);
464 retry:
465         bch2_trans_begin(&trans);
466
467         ret = __bch2_dirent_lookup_trans(&trans, &iter, dir, hash_info,
468                                           name, inum, 0);
469         if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
470                 goto retry;
471         if (!ret)
472                 bch2_trans_iter_exit(&trans, &iter);
473         bch2_trans_exit(&trans);
474         return ret;
475 }
476
477 int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir)
478 {
479         struct btree_iter iter;
480         struct bkey_s_c k;
481         u32 snapshot;
482         int ret;
483
484         ret = bch2_subvolume_get_snapshot(trans, dir.subvol, &snapshot);
485         if (ret)
486                 return ret;
487
488         for_each_btree_key_upto_norestart(trans, iter, BTREE_ID_dirents,
489                            SPOS(dir.inum, 0, snapshot),
490                            POS(dir.inum, U64_MAX), 0, k, ret)
491                 if (k.k->type == KEY_TYPE_dirent) {
492                         ret = -ENOTEMPTY;
493                         break;
494                 }
495         bch2_trans_iter_exit(trans, &iter);
496
497         return ret;
498 }
499
500 int bch2_readdir(struct bch_fs *c, subvol_inum inum, struct dir_context *ctx)
501 {
502         struct btree_trans trans;
503         struct btree_iter iter;
504         struct bkey_s_c k;
505         struct bkey_s_c_dirent dirent;
506         subvol_inum target;
507         u32 snapshot;
508         struct bkey_buf sk;
509         int ret;
510
511         bch2_bkey_buf_init(&sk);
512         bch2_trans_init(&trans, c, 0, 0);
513 retry:
514         bch2_trans_begin(&trans);
515
516         ret = bch2_subvolume_get_snapshot(&trans, inum.subvol, &snapshot);
517         if (ret)
518                 goto err;
519
520         for_each_btree_key_upto_norestart(&trans, iter, BTREE_ID_dirents,
521                            SPOS(inum.inum, ctx->pos, snapshot),
522                            POS(inum.inum, U64_MAX), 0, k, ret) {
523                 if (k.k->type != KEY_TYPE_dirent)
524                         continue;
525
526                 dirent = bkey_s_c_to_dirent(k);
527
528                 ret = bch2_dirent_read_target(&trans, inum, dirent, &target);
529                 if (ret < 0)
530                         break;
531                 if (ret)
532                         continue;
533
534                 /* dir_emit() can fault and block: */
535                 bch2_bkey_buf_reassemble(&sk, c, k);
536                 dirent = bkey_i_to_s_c_dirent(sk.k);
537                 bch2_trans_unlock(&trans);
538
539                 ctx->pos = dirent.k->p.offset;
540                 if (!dir_emit(ctx, dirent.v->d_name,
541                               bch2_dirent_name_bytes(dirent),
542                               target.inum,
543                               vfs_d_type(dirent.v->d_type)))
544                         break;
545                 ctx->pos = dirent.k->p.offset + 1;
546
547                 /*
548                  * read_target looks up subvolumes, we can overflow paths if the
549                  * directory has many subvolumes in it
550                  */
551                 ret = btree_trans_too_many_iters(&trans);
552                 if (ret)
553                         break;
554         }
555         bch2_trans_iter_exit(&trans, &iter);
556 err:
557         if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
558                 goto retry;
559
560         bch2_trans_exit(&trans);
561         bch2_bkey_buf_exit(&sk, c);
562
563         return ret;
564 }