bcachefs: Lookup/create lost+found lazily
authorKent Overstreet <kent.overstreet@gmail.com>
Tue, 20 Apr 2021 02:19:18 +0000 (22:19 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:01 +0000 (17:09 -0400)
This is prep work for subvolumes - each subvolume will have its own
lost+found.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/fsck.c

index cfe6063420329db5a48533ca275db740dac9facf..1ce038846476d80f1727f3e97615b55acf56742e 100644 (file)
@@ -38,9 +38,9 @@ static s64 bch2_count_inode_sectors(struct btree_trans *trans, u64 inum)
        return ret ?: sectors;
 }
 
-static int lookup_inode(struct btree_trans *trans, u64 inode_nr,
-                       struct bch_inode_unpacked *inode,
-                       u32 *snapshot)
+static int __lookup_inode(struct btree_trans *trans, u64 inode_nr,
+                         struct bch_inode_unpacked *inode,
+                         u32 *snapshot)
 {
        struct btree_iter *iter;
        struct bkey_s_c k;
@@ -63,19 +63,34 @@ err:
        return ret;
 }
 
-static int write_inode(struct btree_trans *trans,
-                      struct bch_inode_unpacked *inode,
-                      u32 snapshot)
+static int lookup_inode(struct btree_trans *trans, u64 inode_nr,
+                       struct bch_inode_unpacked *inode,
+                       u32 *snapshot)
+{
+       return lockrestart_do(trans, __lookup_inode(trans, inode_nr, inode, snapshot));
+}
+
+static int __write_inode(struct btree_trans *trans,
+                        struct bch_inode_unpacked *inode,
+                        u32 snapshot)
 {
        struct btree_iter *inode_iter =
                bch2_trans_get_iter(trans, BTREE_ID_inodes,
                                    SPOS(0, inode->bi_inum, snapshot),
                                    BTREE_ITER_INTENT);
+       int ret = bch2_inode_write(trans, inode_iter, inode);
+       bch2_trans_iter_put(trans, inode_iter);
+       return ret;
+}
+
+static int write_inode(struct btree_trans *trans,
+                      struct bch_inode_unpacked *inode,
+                      u32 snapshot)
+{
        int ret = __bch2_trans_do(trans, NULL, NULL,
                                  BTREE_INSERT_NOFAIL|
                                  BTREE_INSERT_LAZY_RW,
-                                 bch2_inode_write(trans, inode_iter, inode));
-       bch2_trans_iter_put(trans, inode_iter);
+                                 __write_inode(trans, inode, snapshot));
        if (ret)
                bch_err(trans->c, "error in fsck: error %i updating inode", ret);
        return ret;
@@ -114,57 +129,101 @@ static int remove_dirent(struct btree_trans *trans, struct bpos pos)
        return ret;
 }
 
-static int __reattach_inode(struct btree_trans *trans,
-                           struct bch_inode_unpacked *lostfound,
-                           u64 inum)
+/* Get lost+found, create if it doesn't exist: */
+static int lookup_lostfound(struct btree_trans *trans,
+                           struct bch_inode_unpacked *lostfound)
 {
-       struct bch_hash_info dir_hash =
-               bch2_hash_info_init(trans->c, lostfound);
-       struct bch_inode_unpacked inode_u;
+       struct bch_fs *c = trans->c;
+       struct bch_inode_unpacked root;
+       struct bch_hash_info root_hash_info;
+       struct qstr lostfound_str = QSTR("lost+found");
+       u64 inum;
+       u32 snapshot;
+       int ret;
+
+       ret = lookup_inode(trans, BCACHEFS_ROOT_INO, &root, &snapshot);
+       if (ret && ret != -ENOENT)
+               return ret;
+
+       root_hash_info = bch2_hash_info_init(c, &root);
+       inum = bch2_dirent_lookup(c, BCACHEFS_ROOT_INO, &root_hash_info,
+                                 &lostfound_str);
+       if (!inum) {
+               bch_notice(c, "creating lost+found");
+               goto create_lostfound;
+       }
+
+       ret = lookup_inode(trans, inum, lostfound, &snapshot);
+       if (ret && ret != -ENOENT) {
+               /*
+                * The check_dirents pass has already run, dangling dirents
+                * shouldn't exist here:
+                */
+               bch_err(c, "error looking up lost+found: %i", ret);
+               return ret;
+       }
+
+       if (ret == -ENOENT) {
+create_lostfound:
+               bch2_inode_init_early(c, lostfound);
+
+               ret = __bch2_trans_do(trans, NULL, NULL,
+                                     BTREE_INSERT_NOFAIL|
+                                     BTREE_INSERT_LAZY_RW,
+                       bch2_create_trans(trans,
+                                         BCACHEFS_ROOT_INO, &root,
+                                         lostfound,
+                                         &lostfound_str,
+                                         0, 0, S_IFDIR|0700, 0, NULL, NULL));
+               if (ret)
+                       bch_err(c, "error creating lost+found: %i", ret);
+       }
+
+       return 0;
+}
+
+static int reattach_inode(struct btree_trans *trans,
+                         struct bch_inode_unpacked *inode)
+{
+       struct bch_hash_info dir_hash;
+       struct bch_inode_unpacked lostfound;
        char name_buf[20];
        struct qstr name;
        u64 dir_offset = 0;
-       u32 snapshot;
        int ret;
 
-       snprintf(name_buf, sizeof(name_buf), "%llu", inum);
-       name = (struct qstr) QSTR(name_buf);
-
-       ret = lookup_inode(trans, inum, &inode_u, &snapshot);
+       ret = lookup_lostfound(trans, &lostfound);
        if (ret)
                return ret;
 
-       if (S_ISDIR(inode_u.bi_mode)) {
-               lostfound->bi_nlink++;
+       if (S_ISDIR(inode->bi_mode)) {
+               lostfound.bi_nlink++;
 
-               ret = write_inode(trans, lostfound, U32_MAX);
+               ret = write_inode(trans, &lostfound, U32_MAX);
                if (ret)
                        return ret;
        }
 
-       ret = bch2_dirent_create(trans, lostfound->bi_inum, &dir_hash,
-                                mode_to_type(inode_u.bi_mode),
-                                &name, inum, &dir_offset,
-                                BCH_HASH_SET_MUST_CREATE);
-       if (ret)
-               return ret;
+       dir_hash = bch2_hash_info_init(trans->c, &lostfound);
 
-       inode_u.bi_dir          = lostfound->bi_inum;
-       inode_u.bi_dir_offset   = dir_offset;
+       snprintf(name_buf, sizeof(name_buf), "%llu", inode->bi_inum);
+       name = (struct qstr) QSTR(name_buf);
 
-       return write_inode(trans, &inode_u, U32_MAX);
-}
+       ret = __bch2_trans_do(trans, NULL, NULL, BTREE_INSERT_LAZY_RW,
+               bch2_dirent_create(trans, lostfound.bi_inum, &dir_hash,
+                                  mode_to_type(inode->bi_mode),
+                                  &name, inode->bi_inum, &dir_offset,
+                                  BCH_HASH_SET_MUST_CREATE));
+       if (ret) {
+               bch_err(trans->c, "error %i reattaching inode %llu",
+                       ret, inode->bi_inum);
+               return ret;
+       }
 
-static int reattach_inode(struct btree_trans *trans,
-                         struct bch_inode_unpacked *lostfound,
-                         u64 inum)
-{
-       int ret = __bch2_trans_do(trans, NULL, NULL, BTREE_INSERT_LAZY_RW,
-                             __reattach_inode(trans, lostfound, inum));
-       if (ret)
-               bch_err(trans->c, "error %i reattaching inode %llu", ret, inum);
+       inode->bi_dir           = lostfound.bi_inum;
+       inode->bi_dir_offset    = dir_offset;
 
-       return ret;
+       return write_inode(trans, inode, U32_MAX);
 }
 
 static int remove_backpointer(struct btree_trans *trans,
@@ -931,58 +990,6 @@ create_root:
                                 BTREE_INSERT_LAZY_RW);
 }
 
-/* Get lost+found, create if it doesn't exist: */
-static int check_lostfound(struct bch_fs *c,
-                          struct bch_inode_unpacked *root_inode,
-                          struct bch_inode_unpacked *lostfound_inode)
-{
-       struct qstr lostfound = QSTR("lost+found");
-       struct bch_hash_info root_hash_info =
-               bch2_hash_info_init(c, root_inode);
-       u64 inum;
-       u32 snapshot;
-       int ret;
-
-       bch_verbose(c, "checking lost+found");
-
-       inum = bch2_dirent_lookup(c, BCACHEFS_ROOT_INO, &root_hash_info,
-                                &lostfound);
-       if (!inum) {
-               bch_notice(c, "creating lost+found");
-               goto create_lostfound;
-       }
-
-       ret = bch2_trans_do(c, NULL, NULL, 0,
-               lookup_inode(&trans, inum, lostfound_inode, &snapshot));
-       if (ret && ret != -ENOENT)
-               return ret;
-
-       if (fsck_err_on(ret, c, "lost+found missing"))
-               goto create_lostfound;
-
-       if (fsck_err_on(!S_ISDIR(lostfound_inode->bi_mode), c,
-                       "lost+found inode not a directory"))
-               goto create_lostfound;
-
-       return 0;
-fsck_err:
-       return ret;
-create_lostfound:
-       bch2_inode_init_early(c, lostfound_inode);
-
-       ret = bch2_trans_do(c, NULL, NULL,
-                           BTREE_INSERT_NOFAIL|
-                           BTREE_INSERT_LAZY_RW,
-               bch2_create_trans(&trans,
-                                 BCACHEFS_ROOT_INO, root_inode,
-                                 lostfound_inode, &lostfound,
-                                 0, 0, S_IFDIR|0700, 0, NULL, NULL));
-       if (ret)
-               bch_err(c, "error creating lost+found: %i", ret);
-
-       return ret;
-}
-
 struct pathbuf {
        size_t          nr;
        size_t          size;
@@ -1014,7 +1021,6 @@ static int path_down(struct pathbuf *p, u64 inum)
 }
 
 static int check_path(struct btree_trans *trans,
-                     struct bch_inode_unpacked *lostfound,
                      struct pathbuf *p,
                      struct bch_inode_unpacked *inode)
 {
@@ -1038,7 +1044,7 @@ static int check_path(struct btree_trans *trans,
                                     inode->bi_nlink,
                                     inode->bi_dir,
                                     inode->bi_dir_offset))
-                               ret = reattach_inode(trans, lostfound, inode->bi_inum);
+                               ret = reattach_inode(trans, inode);
                        break;
                }
                ret = 0;
@@ -1067,12 +1073,11 @@ static int check_path(struct btree_trans *trans,
                                break;
                        }
 
-                       ret = reattach_inode(trans, lostfound, inode->bi_inum);
+                       ret = reattach_inode(trans, inode);
                        break;
                }
 
-               ret = lockrestart_do(trans,
-                               lookup_inode(trans, inode->bi_dir, inode, &snapshot));
+               ret = lookup_inode(trans, inode->bi_dir, inode, &snapshot);
                if (ret) {
                        /* Should have been caught in dirents pass */
                        bch_err(c, "error looking up parent directory: %i", ret);
@@ -1090,8 +1095,7 @@ fsck_err:
  * After check_dirents(), if an inode backpointer doesn't exist that means it's
  * unreachable:
  */
-static int check_directory_structure(struct bch_fs *c,
-                                    struct bch_inode_unpacked *lostfound)
+static int check_directory_structure(struct bch_fs *c)
 {
        struct btree_trans trans;
        struct btree_iter *iter;
@@ -1113,7 +1117,7 @@ static int check_directory_structure(struct bch_fs *c,
                        break;
                }
 
-               ret = check_path(&trans, lostfound, &path, &u);
+               ret = check_path(&trans, &path, &u);
                if (ret)
                        break;
        }
@@ -1190,7 +1194,6 @@ static int bch2_gc_walk_dirents(struct bch_fs *c, nlink_table *links,
 }
 
 static int check_inode_nlink(struct btree_trans *trans,
-                            struct bch_inode_unpacked *lostfound_inode,
                             struct btree_iter *iter,
                             struct bkey_s_c_inode inode,
                             unsigned nlink)
@@ -1238,7 +1241,6 @@ fsck_err:
 
 noinline_for_stack
 static int bch2_gc_walk_inodes(struct bch_fs *c,
-                              struct bch_inode_unpacked *lostfound_inode,
                               nlink_table *links,
                               u64 range_start, u64 range_end)
 {
@@ -1259,7 +1261,7 @@ static int bch2_gc_walk_inodes(struct bch_fs *c,
                        continue;
 
                link = genradix_ptr(links, k.k->p.offset - range_start);
-               ret = check_inode_nlink(&trans, lostfound_inode, iter,
+               ret = check_inode_nlink(&trans, iter,
                                        bkey_s_c_to_inode(k), link ? link->count : 0);
                if (ret)
                        break;
@@ -1275,8 +1277,7 @@ static int bch2_gc_walk_inodes(struct bch_fs *c,
 }
 
 noinline_for_stack
-static int check_nlinks(struct bch_fs *c,
-                             struct bch_inode_unpacked *lostfound_inode)
+static int check_nlinks(struct bch_fs *c)
 {
        nlink_table links;
        u64 this_iter_range_start, next_iter_range_start = 0;
@@ -1296,7 +1297,7 @@ static int check_nlinks(struct bch_fs *c,
                if (ret)
                        break;
 
-               ret = bch2_gc_walk_inodes(c, lostfound_inode, &links,
+               ret = bch2_gc_walk_inodes(c, &links,
                                         this_iter_range_start,
                                         next_iter_range_start);
                if (ret)
@@ -1316,16 +1317,15 @@ static int check_nlinks(struct bch_fs *c,
  */
 int bch2_fsck_full(struct bch_fs *c)
 {
-       struct bch_inode_unpacked root_inode, lostfound_inode;
+       struct bch_inode_unpacked root_inode;
 
        return  check_inodes(c, true) ?:
                check_extents(c) ?:
                check_dirents(c) ?:
                check_xattrs(c) ?:
                check_root(c, &root_inode) ?:
-               check_lostfound(c, &root_inode, &lostfound_inode) ?:
-               check_directory_structure(c, &lostfound_inode) ?:
-               check_nlinks(c, &lostfound_inode);
+               check_directory_structure(c) ?:
+               check_nlinks(c);
 }
 
 int bch2_fsck_walk_inodes_only(struct bch_fs *c)