As Stephanos reported in mailing list: Info: checkpoint state = 1 : unmount [ASSERT] (sanity_check_nid: 362) --> nid[0x3] ino is 0
The root cause is root inode's nat entry is corrupted, this patch add logic to search root inode from all node blocks, try to relink root inode's nat to target node block. Signed-off-by: Chao Yu <[email protected]> --- fsck/main.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 145 insertions(+), 1 deletion(-) diff --git a/fsck/main.c b/fsck/main.c index cd4ca20..5bcbf39 100644 --- a/fsck/main.c +++ b/fsck/main.c @@ -614,12 +614,152 @@ void f2fs_parse_options(int argc, char *argv[]) error_out(prog); } +bool is_root_nat_corrupted(struct f2fs_sb_info *sbi) +{ + struct node_info ni; + struct f2fs_node *node_blk = NULL; + nid_t root_ino = sbi->root_ino_num; + + node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1); + ASSERT(node_blk != NULL); + + if (!IS_VALID_NID(sbi, root_ino)) { + ASSERT_MSG("nid is not valid. [0x%x]", root_ino); + goto out; + } + + get_node_info(sbi, root_ino, &ni); + if (ni.ino == 0) { + ASSERT_MSG("nid[0x%x] ino is 0", root_ino); + goto out; + } + + if (ni.blk_addr == NEW_ADDR) { + ASSERT_MSG("nid is NEW_ADDR. [0x%x]", root_ino); + goto out; + } + + if (ni.blk_addr == NULL_ADDR) { + ASSERT_MSG("nid is NULL_ADDR. [0x%x]", root_ino); + goto out; + } + + if (!IS_VALID_BLK_ADDR(sbi, ni.blk_addr)) { + ASSERT_MSG("blkaddress is not valid. [0x%x]", ni.blk_addr); + goto out; + } + free(node_blk); + return 0; +out: + free(node_blk); + return -EINVAL; +} + +static bool is_sit_bitmap_set(struct f2fs_sb_info *sbi, u32 blk_addr) +{ + struct seg_entry *se; + u32 offset; + + se = get_seg_entry(sbi, GET_SEGNO(sbi, blk_addr)); + offset = OFFSET_IN_SEG(sbi, blk_addr); + + return f2fs_test_bit(offset, + (const char *)se->cur_valid_map) != 0; +} + +int fsck_find_and_link_root(struct f2fs_sb_info *sbi) +{ + struct f2fs_node *node_blk; + int segment_count = SM_I(sbi)->main_segments; + int segno; + bool valid_bitmap = true; + block_t last_blkaddr = NULL_ADDR; + u64 last_ctime = 0; + u32 last_ctime_nsec = 0; + int ret = -EINVAL; + + node_blk = calloc(BLOCK_SZ, 1); + ASSERT(node_blk); + +retry: + for (segno = 0; segno < segment_count; segno++) { + struct seg_entry *se = get_seg_entry(sbi, segno); + block_t blkaddr = START_BLOCK(sbi, segno); + int ret; + int i; + + if (IS_DATASEG(se->type)) + continue; + + dev_readahead(blkaddr << F2FS_BLKSIZE_BITS, + sbi->blocks_per_seg << F2FS_BLKSIZE_BITS); + + for (i = 0; i < sbi->blocks_per_seg; i++, blkaddr++) { + if (valid_bitmap && !is_sit_bitmap_set(sbi, blkaddr)) + continue; + if (!valid_bitmap && is_sit_bitmap_set(sbi, blkaddr)) + continue; + ret = dev_read_block(node_blk, blkaddr); + ASSERT(ret >= 0); + + if (node_blk->footer.ino == sbi->root_ino_num && + node_blk->footer.nid == sbi->root_ino_num) + break; + } + + if (i != sbi->blocks_per_seg) { + if (valid_bitmap) { + if (c.fix_on) { + FIX_MSG("Relink root inode, blkaddr: 0x%x", + blkaddr); + update_nat_blkaddr(sbi, sbi->root_ino_num, + sbi->root_ino_num, blkaddr); + ret = 0; + } + goto out; + } else { + if (last_blkaddr == NULL_ADDR) + goto init; + if (le64_to_cpu(node_blk->i.i_ctime) < + last_ctime) + continue; + if (le64_to_cpu(node_blk->i.i_ctime) == + last_ctime && + le32_to_cpu(node_blk->i.i_ctime_nsec) <= + last_ctime_nsec) + continue; +init: + last_blkaddr = blkaddr; + last_ctime = + le64_to_cpu(node_blk->i.i_ctime); + last_ctime_nsec = + le32_to_cpu(node_blk->i.i_ctime_nsec); + } + } + } + + if (valid_bitmap) { + valid_bitmap = false; + goto retry; + } else { + if (last_blkaddr && c.fix_on) { + FIX_MSG("Relink root inode, blkaddr: 0x%x", last_blkaddr); + update_nat_blkaddr(sbi, sbi->root_ino_num, + sbi->root_ino_num, last_blkaddr); + ret = 0; + } + } +out: + free(node_blk); + return ret; +} + static void do_fsck(struct f2fs_sb_info *sbi) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); u32 flag = le32_to_cpu(ckpt->ckpt_flags); u32 blk_cnt; - errcode_t ret; + errcode_t ret = 0; fsck_init(sbi); @@ -675,6 +815,10 @@ static void do_fsck(struct f2fs_sb_info *sbi) } } fsck_chk_orphan_node(sbi); + + if (is_root_nat_corrupted(sbi)) + fsck_find_and_link_root(sbi); + fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num, F2FS_FT_DIR, TYPE_INODE, &blk_cnt, NULL); fsck_chk_quota_files(sbi); -- 2.18.0.rc1 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
