f2fs: return error during fill_super
authorJaegeuk Kim <jaegeuk@kernel.org>
Wed, 20 Dec 2017 03:16:34 +0000 (19:16 -0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 3 Jan 2018 03:27:31 +0000 (19:27 -0800)
Let's avoid BUG_ON during fill_super, when on-disk was totall corrupted.

Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/segment.c
fs/f2fs/segment.h

index 40e1d20..b03f65e 100644 (file)
@@ -3476,7 +3476,7 @@ static int build_curseg(struct f2fs_sb_info *sbi)
        return restore_curseg_summaries(sbi);
 }
 
-static void build_sit_entries(struct f2fs_sb_info *sbi)
+static int build_sit_entries(struct f2fs_sb_info *sbi)
 {
        struct sit_info *sit_i = SIT_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
@@ -3486,6 +3486,7 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
        int sit_blk_cnt = SIT_BLK_CNT(sbi);
        unsigned int i, start, end;
        unsigned int readed, start_blk = 0;
+       int err = 0;
 
        do {
                readed = ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES,
@@ -3504,7 +3505,9 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
                        sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
                        f2fs_put_page(page, 1);
 
-                       check_block_count(sbi, start, &sit);
+                       err = check_block_count(sbi, start, &sit);
+                       if (err)
+                               return err;
                        seg_info_from_raw_sit(se, &sit);
 
                        /* build discard map only one time */
@@ -3539,7 +3542,9 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
 
                old_valid_blocks = se->valid_blocks;
 
-               check_block_count(sbi, start, &sit);
+               err = check_block_count(sbi, start, &sit);
+               if (err)
+                       break;
                seg_info_from_raw_sit(se, &sit);
 
                if (f2fs_discard_en(sbi)) {
@@ -3559,6 +3564,7 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
                                se->valid_blocks - old_valid_blocks;
        }
        up_read(&curseg->journal_rwsem);
+       return err;
 }
 
 static void init_free_segmap(struct f2fs_sb_info *sbi)
@@ -3733,7 +3739,9 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
                return err;
 
        /* reinit free segmap based on SIT */
-       build_sit_entries(sbi);
+       err = build_sit_entries(sbi);
+       if (err)
+               return err;
 
        init_free_segmap(sbi);
        err = build_dirty_segmap(sbi);
index d1d394c..71a2aaa 100644 (file)
@@ -655,7 +655,7 @@ static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
 /*
  * Summary block is always treated as an invalid block
  */
-static inline void check_block_count(struct f2fs_sb_info *sbi,
+static inline int check_block_count(struct f2fs_sb_info *sbi,
                int segno, struct f2fs_sit_entry *raw_sit)
 {
 #ifdef CONFIG_F2FS_CHECK_FS
@@ -677,11 +677,25 @@ static inline void check_block_count(struct f2fs_sb_info *sbi,
                cur_pos = next_pos;
                is_valid = !is_valid;
        } while (cur_pos < sbi->blocks_per_seg);
-       BUG_ON(GET_SIT_VBLOCKS(raw_sit) != valid_blocks);
+
+       if (unlikely(GET_SIT_VBLOCKS(raw_sit) != valid_blocks)) {
+               f2fs_msg(sbi->sb, KERN_ERR,
+                               "Mismatch valid blocks %d vs. %d",
+                                       GET_SIT_VBLOCKS(raw_sit), valid_blocks);
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               return -EINVAL;
+       }
 #endif
        /* check segment usage, and check boundary of a given segment number */
-       f2fs_bug_on(sbi, GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
-                                       || segno > TOTAL_SEGS(sbi) - 1);
+       if (unlikely(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
+                                       || segno > TOTAL_SEGS(sbi) - 1)) {
+               f2fs_msg(sbi->sb, KERN_ERR,
+                               "Wrong valid blocks %d or segno %u",
+                                       GET_SIT_VBLOCKS(raw_sit), segno);
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               return -EINVAL;
+       }
+       return 0;
 }
 
 static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi,