mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git
synced 2024-12-02 22:23:54 +08:00
fsck.f2fs: lookup and relink root inode
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. Before: Info: checkpoint state = 185 : trimmed nat_bits compacted_summary unmount [lookup_nat_in_journal:3085] ==> Found nid [0x3] in nat cache [ASSERT] (sanity_check_nat: 404) --> nid->blk_addr is 0x0. [0x3] Info: root inode is corrupted, search and relink it Info: possible root inode blkaddr: 0x5a00 [lookup_nat_in_journal:3085] ==> Found nid [0x3] in nat cache [ASSERT] (sanity_check_nat: 404) --> nid->blk_addr is 0x0. [0x3] [FSCK] Max image size: 94 MB, Free space: 12194 MB [FSCK] Unreachable nat entries [Ok..] [0x0] [FSCK] SIT valid block bitmap checking [Fail] [FSCK] Hard link checking for regular file [Ok..] [0x0] [FSCK] valid_block_count matching with CP [Fail] [0x2, 0x0] [FSCK] valid_node_count matching with CP (de lookup) [Fail] [0x1, 0x0] [FSCK] valid_node_count matching with CP (nat lookup) [Fail] [0x1, 0x0] [FSCK] valid_inode_count matched with CP [Fail] [0x1, 0x0] [FSCK] free segment_count matched with CP [Ok..] [0x17cd] [FSCK] next block offset is free [Ok..] [FSCK] fixing SIT types [FSCK] other corrupted bugs [Fail] Do you want to fix this partition? [Y/N] Y After: Info: checkpoint state = 185 : trimmed nat_bits compacted_summary unmount [lookup_nat_in_journal:3085] ==> Found nid [0x3] in nat cache [ASSERT] (sanity_check_nat: 404) --> nid->blk_addr is 0x0. [0x3] Info: root inode is corrupted, search and relink it Info: possible root inode blkaddr: 0x5a00 [FIX] (fsck_chk_root_inode: 730) --> Relink root inode, blkaddr: 0x5a00 update nat(nid:3) blkaddr [0x5a00] in journal [fsck_chk_dentry_blk:1978] [ 1] Dentry Block [0x6000] Done : dentries:0 in 214 slots (len:255) [fsck_chk_inode_blk:1244] Directory Inode: 0x3 [] depth: 1 has 0 files [FSCK] Max image size: 94 MB, Free space: 12194 MB [FSCK] Unreachable nat entries [Ok..] [0x0] [FSCK] SIT valid block bitmap checking [Ok..] [FSCK] Hard link checking for regular file [Ok..] [0x0] [FSCK] valid_block_count matching with CP [Ok..] [0x2] [FSCK] valid_node_count matching with CP (de lookup) [Ok..] [0x1] [FSCK] valid_node_count matching with CP (nat lookup) [Ok..] [0x1] [FSCK] valid_inode_count matched with CP [Ok..] [0x1] [FSCK] free segment_count matched with CP [Ok..] [0x17cd] [FSCK] next block offset is free [Ok..] [FSCK] fixing SIT types [FSCK] other corrupted bugs [Fail] Info: flush_journal_entries() n_nats: 1, n_sits: 6 Info: Duplicate valid checkpoint to mirror position 512 -> 1024 [write_nat_bits:1737] Writing NAT bits pages, at offset 0x000003ff Info: Write valid nat_bits in checkpoint Info: write_checkpoint() cur_cp:1 [write_nat_bits:1737] Writing NAT bits pages, at offset 0x000003ff Info: Write valid nat_bits in checkpoint Info: fix_checkpoint() cur_cp:1 Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
cf3a7c30e3
commit
75f7c586c3
148
fsck/fsck.c
148
fsck/fsck.c
@ -386,14 +386,9 @@ err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid,
|
||||
struct f2fs_node *node_blk,
|
||||
enum FILE_TYPE ftype, enum NODE_TYPE ntype,
|
||||
struct node_info *ni)
|
||||
static int sanity_check_nat(struct f2fs_sb_info *sbi, u32 nid,
|
||||
struct node_info *ni)
|
||||
{
|
||||
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
|
||||
int ret;
|
||||
|
||||
if (!IS_VALID_NID(sbi, nid)) {
|
||||
ASSERT_MSG("nid is not valid. [0x%x]", nid);
|
||||
return -EINVAL;
|
||||
@ -415,6 +410,28 @@ static int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fsck_sanity_check_nat(struct f2fs_sb_info *sbi, u32 nid)
|
||||
{
|
||||
struct node_info ni;
|
||||
|
||||
return sanity_check_nat(sbi, nid, &ni);
|
||||
}
|
||||
|
||||
static int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid,
|
||||
struct f2fs_node *node_blk,
|
||||
enum FILE_TYPE ftype, enum NODE_TYPE ntype,
|
||||
struct node_info *ni)
|
||||
{
|
||||
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
|
||||
int ret;
|
||||
|
||||
ret = sanity_check_nat(sbi, nid, ni);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dev_read_block(node_blk, ni->blk_addr);
|
||||
ASSERT(ret >= 0);
|
||||
|
||||
@ -609,6 +626,123 @@ err:
|
||||
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_chk_root_inode(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;
|
||||
nid_t root_ino = sbi->root_ino_num;
|
||||
u64 last_ctime = 0;
|
||||
u32 last_ctime_nsec = 0;
|
||||
int ret = -EINVAL;
|
||||
|
||||
node_blk = calloc(BLOCK_SZ, 1);
|
||||
ASSERT(node_blk);
|
||||
|
||||
MSG(0, "Info: root inode is corrupted, search and relink it\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;
|
||||
|
||||
ret = dev_read_block(node_blk, blkaddr);
|
||||
ASSERT(ret >= 0);
|
||||
|
||||
if (le32_to_cpu(node_blk->footer.ino) !=
|
||||
root_ino ||
|
||||
le32_to_cpu(node_blk->footer.nid) !=
|
||||
root_ino)
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == sbi->blocks_per_seg)
|
||||
continue;
|
||||
|
||||
if (valid_bitmap) {
|
||||
last_blkaddr = blkaddr;
|
||||
MSG(0, "Info: possible root inode blkaddr: 0x%x\n",
|
||||
last_blkaddr);
|
||||
goto fix;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
MSG(0, "Info: possible root inode blkaddr: %u\n",
|
||||
last_blkaddr);
|
||||
}
|
||||
|
||||
if (valid_bitmap) {
|
||||
valid_bitmap = false;
|
||||
goto retry;
|
||||
}
|
||||
fix:
|
||||
if (!last_blkaddr) {
|
||||
MSG(0, "Info: there is no valid root inode\n");
|
||||
} else if (c.fix_on) {
|
||||
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
|
||||
|
||||
FIX_MSG("Relink root inode, blkaddr: 0x%x", last_blkaddr);
|
||||
update_nat_journal_blkaddr(sbi, root_ino, last_blkaddr);
|
||||
update_nat_blkaddr(sbi, root_ino, root_ino, last_blkaddr);
|
||||
|
||||
if (f2fs_test_bit(root_ino, fsck->nat_area_bitmap))
|
||||
f2fs_clear_bit(root_ino, fsck->nat_area_bitmap);
|
||||
fsck->chk.valid_nat_entry_cnt++;
|
||||
|
||||
if (!f2fs_test_sit_bitmap(sbi, last_blkaddr))
|
||||
f2fs_set_sit_bitmap(sbi, last_blkaddr);
|
||||
ret = 0;
|
||||
}
|
||||
free(node_blk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void get_extent_info(struct extent_info *ext,
|
||||
struct f2fs_extent *i_ext)
|
||||
{
|
||||
|
@ -167,9 +167,11 @@ extern int fsck_chk_quota_node(struct f2fs_sb_info *);
|
||||
extern int fsck_chk_quota_files(struct f2fs_sb_info *);
|
||||
extern int fsck_sanity_check_nid(struct f2fs_sb_info *, u32,
|
||||
enum FILE_TYPE, enum NODE_TYPE);
|
||||
extern int fsck_sanity_check_nat(struct f2fs_sb_info *sbi, u32 nid);
|
||||
extern int fsck_chk_node_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32,
|
||||
enum FILE_TYPE, enum NODE_TYPE, u32 *,
|
||||
struct f2fs_compr_blk_cnt *, struct child_info *);
|
||||
extern int fsck_chk_root_inode(struct f2fs_sb_info *);
|
||||
extern void fsck_chk_inode_blk(struct f2fs_sb_info *, u32, enum FILE_TYPE,
|
||||
struct f2fs_node *, u32 *, struct f2fs_compr_blk_cnt *,
|
||||
struct node_info *, struct child_info *);
|
||||
@ -208,6 +210,8 @@ extern void update_sum_entry(struct f2fs_sb_info *, block_t,
|
||||
struct f2fs_summary *);
|
||||
extern void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
|
||||
extern void nullify_nat_entry(struct f2fs_sb_info *, u32);
|
||||
extern void update_nat_journal_blkaddr(struct f2fs_sb_info *sbi, u32 nid,
|
||||
block_t blkaddr);
|
||||
extern void rewrite_sit_area_bitmap(struct f2fs_sb_info *);
|
||||
extern void build_nat_area_bitmap(struct f2fs_sb_info *);
|
||||
extern void build_sit_area_bitmap(struct f2fs_sb_info *);
|
||||
|
@ -885,6 +885,10 @@ static int do_fsck(struct f2fs_sb_info *sbi)
|
||||
}
|
||||
}
|
||||
fsck_chk_orphan_node(sbi);
|
||||
|
||||
if (fsck_sanity_check_nat(sbi, sbi->root_ino_num))
|
||||
fsck_chk_root_inode(sbi);
|
||||
|
||||
fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num,
|
||||
F2FS_FT_DIR, TYPE_INODE, &blk_cnt, &cbc, NULL);
|
||||
fsck_chk_quota_files(sbi);
|
||||
|
18
fsck/mount.c
18
fsck/mount.c
@ -3132,6 +3132,24 @@ void nullify_nat_entry(struct f2fs_sb_info *sbi, u32 nid)
|
||||
free(nat_block);
|
||||
}
|
||||
|
||||
void update_nat_journal_blkaddr(struct f2fs_sb_info *sbi, u32 nid,
|
||||
block_t blkaddr)
|
||||
{
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
|
||||
struct f2fs_journal *journal = &curseg->sum_blk->journal;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nats_in_cursum(journal); i++) {
|
||||
if (le32_to_cpu(nid_in_journal(journal, i)) == nid) {
|
||||
nat_in_journal(journal, i).block_addr =
|
||||
cpu_to_le32(blkaddr);
|
||||
MSG(0, "update nat(nid:%d) blkaddr [0x%x] in journal\n",
|
||||
nid, blkaddr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void duplicate_checkpoint(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
|
||||
|
Loading…
Reference in New Issue
Block a user