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