summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-07-15 04:06:51 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:08:07 +0300
commit88c07f739786d00c7526d598956955c8310d72d2 (patch)
tree9f34060d43a1588532ff962cdf4c0d68d1a6110c
parent1c6fdbd8f2465ddfb73a01ec620cbf3d14044e1a (diff)
downloadlinux-88c07f739786d00c7526d598956955c8310d72d2.tar.xz
bcachefs: Only check inode i_nlink during full fsck
Now that all filesystem operatinos that manipulate the filesystem heirachy and i_nlink are fully atomic, we can add a feature bit to indicate i_nlink doesn't need to be checked. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/bcachefs.h1
-rw-r--r--fs/bcachefs/error.c5
-rw-r--r--fs/bcachefs/fsck.c30
-rw-r--r--fs/bcachefs/recovery.c7
4 files changed, 40 insertions, 3 deletions
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index b5e119d09a83..57132c79c4b9 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -472,6 +472,7 @@ enum {
/* misc: */
BCH_FS_BDEV_MOUNTED,
BCH_FS_FSCK_FIXED_ERRORS,
+ BCH_FS_FSCK_UNFIXED_ERRORS,
BCH_FS_FIXED_GENS,
BCH_FS_REBUILD_REPLICAS,
BCH_FS_HOLD_BTREE_WRITES,
diff --git a/fs/bcachefs/error.c b/fs/bcachefs/error.c
index e975fab43d49..08e79166dae4 100644
--- a/fs/bcachefs/error.c
+++ b/fs/bcachefs/error.c
@@ -132,8 +132,9 @@ print:
mutex_unlock(&c->fsck_error_lock);
- if (fix)
- set_bit(BCH_FS_FSCK_FIXED_ERRORS, &c->flags);
+ set_bit(fix
+ ? BCH_FS_FSCK_FIXED_ERRORS
+ : BCH_FS_FSCK_UNFIXED_ERRORS, &c->flags);
return fix ? FSCK_ERR_FIX
: flags & FSCK_CAN_IGNORE ? FSCK_ERR_IGNORE
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index eb01284a841f..c352fa01fb5a 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -954,6 +954,23 @@ static int check_inode_nlink(struct bch_fs *c,
return 0;
}
+ if (!link->count &&
+ !(u->bi_flags & BCH_INODE_UNLINKED) &&
+ (c->sb.features & (1 << BCH_FEATURE_ATOMIC_NLINK))) {
+ if (fsck_err(c, "unreachable inode %llu not marked as unlinked (type %u)",
+ u->bi_inum, mode_to_type(u->bi_mode)) ==
+ FSCK_ERR_IGNORE)
+ return 0;
+
+ ret = reattach_inode(c, lostfound_inode, u->bi_inum);
+ if (ret)
+ return ret;
+
+ link->count = 1;
+ real_i_nlink = nlink_bias(u->bi_mode) + link->dir_count;
+ goto set_i_nlink;
+ }
+
if (i_nlink < link->count) {
if (fsck_err(c, "inode %llu i_link too small (%u < %u, type %i)",
u->bi_inum, i_nlink, link->count,
@@ -973,6 +990,16 @@ static int check_inode_nlink(struct bch_fs *c,
goto set_i_nlink;
}
+ if (i_nlink != real_i_nlink &&
+ (c->sb.features & (1 << BCH_FEATURE_ATOMIC_NLINK))) {
+ if (fsck_err(c, "inode %llu has wrong i_nlink "
+ "(type %u i_nlink %u, should be %u)",
+ u->bi_inum, mode_to_type(u->bi_mode),
+ i_nlink, real_i_nlink) == FSCK_ERR_IGNORE)
+ return 0;
+ goto set_i_nlink;
+ }
+
if (real_i_nlink && i_nlink != real_i_nlink)
bch_verbose(c, "setting inode %llu nlink from %u to %u",
u->bi_inum, i_nlink, real_i_nlink);
@@ -1299,7 +1326,8 @@ int bch2_fsck(struct bch_fs *c)
if (!c->opts.nofsck)
return bch2_fsck_full(c);
- if (!c->sb.clean)
+ if (!c->sb.clean &&
+ !(c->sb.features & (1 << BCH_FEATURE_ATOMIC_NLINK)))
return bch2_fsck_inode_nlink(c);
return bch2_fsck_walk_inodes_only(c);
diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c
index 2596c3c26064..624d97dc4537 100644
--- a/fs/bcachefs/recovery.c
+++ b/fs/bcachefs/recovery.c
@@ -256,6 +256,12 @@ int bch2_fs_recovery(struct bch_fs *c)
if (ret)
goto err;
+ if (!test_bit(BCH_FS_FSCK_UNFIXED_ERRORS, &c->flags)) {
+ mutex_lock(&c->sb_lock);
+ c->disk_sb.sb->features[0] |= 1ULL << BCH_FEATURE_ATOMIC_NLINK;
+ mutex_unlock(&c->sb_lock);
+ }
+
if (enabled_qtypes(c)) {
bch_verbose(c, "reading quotas:");
ret = bch2_fs_quota_read(c);
@@ -366,6 +372,7 @@ int bch2_fs_initialize(struct bch_fs *c)
mutex_lock(&c->sb_lock);
SET_BCH_SB_INITIALIZED(c->disk_sb.sb, true);
SET_BCH_SB_CLEAN(c->disk_sb.sb, false);
+ c->disk_sb.sb->features[0] |= 1ULL << BCH_FEATURE_ATOMIC_NLINK;
bch2_write_super(c);
mutex_unlock(&c->sb_lock);