]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
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, 28 Sep 2018 17:39:58 +0000 (10:39 -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 d312d2829d5a22b1e4c987e3d78f0b3c94188555..f4b9b81e3ed671330c2a176829876522d3c28f7f 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 b32fd9f7da95aad45af537a5a19c859877998a75..dcfa6a94676eeb99d9e8a2434a6b117bc9984b80 100644 (file)
@@ -2911,7 +2911,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 77ffa8045a3b4858eebec748b7d8ae8b9195e010..247b31e733032dc21bc32e8f5617b0297dfacfb3 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 8f4e12819c94029e8b0a3cb9bf4d3e5b9e65813e..3994b44541b4716dffaa1b36c065fa8244ac7a24 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 fb24a6d734e90b313d6ae629f2df2d3fe1424b83..93e3b6c46aae0ca4fb3abcaf2a94155d4bf5f302 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);