Skip to content

Commit 1773f63

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: handle nat.blkaddr corruption in f2fs_get_node_info()
F2FS-fs (dm-55): access invalid blkaddr:972878540 Call trace: dump_backtrace+0xec/0x128 show_stack+0x18/0x28 dump_stack_lvl+0x40/0x88 dump_stack+0x18/0x24 __f2fs_is_valid_blkaddr+0x360/0x3b4 f2fs_is_valid_blkaddr+0x10/0x20 f2fs_get_node_info+0x21c/0x60c __write_node_page+0x15c/0x734 f2fs_sync_node_pages+0x4f8/0x700 f2fs_write_checkpoint+0x4a8/0x99c __checkpoint_and_complete_reqs+0x7c/0x20c issue_checkpoint_thread+0x4c/0xd8 kthread+0x11c/0x1b0 ret_from_fork+0x10/0x20 If nat.blkaddr is corrupted, during checkpoint, f2fs_sync_node_pages() will loop to flush node page w/ corrupted nat.blkaddr. Although, it tags SBI_NEED_FSCK, checkpoint can not persist it due to deadloop. Let's call f2fs_handle_error(, ERROR_INCONSISTENT_NAT) to record such error into superblock, it expects fsck can detect the error and repair inconsistent nat.blkaddr after device reboot. Note that, let's add sanity check in f2fs_get_node_info() to detect in-memory nat.blkaddr inconsistency, but only if CONFIG_F2FS_CHECK_FS is enabled. Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent 8142daf commit 1773f63

File tree

1 file changed

+21
-8
lines changed

1 file changed

+21
-8
lines changed

fs/f2fs/node.c

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -555,8 +555,8 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
555555
struct f2fs_nat_entry ne;
556556
struct nat_entry *e;
557557
pgoff_t index;
558-
block_t blkaddr;
559558
int i;
559+
bool need_cache = true;
560560

561561
ni->flag = 0;
562562
ni->nid = nid;
@@ -569,6 +569,10 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
569569
ni->blk_addr = nat_get_blkaddr(e);
570570
ni->version = nat_get_version(e);
571571
f2fs_up_read(&nm_i->nat_tree_lock);
572+
if (IS_ENABLED(CONFIG_F2FS_CHECK_FS)) {
573+
need_cache = false;
574+
goto sanity_check;
575+
}
572576
return 0;
573577
}
574578

@@ -594,7 +598,7 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
594598
up_read(&curseg->journal_rwsem);
595599
if (i >= 0) {
596600
f2fs_up_read(&nm_i->nat_tree_lock);
597-
goto cache;
601+
goto sanity_check;
598602
}
599603

600604
/* Fill node_info from nat page */
@@ -609,14 +613,23 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
609613
ne = nat_blk->entries[nid - start_nid];
610614
node_info_from_raw_nat(ni, &ne);
611615
f2fs_folio_put(folio, true);
612-
cache:
613-
blkaddr = le32_to_cpu(ne.block_addr);
614-
if (__is_valid_data_blkaddr(blkaddr) &&
615-
!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE))
616-
return -EFAULT;
616+
sanity_check:
617+
if (__is_valid_data_blkaddr(ni->blk_addr) &&
618+
!f2fs_is_valid_blkaddr(sbi, ni->blk_addr,
619+
DATA_GENERIC_ENHANCE)) {
620+
set_sbi_flag(sbi, SBI_NEED_FSCK);
621+
f2fs_err_ratelimited(sbi,
622+
"f2fs_get_node_info of %pS: inconsistent nat entry, "
623+
"ino:%u, nid:%u, blkaddr:%u, ver:%u, flag:%u",
624+
__builtin_return_address(0),
625+
ni->ino, ni->nid, ni->blk_addr, ni->version, ni->flag);
626+
f2fs_handle_error(sbi, ERROR_INCONSISTENT_NAT);
627+
return -EFSCORRUPTED;
628+
}
617629

618630
/* cache nat entry */
619-
cache_nat_entry(sbi, nid, &ne);
631+
if (need_cache)
632+
cache_nat_entry(sbi, nid, &ne);
620633
return 0;
621634
}
622635

0 commit comments

Comments
 (0)