bcachefs: fsck: Fix check_directory_structure when no check_dirents
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 17 Jun 2025 17:08:35 +0000 (13:08 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Tue, 17 Jun 2025 17:35:19 +0000 (13:35 -0400)
check_directory_structure runs after check_dirents, so it expects that
it won't see any inodes with missing backpointers - normally.

But online fsck can't run check_dirents yet, or the user might only be
running a specific pass, so we need to be careful that this isn't an
error. If an inode is unreachable, that's handled by a separate pass.

Also, add a new 'bch2_inode_has_backpointer()' helper, since we were
doing this inconsistently.

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

index 73cff24598edfdc56c73e5db1acb963a9bd2416f..57ddc20a5cce16c461fd01778e207cb7b8621703 100644 (file)
@@ -327,7 +327,8 @@ static inline bool inode_should_reattach(struct bch_inode_unpacked *inode)
            (inode->bi_flags & BCH_INODE_has_child_snapshot))
                return false;
 
-       return !inode->bi_dir && !(inode->bi_flags & BCH_INODE_unlinked);
+       return !bch2_inode_has_backpointer(inode) &&
+               !(inode->bi_flags & BCH_INODE_unlinked);
 }
 
 static int maybe_delete_dirent(struct btree_trans *trans, struct bpos d_pos, u32 snapshot)
@@ -514,7 +515,7 @@ static struct bkey_s_c_dirent dirent_get_by_pos(struct btree_trans *trans,
 static int remove_backpointer(struct btree_trans *trans,
                              struct bch_inode_unpacked *inode)
 {
-       if (!inode->bi_dir)
+       if (!bch2_inode_has_backpointer(inode))
                return 0;
 
        u32 snapshot = inode->bi_snapshot;
@@ -1165,13 +1166,14 @@ static int check_inode(struct btree_trans *trans,
        if (ret)
                goto err;
 
-       if (u.bi_dir || u.bi_dir_offset) {
+       if (bch2_inode_has_backpointer(&u)) {
                ret = check_inode_dirent_inode(trans, &u, &do_update);
                if (ret)
                        goto err;
        }
 
-       if (fsck_err_on(u.bi_dir && (u.bi_flags & BCH_INODE_unlinked),
+       if (fsck_err_on(bch2_inode_has_backpointer(&u) &&
+                       (u.bi_flags & BCH_INODE_unlinked),
                        trans, inode_unlinked_but_has_dirent,
                        "inode unlinked but has dirent\n%s",
                        (printbuf_reset(&buf),
@@ -2751,7 +2753,13 @@ static int check_path_loop(struct btree_trans *trans, struct bkey_s_c inode_k)
        if (ret)
                return ret;
 
-       while (!inode.bi_subvol) {
+       /*
+        * If we're running full fsck, check_dirents() will have already ran,
+        * and we shouldn't see any missing backpointers here - otherwise that's
+        * handled separately, by check_unreachable_inodes
+        */
+       while (!inode.bi_subvol &&
+              bch2_inode_has_backpointer(&inode)) {
                struct btree_iter dirent_iter;
                struct bkey_s_c_dirent d;
 
index 82cec2836cbdd35c644f883e9f673ba195911b77..b8ec3e628d9055971fbf52c29a9c7f7e629ae781 100644 (file)
@@ -254,6 +254,11 @@ static inline bool bch2_inode_casefold(struct bch_fs *c, const struct bch_inode_
                : c->opts.casefold;
 }
 
+static inline bool bch2_inode_has_backpointer(const struct bch_inode_unpacked *bi)
+{
+       return bi->bi_dir || bi->bi_dir_offset;
+}
+
 /* i_nlink: */
 
 static inline unsigned nlink_bias(umode_t mode)
index 7d1068aa998f91585035ba2a3ef5874eb9b8974a..c3f87c59922d1a0c1cbf8220a52e759c9ecfb53a 100644 (file)
@@ -734,8 +734,7 @@ static int bch2_check_dirent_inode_dirent(struct btree_trans *trans,
        if (inode_points_to_dirent(target, d))
                return 0;
 
-       if (!target->bi_dir &&
-           !target->bi_dir_offset) {
+       if (!bch2_inode_has_backpointer(target)) {
                fsck_err_on(S_ISDIR(target->bi_mode),
                            trans, inode_dir_missing_backpointer,
                            "directory with missing backpointer\n%s",