fsck.f2fs: remove corrupted nid entry from indirect/double-indirect node
authorSheng Yong <shengyong1@huawei.com>
Fri, 19 Feb 2016 17:14:58 +0000 (17:14 +0000)
committerJaegeuk Kim <jaegeuk@kernel.org>
Mon, 22 Feb 2016 17:22:19 +0000 (09:22 -0800)
For indirect/double-indirect node, if the blk_addr in its nat entry is
corrupted, fsck could figure this out and nullify the nat entry. However,
the indirect/double-indirect node still keeps the corrupted nid. As a
result, fsck reports valid blkaddr but fixes nothing each time during
scanning all nodes, like:

=============================
[ASSERT] (sanity_check_nid: 356)  --> blkaddres is not valid. [0x0]
delete in.nid[i] = 0;
[ASSERT] (sanity_check_nid: 356)  --> blkaddres is not valid. [0x0]
delete in.nid[i] = 0;

[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..] [0xa51b]
[FSCK] valid_node_count matcing with CP (de lookup)   [Ok..] [0x98]
[FSCK] valid_node_count matcing with CP (nat lookup)  [Ok..] [0x98]
[FSCK] valid_inode_count matched with CP              [Ok..] [0x7b]
[FSCK] free segment_count matched with CP             [Ok..] [0x1a]
[FSCK] next block offset is free                      [Ok..]
[FSCK] fixing SIT types
[FSCK] other corrupted bugs                           [Fail]
=============================

So let's clean it.

Reported-by: Chen Yinchao <chengyinchao@huawei.com>
Signed-off-by: Liu Xue <liuxueliu.liu@huawei.com>
Signed-off-by: Sheng Yong <shengyong1@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fsck/fsck.c

index 6451595..ca8ea15 100644 (file)
@@ -834,7 +834,7 @@ int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
                enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt,
                struct child_info *child, struct extent_info *i_ext)
 {
-       int ret;
+       int need_fix = 0, ret;
        int i = 0;
 
        for (i = 0 ; i < NIDS_PER_BLOCK; i++) {
@@ -846,9 +846,26 @@ int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
                                i_ext);
                if (!ret)
                        *blk_cnt = *blk_cnt + 1;
-               else if (ret == -EINVAL)
-                       printf("delete in.nid[i] = 0;\n");
+               else if (ret == -EINVAL) {
+                       if (!config.fix_on)
+                               printf("should delete in.nid[i] = 0;\n");
+                       else {
+                               node_blk->in.nid[i] = 0;
+                               need_fix = 1;
+                               FIX_MSG("Set indirect node 0x%x -> 0\n", i);
+                       }
+               }
+       }
+
+       if (need_fix && !config.ro) {
+               struct node_info ni;
+               nid_t nid = le32_to_cpu(node_blk->footer.nid);
+
+               get_node_info(sbi, nid, &ni);
+               ret = dev_write_block(node_blk, ni.blk_addr);
+               ASSERT(ret >= 0);
        }
+
        return 0;
 }
 
@@ -857,7 +874,7 @@ int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
                struct child_info *child, struct extent_info *i_ext)
 {
        int i = 0;
-       int ret = 0;
+       int need_fix = 0, ret = 0;
 
        for (i = 0; i < NIDS_PER_BLOCK; i++) {
                if (le32_to_cpu(node_blk->in.nid[i]) == 0x0)
@@ -868,9 +885,26 @@ int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
                                i_ext);
                if (!ret)
                        *blk_cnt = *blk_cnt + 1;
-               else if (ret == -EINVAL)
-                       printf("delete in.nid[i] = 0;\n");
+               else if (ret == -EINVAL) {
+                       if (!config.fix_on)
+                               printf("should delete in.nid[i] = 0;\n");
+                       else {
+                               node_blk->in.nid[i] = 0;
+                               need_fix = 1;
+                               FIX_MSG("Set double indirect node 0x%x -> 0\n", i);
+                       }
+               }
        }
+
+       if (need_fix && !config.ro) {
+               struct node_info ni;
+               nid_t nid = le32_to_cpu(node_blk->footer.nid);
+
+               get_node_info(sbi, nid, &ni);
+               ret = dev_write_block(node_blk, ni.blk_addr);
+               ASSERT(ret >= 0);
+       }
+
        return 0;
 }