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/fsck.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fsck/fsck.h | 1 + 2 files changed, 136 insertions(+) diff --git a/fsck/fsck.c b/fsck/fsck.c index 0389146..e22ed4a 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -572,6 +572,141 @@ err: return -EINVAL; } +static int is_root_nat_corrupted(struct f2fs_sb_info *sbi) +{ + struct node_info ni; + struct f2fs_node *node_blk = NULL; + int ret; + + node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1); + ASSERT(node_blk != NULL); + + ret = sanity_check_nid(sbi, sbi->root_ino_num, node_blk, + F2FS_FT_DIR, TYPE_INODE, &ni); + + free(node_blk); + return ret; +} + +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; + + if (!is_root_nat_corrupted(sbi)) + return 0; + + node_blk = calloc(BLOCK_SZ, 1); + ASSERT(node_blk); + + printf("fsck_find_and_link_root\n"); + +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 (le32_to_cpu(node_blk->footer.ino) != + sbi->root_ino_num || + le32_to_cpu(node_blk->footer.nid) != + sbi->root_ino_num) + continue; + + if (!IS_INODE(node_blk)) + continue; + + if (le32_to_cpu(node_blk->i.i_generation) || + le32_to_cpu(node_blk->i.i_namelen)) + continue; + + printf("possible valid_bitmap: %d, nid: %u, blkaddr:%u\n", + valid_bitmap, + le32_to_cpu(node_blk->footer.nid), + blkaddr); + 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 inline void get_extent_info(struct extent_info *ext, struct f2fs_extent *i_ext) { diff --git a/fsck/fsck.h b/fsck/fsck.h index 2de6f62..4ce51d7 100644 --- a/fsck/fsck.h +++ b/fsck/fsck.h @@ -150,6 +150,7 @@ extern int fsck_sanity_check_nid(struct f2fs_sb_info *, u32, extern int fsck_chk_node_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32, enum FILE_TYPE, enum NODE_TYPE, u32 *, struct child_info *); +extern int fsck_find_and_link_root(struct f2fs_sb_info *); extern void fsck_chk_inode_blk(struct f2fs_sb_info *, u32, enum FILE_TYPE, struct f2fs_node *, u32 *, struct node_info *, struct child_info *); extern int fsck_chk_dnode_blk(struct f2fs_sb_info *, struct f2fs_inode *, -- 2.18.0.rc1 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
