fsck.f2fs: update curseg .next_blkoff/.alloc_type preferential
authorChao Yu <yuchao0@huawei.com>
Thu, 16 May 2019 12:40:43 +0000 (20:40 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 21 May 2019 00:42:52 +0000 (17:42 -0700)
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>
fsck/fsck.c
fsck/fsck.h
fsck/mount.c

index 247b75e..6f0f262 100644 (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) ||
index c56e733..f00036e 100644 (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);
index 21d71d4..aecd0cd 100644 (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;