fsck.f2fs: allow fsck to fix issues with online resize due to SPO

Add support for new CP flag CP_RESIZEFS_FLAG set during online
resize FS. If SPO happens after SB is updated but CP isn't, then
allow fsck to fix it.

The fsck errors without this fix -
    Info: CKPT version = 6ed7bccb
            Wrong user_block_count(2233856)
    [f2fs_do_mount:3365] Checkpoint is polluted

The subsequent mount failure without this fix -
[   11.294650] F2FS-fs (sda8): Wrong user_block_count: 2233856
[   11.300272] F2FS-fs (sda8): Failed to get valid F2FS checkpoint

Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Sahitya Tummala 2020-03-24 14:42:50 +05:30 committed by Jaegeuk Kim
parent 11e4322127
commit 9a31cefa29
2 changed files with 55 additions and 16 deletions

View File

@ -429,6 +429,8 @@ void print_cp_state(u32 flag)
MSG(0, "%s", " orphan_inodes");
if (flag & CP_DISABLED_FLAG)
MSG(0, "%s", " disabled");
if (flag & CP_RESIZEFS_FLAG)
MSG(0, "%s", " resizefs");
if (flag & CP_UMOUNT_FLAG)
MSG(0, "%s", " unmount");
else
@ -1123,11 +1125,31 @@ fail_no_cp:
return -EINVAL;
}
/*
* For a return value of 1, caller should further check for c.fix_on state
* and take appropriate action.
*/
static int f2fs_should_proceed(struct f2fs_super_block *sb, u32 flag)
{
if (!c.fix_on && (c.auto_fix || c.preen_mode)) {
if (flag & CP_FSCK_FLAG ||
flag & CP_QUOTA_NEED_FSCK_FLAG ||
(exist_qf_ino(sb) && (flag & CP_ERROR_FLAG))) {
c.fix_on = 1;
} else if (!c.preen_mode) {
print_cp_state(flag);
return 0;
}
}
return 1;
}
int sanity_check_ckpt(struct f2fs_sb_info *sbi)
{
unsigned int total, fsmeta;
struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
unsigned int flag = get_cp(ckpt_flags);
unsigned int ovp_segments, reserved_segments;
unsigned int main_segs, blocks_per_seg;
unsigned int sit_segs, nat_segs;
@ -1164,8 +1186,34 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi)
log_blocks_per_seg = get_sb(log_blocks_per_seg);
if (!user_block_count || user_block_count >=
segment_count_main << log_blocks_per_seg) {
MSG(0, "\tWrong user_block_count(%u)\n", user_block_count);
return 1;
ASSERT_MSG("\tWrong user_block_count(%u)\n", user_block_count);
if (!f2fs_should_proceed(sb, flag))
return 1;
if (!c.fix_on)
return 1;
if (flag & (CP_FSCK_FLAG | CP_RESIZEFS_FLAG)) {
u32 valid_user_block_cnt;
u32 seg_cnt_main = get_sb(segment_count) -
(get_sb(segment_count_ckpt) +
get_sb(segment_count_sit) +
get_sb(segment_count_nat) +
get_sb(segment_count_ssa));
/* validate segment_count_main in sb first */
if (seg_cnt_main != get_sb(segment_count_main)) {
MSG(0, "Inconsistent segment_cnt_main %u in sb\n",
segment_count_main << log_blocks_per_seg);
return 1;
}
valid_user_block_cnt = ((get_sb(segment_count_main) -
get_cp(overprov_segment_count)) * c.blks_per_seg);
MSG(0, "Info: Fix wrong user_block_count in CP: (%u) -> (%u)\n",
user_block_count, valid_user_block_cnt);
set_cp(user_block_count, valid_user_block_cnt);
c.bug_on = 1;
}
}
main_segs = get_sb(segment_count_main);
@ -3355,6 +3403,8 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
return -1;
}
c.bug_on = 0;
if (sanity_check_ckpt(sbi)) {
ERR_MSG("Checkpoint is polluted\n");
return -1;
@ -3374,8 +3424,6 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
c.fix_on = 1;
}
c.bug_on = 0;
if (tune_sb_features(sbi))
return -1;
@ -3405,18 +3453,8 @@ int f2fs_do_mount(struct f2fs_sb_info *sbi)
return -1;
}
if (!c.fix_on && (c.auto_fix || c.preen_mode)) {
u32 flag = get_cp(ckpt_flags);
if (flag & CP_FSCK_FLAG ||
flag & CP_QUOTA_NEED_FSCK_FLAG ||
(exist_qf_ino(sb) && (flag & CP_ERROR_FLAG))) {
c.fix_on = 1;
} else if (!c.preen_mode) {
print_cp_state(flag);
return 1;
}
}
if (!f2fs_should_proceed(sb, get_cp(ckpt_flags)))
return 1;
/* Check nat_bits */
if (c.func == FSCK && is_set_ckpt_flags(cp, CP_NAT_BITS_FLAG)) {

View File

@ -678,6 +678,7 @@ struct f2fs_super_block {
/*
* For checkpoint
*/
#define CP_RESIZEFS_FLAG 0x00004000
#define CP_DISABLED_FLAG 0x00001000
#define CP_QUOTA_NEED_FSCK_FLAG 0x00000800
#define CP_LARGE_NAT_BITMAP_FLAG 0x00000400