Jinbao,
On 1/12/2026 2:11 PM, liujinbao1 wrote:
From: liujinbao1 <[email protected]>
During SPO tests, when mounting F2FS, an -EINVAL error was returned.
The issue originates from the f2fs_recover_inode_page function's
check, where old_ni.blk_addr != NULL_ADDR under the conditions of
IS_INODE(folio) && is_dent_dnode(folio).
Add detection and repair for this scenario in fsck.
Signed-off-by: Sheng Yong <[email protected]>
Signed-off-by: Yongpeng Yang <[email protected]>
Signed-off-by: Jinbao Liu <[email protected]>
---
v2:
- Clear the node_blk dent flag, proceed with recovery
of this and subsequent data.
---
v1:
- Clear the node_blk fsync flag, set next_blkaddr=NULL,
skip recovery of this and later data.
---
fsck/mount.c | 21 ++++++++++++++++++++-
fsck/node.h | 13 +++++++++++++
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/fsck/mount.c b/fsck/mount.c
index 6f640a0..8254644 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -3878,6 +3878,7 @@ int f2fs_find_fsync_inode(struct f2fs_sb_info *sbi,
struct list_head *head)
while (1) {
struct fsync_inode_entry *entry;
+ struct f2fs_nat_entry nat_entry;
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
break;
@@ -3902,8 +3903,26 @@ int f2fs_find_fsync_inode(struct f2fs_sb_info *sbi,
struct list_head *head)
}
entry->blkaddr = blkaddr;
- if (IS_INODE(node_blk) && is_dent_dnode(node_blk))
+ if (IS_INODE(node_blk) && is_dent_dnode(node_blk)) {
+ get_nat_entry(sbi, ino_of_node(node_blk), &nat_entry);
+ if (is_valid_data_blkaddr(nat_entry.block_addr)) {
+ ASSERT_MSG("Invalid dent flag: blkaddr = %#x, "
+ "ino: %u, is_dent:%d, nat entry blkaddr is
%#X\n",
+ blkaddr, ino_of_node(node_blk),
is_dent_dnode(node_blk),
+ nat_entry.block_addr);
+ if (c.fix_on && f2fs_dev_is_writable()) {
+ int ret = 0;
int ret;
No need to initialize ret variable.
BTW, can you please use inject.f2fs to simulate such inconsistent image,
and use the image to test this fix? it will be better to include the
testcase and result in commit message. What do you think?
Thanks,
+
+ FIX_MSG("Clear dent flag: blkaddr:%#x, ino:
%u\n",
+ blkaddr, ino_of_node(node_blk));
+ set_dentry_mark(node_blk, 0);
+ ret = update_inode(sbi, node_blk,
blkaddr);
+ ASSERT(ret >= 0);
+ goto next;
+ }
+ }
entry->last_dentry = blkaddr;
+ }
next:
blkaddr = next_blkaddr_of_node(node_blk);
diff --git a/fsck/node.h b/fsck/node.h
index 19f1e57..f3e2c46 100644
--- a/fsck/node.h
+++ b/fsck/node.h
@@ -173,6 +173,19 @@ static inline void set_cold_node(struct f2fs_node *rn,
bool is_dir)
F2FS_NODE_FOOTER(rn)->flag = cpu_to_le32(flag);
}
+static inline void set_mark(struct f2fs_node *rn, int mark, int type)
+{
+ unsigned int flag = le32_to_cpu(F2FS_NODE_FOOTER(rn)->flag);
+
+ if (mark)
+ flag |= (1 << type);
+ else
+ flag &= ~(1 << type);
+ F2FS_NODE_FOOTER(rn)->flag = cpu_to_le32(flag);
+}
+
+#define set_dentry_mark(page, mark) set_mark(page, mark, DENT_BIT_SHIFT)
+
#define is_fsync_dnode(node_blk) is_node(node_blk, FSYNC_BIT_SHIFT)
#define is_dent_dnode(node_blk) is_node(node_blk,
DENT_BIT_SHIFT)
_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel