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:
+13
-5
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user