Commit edc55aaf authored by Jaegeuk Kim's avatar Jaegeuk Kim

f2fs: avoid f2fs_bug_on if f2fs_get_meta_page_nofail got EIO

This patch avoids BUG_ON when f2fs_get_meta_page_nofail got EIO during
xfstests/generic/475.
Reviewed-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 4a1728ca
...@@ -119,11 +119,8 @@ struct page *f2fs_get_meta_page_nofail(struct f2fs_sb_info *sbi, pgoff_t index) ...@@ -119,11 +119,8 @@ struct page *f2fs_get_meta_page_nofail(struct f2fs_sb_info *sbi, pgoff_t index)
if (PTR_ERR(page) == -EIO && if (PTR_ERR(page) == -EIO &&
++count <= DEFAULT_RETRY_IO_COUNT) ++count <= DEFAULT_RETRY_IO_COUNT)
goto retry; goto retry;
f2fs_stop_checkpoint(sbi, false); f2fs_stop_checkpoint(sbi, false);
f2fs_bug_on(sbi, 1);
} }
return page; return page;
} }
...@@ -1496,7 +1493,10 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -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); ckpt->checkpoint_ver = cpu_to_le64(++ckpt_ver);
/* write cached NAT/SIT entries to NAT/SIT area */ /* 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); f2fs_flush_sit_entries(sbi, cpc);
/* unlock all the fs_lock[] in do_checkpoint() */ /* 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) ...@@ -1505,7 +1505,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
f2fs_release_discard_addrs(sbi); f2fs_release_discard_addrs(sbi);
else else
f2fs_clear_prefree_segments(sbi, cpc); f2fs_clear_prefree_segments(sbi, cpc);
stop:
unblock_operations(sbi); unblock_operations(sbi);
stat_inc_cp_count(sbi->stat_info); stat_inc_cp_count(sbi->stat_info);
......
...@@ -2911,7 +2911,7 @@ int f2fs_recover_xattr_data(struct inode *inode, struct page *page); ...@@ -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_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page);
int f2fs_restore_node_summary(struct f2fs_sb_info *sbi, int f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
unsigned int segno, struct f2fs_summary_block *sum); 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); int f2fs_build_node_manager(struct f2fs_sb_info *sbi);
void f2fs_destroy_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); int __init f2fs_create_node_manager_caches(void);
......
...@@ -1066,6 +1066,18 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, ...@@ -1066,6 +1066,18 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
/* reference all summary page */ /* reference all summary page */
while (segno < end_segno) { while (segno < end_segno) {
sum_page = f2fs_get_sum_page(sbi, 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); unlock_page(sum_page);
} }
......
...@@ -126,6 +126,8 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid) ...@@ -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 */ /* get current nat block page with lock */
src_page = get_current_nat_page(sbi, nid); 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); dst_page = f2fs_grab_meta_page(sbi, dst_off);
f2fs_bug_on(sbi, PageDirty(src_page)); f2fs_bug_on(sbi, PageDirty(src_page));
...@@ -2265,15 +2267,19 @@ static int __f2fs_build_free_nids(struct f2fs_sb_info *sbi, ...@@ -2265,15 +2267,19 @@ static int __f2fs_build_free_nids(struct f2fs_sb_info *sbi,
nm_i->nat_block_bitmap)) { nm_i->nat_block_bitmap)) {
struct page *page = get_current_nat_page(sbi, nid); struct page *page = get_current_nat_page(sbi, nid);
ret = scan_nat_page(sbi, page, nid); if (IS_ERR(page)) {
f2fs_put_page(page, 1); ret = PTR_ERR(page);
} else {
ret = scan_nat_page(sbi, page, nid);
f2fs_put_page(page, 1);
}
if (ret) { if (ret) {
up_read(&nm_i->nat_tree_lock); up_read(&nm_i->nat_tree_lock);
f2fs_bug_on(sbi, !mount); f2fs_bug_on(sbi, !mount);
f2fs_msg(sbi->sb, KERN_ERR, f2fs_msg(sbi->sb, KERN_ERR,
"NAT is corrupt, run fsck to fix it"); "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, ...@@ -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); __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 nat_entry_set *set, struct cp_control *cpc)
{ {
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); 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, ...@@ -2732,6 +2738,9 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
down_write(&curseg->journal_rwsem); down_write(&curseg->journal_rwsem);
} else { } else {
page = get_next_nat_page(sbi, start_nid); page = get_next_nat_page(sbi, start_nid);
if (IS_ERR(page))
return PTR_ERR(page);
nat_blk = page_address(page); nat_blk = page_address(page);
f2fs_bug_on(sbi, !nat_blk); f2fs_bug_on(sbi, !nat_blk);
} }
...@@ -2777,12 +2786,13 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi, ...@@ -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); radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
kmem_cache_free(nat_entry_set_slab, set); kmem_cache_free(nat_entry_set_slab, set);
} }
return 0;
} }
/* /*
* This function is called during the checkpointing process. * 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 f2fs_nm_info *nm_i = NM_I(sbi);
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); 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) ...@@ -2792,6 +2802,7 @@ void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
unsigned int found; unsigned int found;
nid_t set_idx = 0; nid_t set_idx = 0;
LIST_HEAD(sets); LIST_HEAD(sets);
int err = 0;
/* during unmount, let's flush nat_bits before checking dirty_nat_cnt */ /* during unmount, let's flush nat_bits before checking dirty_nat_cnt */
if (enabled_nat_bits(sbi, cpc)) { if (enabled_nat_bits(sbi, cpc)) {
...@@ -2801,7 +2812,7 @@ void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *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) if (!nm_i->dirty_nat_cnt)
return; return 0;
down_write(&nm_i->nat_tree_lock); 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) ...@@ -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 */ /* flush dirty nats in nat entry set */
list_for_each_entry_safe(set, tmp, &sets, set_list) list_for_each_entry_safe(set, tmp, &sets, set_list) {
__flush_nat_entry_set(sbi, set, cpc); err = __flush_nat_entry_set(sbi, set, cpc);
if (err)
break;
}
up_write(&nm_i->nat_tree_lock); up_write(&nm_i->nat_tree_lock);
/* Allow dirty nats by node block allocation in write_begin */ /* Allow dirty nats by node block allocation in write_begin */
return err;
} }
static int __get_nat_bitmaps(struct f2fs_sb_info *sbi) static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
......
...@@ -375,6 +375,8 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, ...@@ -375,6 +375,8 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
} }
sum_page = f2fs_get_sum_page(sbi, segno); 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_node = (struct f2fs_summary_block *)page_address(sum_page);
sum = sum_node->entries[blkoff]; sum = sum_node->entries[blkoff];
f2fs_put_page(sum_page, 1); f2fs_put_page(sum_page, 1);
......
...@@ -2429,6 +2429,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type) ...@@ -2429,6 +2429,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type)
__next_free_blkoff(sbi, curseg, 0); __next_free_blkoff(sbi, curseg, 0);
sum_page = f2fs_get_sum_page(sbi, new_segno); 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); sum_node = (struct f2fs_summary_block *)page_address(sum_page);
memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE); memcpy(curseg->sum_blk, sum_node, SUM_ENTRY_SIZE);
f2fs_put_page(sum_page, 1); f2fs_put_page(sum_page, 1);
...@@ -3903,6 +3904,8 @@ static int build_sit_entries(struct f2fs_sb_info *sbi) ...@@ -3903,6 +3904,8 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
se = &sit_i->sentries[start]; se = &sit_i->sentries[start];
page = get_current_sit_page(sbi, 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_blk = (struct f2fs_sit_block *)page_address(page);
sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)]; sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, start)];
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment