diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2018-07-15 04:06:51 +0300 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-23 00:08:07 +0300 |
commit | 88c07f739786d00c7526d598956955c8310d72d2 (patch) | |
tree | 9f34060d43a1588532ff962cdf4c0d68d1a6110c | |
parent | 1c6fdbd8f2465ddfb73a01ec620cbf3d14044e1a (diff) | |
download | linux-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.h | 1 | ||||
-rw-r--r-- | fs/bcachefs/error.c | 5 | ||||
-rw-r--r-- | fs/bcachefs/fsck.c | 30 | ||||
-rw-r--r-- | fs/bcachefs/recovery.c | 7 |
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); |