fsck.f2fs: update curseg .next_blkoff/.alloc_type preferential

If .next_blkoff is inconsistent, we can update curseg .next_blkoff
to first unused block address, and change .alloc_type to SSR
preferential, instead of move curseg to other position.

This can help to repair fuzzed image which has no more free segment.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Chao Yu 2019-05-16 20:40:43 +08:00 committed by Jaegeuk Kim
parent 9e0a58749d
commit 54244dcafd
3 changed files with 50 additions and 5 deletions

View File

@ -2164,6 +2164,23 @@ int check_curseg_offsets(struct f2fs_sb_info *sbi)
return 0;
}
static void fix_curseg_info(struct f2fs_sb_info *sbi)
{
int i, need_update = 0;
for (i = 0; i < NO_CHECK_TYPE; i++) {
if (check_curseg_offset(sbi, i)) {
update_curseg_info(sbi, i);
need_update = 1;
}
}
if (need_update) {
write_curseg_info(sbi);
flush_curseg_sit_entries(sbi);
}
}
int check_sit_types(struct f2fs_sb_info *sbi)
{
unsigned int i;
@ -2752,11 +2769,7 @@ int fsck_verify(struct f2fs_sb_info *sbi)
fix_hard_links(sbi);
fix_nat_entries(sbi);
rewrite_sit_area_bitmap(sbi);
if (check_curseg_offsets(sbi)) {
move_curseg_info(sbi, SM_I(sbi)->main_blkaddr, 0);
write_curseg_info(sbi);
flush_curseg_sit_entries(sbi);
}
fix_curseg_info(sbi);
fix_checksum(sbi);
fix_checkpoint(sbi);
} else if (is_set_ckpt_flags(cp, CP_FSCK_FLAG) ||

View File

@ -185,6 +185,7 @@ extern void f2fs_do_umount(struct f2fs_sb_info *);
extern int f2fs_sparse_initialize_meta(struct f2fs_sb_info *);
extern void flush_journal_entries(struct f2fs_sb_info *);
extern void update_curseg_info(struct f2fs_sb_info *, int);
extern void zero_journal_entries(struct f2fs_sb_info *);
extern void flush_sit_entries(struct f2fs_sb_info *);
extern void move_curseg_info(struct f2fs_sb_info *, u64, int);

View File

@ -2159,6 +2159,30 @@ void flush_sit_entries(struct f2fs_sb_info *sbi)
free(sit_blk);
}
int relocate_curseg_offset(struct f2fs_sb_info *sbi, int type)
{
struct curseg_info *curseg = CURSEG_I(sbi, type);
struct seg_entry *se = get_seg_entry(sbi, curseg->segno);
unsigned int i;
for (i = 0; i < sbi->blocks_per_seg; i++) {
if (!f2fs_test_bit(i, (const char *)se->cur_valid_map))
break;
}
if (i == sbi->blocks_per_seg)
return -EINVAL;
DBG(1, "Update curseg[%d].next_blkoff %u -> %u, alloc_type %s -> SSR\n",
type, curseg->next_blkoff, i,
curseg->alloc_type == LFS ? "LFS" : "SSR");
curseg->next_blkoff = i;
curseg->alloc_type = SSR;
return 0;
}
int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left, int type)
{
struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
@ -2255,6 +2279,13 @@ void move_curseg_info(struct f2fs_sb_info *sbi, u64 from, int left)
}
}
void update_curseg_info(struct f2fs_sb_info *sbi, int type)
{
if (!relocate_curseg_offset(sbi, type))
return;
move_curseg_info(sbi, SM_I(sbi)->main_blkaddr, 0);
}
void zero_journal_entries(struct f2fs_sb_info *sbi)
{
int i;