f2fs: avoid f2fs_bug_on if f2fs_get_meta_page_nofail got EIO
authorJaegeuk Kim <jaegeuk@kernel.org>
Tue, 18 Sep 2018 00:36:06 +0000 (17:36 -0700)
committerJaegeuk Kim <jaegeuk@kernel.org>
Fri, 26 Oct 2018 18:23:32 +0000 (11:23 -0700)
This patch avoids BUG_ON when f2fs_get_meta_page_nofail got EIO during
xfstests/generic/475.

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

index 86db0004774af062817f9b7bc4f1c97310aa0df1..49b6c9c44fa166a81545d399f775fd269eb984d8 100644 (file)
@@ -119,11 +119,8 @@ retry:
                if (PTR_ERR(page) == -EIO &&
                                ++count <= DEFAULT_RETRY_IO_COUNT)
                        goto retry;
-
                f2fs_stop_checkpoint(sbi, false);
-               f2fs_bug_on(sbi, 1);
        }
-
        return page;
 }
 
@@ -1496,7 +1493,10 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver);
 
        /* write cached NAT/SIT entries to NAT/SIT area */
-       f2fs_flush_nat_entries(sbi, cpc);
+       err = f2fs_flush_nat_entries(sbi, cpc);
+       if (err)
+               goto stop;
+
        f2fs_flush_sit_entries(sbi, cpc);
 
        /* unlock all the fs_lock[] in do_checkpoint() */
@@ -1505,7 +1505,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                f2fs_release_discard_addrs(sbi);
        else
                f2fs_clear_prefree_segments(sbi, cpc);
-
+stop:
        unblock_operations(sbi);
        stat_inc_cp_count(sbi->stat_info);
 
index 45add593d55c276d97596f673d5cf4a2915ad693..140aafaddcc91381e8a4c6d0af48bd260acfef38 100644 (file)
@@ -2912,7 +2912,7 @@ int f2fs_recover_xattr_data(struct inode *inode, struct page *page);
 int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page);
 int f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
                        unsigned int segno, struct f2fs_summary_block *sum);
-void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
+int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
 int f2fs_build_node_manager(struct f2fs_sb_info *sbi);
 void f2fs_destroy_node_manager(struct f2fs_sb_info *sbi);
 int __init f2fs_create_node_manager_caches(void);
index 7a41f97fae688f718f7b13f80c627bc6b55f6915..55ef8a8885452e1740e830979f2e14b14edd35f6 100644 (file)
@@ -1066,6 +1066,18 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
        /* reference all summary page */
        while (segno < end_segno) {
                sum_page = f2fs_get_sum_page(sbi, segno++);
+               if (IS_ERR(sum_page)) {
+                       int err = PTR_ERR(sum_page);
+
+                       end_segno = segno - 1;
+                       for (segno = start_segno; segno < end_segno; segno++) {
+                               sum_page = find_get_page(META_MAPPING(sbi),
+                                               GET_SUM_BLOCK(sbi, segno));
+                               f2fs_put_page(sum_page, 0);
+                               f2fs_put_page(sum_page, 0);
+                       }
+                       return err;
+               }
                unlock_page(sum_page);
        }
 
index 245ea6c0fcbb4b0bdae76410d344a425c426ab87..4d78da6b2c95791be8557a4cdeb7b8262505d56f 100644 (file)
@@ -126,6 +126,8 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid)
 
        /* get current nat block page with lock */
        src_page = get_current_nat_page(sbi, nid);
+       if (IS_ERR(src_page))
+               return src_page;
        dst_page = f2fs_grab_meta_page(sbi, dst_off);
        f2fs_bug_on(sbi, PageDirty(src_page));
 
@@ -2265,15 +2267,19 @@ static int __f2fs_build_free_nids(struct f2fs_sb_info *sbi,
                                                nm_i->nat_block_bitmap)) {
                        struct page *page = get_current_nat_page(sbi, nid);
 
-                       ret = scan_nat_page(sbi, page, nid);
-                       f2fs_put_page(page, 1);
+                       if (IS_ERR(page)) {
+                               ret = PTR_ERR(page);
+                       } else {
+                               ret = scan_nat_page(sbi, page, nid);
+                               f2fs_put_page(page, 1);
+                       }
 
                        if (ret) {
                                up_read(&nm_i->nat_tree_lock);
                                f2fs_bug_on(sbi, !mount);
                                f2fs_msg(sbi->sb, KERN_ERR,
                                        "NAT is corrupt, run fsck to fix it");
-                               return -EINVAL;
+                               return ret;
                        }
                }
 
@@ -2708,7 +2714,7 @@ static void __update_nat_bits(struct f2fs_sb_info *sbi, nid_t start_nid,
                __clear_bit_le(nat_index, nm_i->full_nat_bits);
 }
 
-static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
+static int __flush_nat_entry_set(struct f2fs_sb_info *sbi,
                struct nat_entry_set *set, struct cp_control *cpc)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
@@ -2732,6 +2738,9 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
                down_write(&curseg->journal_rwsem);
        } else {
                page = get_next_nat_page(sbi, start_nid);
+               if (IS_ERR(page))
+                       return PTR_ERR(page);
+
                nat_blk = page_address(page);
                f2fs_bug_on(sbi, !nat_blk);
        }
@@ -2777,12 +2786,13 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
                radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
                kmem_cache_free(nat_entry_set_slab, set);
        }
+       return 0;
 }
 
 /*
  * This function is called during the checkpointing process.
  */
-void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
@@ -2792,6 +2802,7 @@ void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        unsigned int found;
        nid_t set_idx = 0;
        LIST_HEAD(sets);
+       int err = 0;
 
        /* during unmount, let's flush nat_bits before checking dirty_nat_cnt */
        if (enabled_nat_bits(sbi, cpc)) {
@@ -2801,7 +2812,7 @@ void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        }
 
        if (!nm_i->dirty_nat_cnt)
-               return;
+               return 0;
 
        down_write(&nm_i->nat_tree_lock);
 
@@ -2824,11 +2835,16 @@ void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        }
 
        /* flush dirty nats in nat entry set */
-       list_for_each_entry_safe(set, tmp, &sets, set_list)
-               __flush_nat_entry_set(sbi, set, cpc);
+       list_for_each_entry_safe(set, tmp, &sets, set_list) {
+               err = __flush_nat_entry_set(sbi, set, cpc);
+               if (err)
+                       break;
+       }
 
        up_write(&nm_i->nat_tree_lock);
        /* Allow dirty nats by node block allocation in write_begin */
+
+       return err;
 }
 
 static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
index 6682c8d86a511a0d07f7816ef799a89a2c92a73f..b069b7d7403db499d2c1b1dd2ce01898c0427af0 100644 (file)
@@ -375,6 +375,8 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
        }
 
        sum_page = f2fs_get_sum_page(sbi, segno);
+       if (IS_ERR(sum_page))
+               return PTR_ERR(sum_page);
        sum_node = (struct f2fs_summary_block *)page_address(sum_page);
        sum = sum_node->entries[blkoff];
        f2fs_put_page(sum_page, 1);
index 97a4fae75651e6444dfd30b582b46e23b66ece48..d33e9d0d5d47a5cc4c5f2fa55f65115e48632d21 100644 (file)
@@ -2429,6 +2429,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type)
        __next_free_blkoff(sbi, curseg, 0);
 
        sum_page = f2fs_get_sum_page(sbi, new_segno);
+       f2fs_bug_on(sbi, IS_ERR(sum_page));
        sum_node = (struct f2fs_summary_block *)page_address(sum_page);
        memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
        f2fs_put_page(sum_page, 1);
@@ -3903,6 +3904,8 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
 
                        se = &sit_i->sentries[start];
                        page = get_current_sit_page(sbi, start);
+                       if (IS_ERR(page))
+                               return PTR_ERR(page);
                        sit_blk = (struct f2fs_sit_block *)page_address(page);
                        sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
                        f2fs_put_page(page, 1);