bcachefs: fsck: Fix check_directory_structure when no check_dirents

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>
This commit is contained in:
Kent Overstreet
2025-06-17 13:08:35 -04:00
parent e1f0e1a45a
commit bbc3a0b17a
3 changed files with 19 additions and 7 deletions
+13 -5
View 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;
+5
View 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)
+1 -2
View 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",