mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-23 07:23:12 +02:00
f2fs: handle nat.blkaddr corruption in f2fs_get_node_info()
[ Upstream commit 1773f63d10
]
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 <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
e229f96c06
commit
53bac3cbfa
|
@ -555,8 +555,8 @@ int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
|
||||||
struct f2fs_nat_entry ne;
|
struct f2fs_nat_entry ne;
|
||||||
struct nat_entry *e;
|
struct nat_entry *e;
|
||||||
pgoff_t index;
|
pgoff_t index;
|
||||||
block_t blkaddr;
|
|
||||||
int i;
|
int i;
|
||||||
|
bool need_cache = true;
|
||||||
|
|
||||||
ni->flag = 0;
|
ni->flag = 0;
|
||||||
ni->nid = nid;
|
ni->nid = nid;
|
||||||
|
@ -569,6 +569,10 @@ retry:
|
||||||
ni->blk_addr = nat_get_blkaddr(e);
|
ni->blk_addr = nat_get_blkaddr(e);
|
||||||
ni->version = nat_get_version(e);
|
ni->version = nat_get_version(e);
|
||||||
f2fs_up_read(&nm_i->nat_tree_lock);
|
f2fs_up_read(&nm_i->nat_tree_lock);
|
||||||
|
if (IS_ENABLED(CONFIG_F2FS_CHECK_FS)) {
|
||||||
|
need_cache = false;
|
||||||
|
goto sanity_check;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,7 +598,7 @@ retry:
|
||||||
up_read(&curseg->journal_rwsem);
|
up_read(&curseg->journal_rwsem);
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
f2fs_up_read(&nm_i->nat_tree_lock);
|
f2fs_up_read(&nm_i->nat_tree_lock);
|
||||||
goto cache;
|
goto sanity_check;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill node_info from nat page */
|
/* Fill node_info from nat page */
|
||||||
|
@ -609,14 +613,23 @@ retry:
|
||||||
ne = nat_blk->entries[nid - start_nid];
|
ne = nat_blk->entries[nid - start_nid];
|
||||||
node_info_from_raw_nat(ni, &ne);
|
node_info_from_raw_nat(ni, &ne);
|
||||||
f2fs_folio_put(folio, true);
|
f2fs_folio_put(folio, true);
|
||||||
cache:
|
sanity_check:
|
||||||
blkaddr = le32_to_cpu(ne.block_addr);
|
if (__is_valid_data_blkaddr(ni->blk_addr) &&
|
||||||
if (__is_valid_data_blkaddr(blkaddr) &&
|
!f2fs_is_valid_blkaddr(sbi, ni->blk_addr,
|
||||||
!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE))
|
DATA_GENERIC_ENHANCE)) {
|
||||||
return -EFAULT;
|
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||||
|
f2fs_err_ratelimited(sbi,
|
||||||
|
"f2fs_get_node_info of %pS: inconsistent nat entry, "
|
||||||
|
"ino:%u, nid:%u, blkaddr:%u, ver:%u, flag:%u",
|
||||||
|
__builtin_return_address(0),
|
||||||
|
ni->ino, ni->nid, ni->blk_addr, ni->version, ni->flag);
|
||||||
|
f2fs_handle_error(sbi, ERROR_INCONSISTENT_NAT);
|
||||||
|
return -EFSCORRUPTED;
|
||||||
|
}
|
||||||
|
|
||||||
/* cache nat entry */
|
/* cache nat entry */
|
||||||
cache_nat_entry(sbi, nid, &ne);
|
if (need_cache)
|
||||||
|
cache_nat_entry(sbi, nid, &ne);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user