fsck.f2fs: select to update the latest valid summary
authorJaegeuk Kim <jaegeuk@kernel.org>
Thu, 2 Jul 2015 01:19:53 +0000 (18:19 -0700)
committerJaegeuk Kim <jaegeuk@kernel.org>
Thu, 2 Jul 2015 01:53:58 +0000 (18:53 -0700)
If two dnode blocks indicate one block address, it needs to keep the latest
valid address selectively.

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fsck/fsck.c

index b15edbe..bbd4cab 100644 (file)
@@ -191,6 +191,47 @@ out:
        return ret;
 }
 
+static int is_valid_summary(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
+                                                       u32 blk_addr)
+{
+       u16 ofs_in_node = le16_to_cpu(sum->ofs_in_node);
+       u32 nid = le32_to_cpu(sum->nid);
+       struct f2fs_node *node_blk = NULL;
+       __le32 target_blk_addr;
+       struct node_info ni;
+       int ret = 0;
+
+       node_blk = (struct f2fs_node *)calloc(BLOCK_SZ, 1);
+       ASSERT(node_blk != NULL);
+
+       if (!IS_VALID_NID(sbi, nid))
+               goto out;
+
+       get_node_info(sbi, nid, &ni);
+
+       if (!IS_VALID_BLK_ADDR(sbi, ni.blk_addr))
+               goto out;
+
+       /* read node_block */
+       ret = dev_read_block(node_blk, ni.blk_addr);
+       ASSERT(ret >= 0);
+
+       if (le32_to_cpu(node_blk->footer.nid) != nid)
+               goto out;
+
+       /* check its block address */
+       if (node_blk->footer.nid == node_blk->footer.ino)
+               target_blk_addr = node_blk->i.i_addr[ofs_in_node];
+       else
+               target_blk_addr = node_blk->dn.addr[ofs_in_node];
+
+       if (blk_addr == le32_to_cpu(target_blk_addr))
+               ret = 1;
+out:
+       free(node_blk);
+       return ret;
+}
+
 static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
                u32 parent_nid, u16 idx_in_node, u8 version)
 {
@@ -238,6 +279,9 @@ static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr,
                        DBG(0, "Target data block addr    [0x%x]\n", blk_addr);
                        ASSERT_MSG("Invalid data seg summary\n");
                        ret = -EINVAL;
+               } else if (is_valid_summary(sbi, sum_entry, blk_addr)) {
+                       /* delete wrong index */
+                       ret = -EINVAL;
                } else {
                        FIX_MSG("Set data summary 0x%x -> [0x%x] [0x%x] [0x%x]",
                                        segno, parent_nid, version, idx_in_node);