fsck.f2fs: select to update the latest valid summary

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>
diff --git a/fsck/fsck.c b/fsck/fsck.c
index b15edbe..bbd4cab 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -191,6 +191,47 @@
 	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 @@
 			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);