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). Clear dent flag of the node block to fix this issue. Test Step: 1.Modify files and induce SPO to generate fsync inode list. blkaddr: 0x15828, ino: 1378, is_inode: 1, is_fsync: 2, is_dent: 0
2.Use inject.f2fs to set dent flag for a fsync inode. inject.f2fs --cp 0 --mb flag --idx 2 --val 7 /dev/vda Info: inject blkaddr[2] flag of cp 2: 0x3 -> 0x7 3.Boot verification, System fails to mount during recovery: f2fs_recover_inode_page:ino: 1378, ni.blkaddr: 0x1581a, old_ni.blk_addr != NULL_ADDR F2FS-fs (vda): Cannot recover all fsync data errno=-22 4.Run fsck fsck.f2fs -f /dev/vda [ASSERT] (f2fs_find_fsync_inode:3924) --> Invalid dent flag: blkaddr: 0x15828, ino: 1378, is_dent: 4, nat entry blkaddr: 0x1581a [FIX] (f2fs_find_fsync_inode:3931) --> Clear dent flag: blkaddr: 0x15828, ino: 1378 After this fix, the system boots normally. Signed-off-by: Sheng Yong <[email protected]> Signed-off-by: Yongpeng Yang <[email protected]> Signed-off-by: Jinbao Liu <[email protected]> --- v3: - Add test steps to verify the effect. --- 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 | 19 ++++++++++++++++++- fsck/node.h | 13 +++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/fsck/mount.c b/fsck/mount.c index 6f640a0..3385489 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,24 @@ 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: 0x%x, " + "ino: %u, is_dent: %d, nat entry blkaddr: 0x%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()) { + FIX_MSG("Clear dent flag: blkaddr: 0x%x, ino: %u\n", + blkaddr, ino_of_node(node_blk)); + set_dentry_mark(node_blk, 0); + err = update_inode(sbi, node_blk, &blkaddr); + ASSERT(err >= 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) -- 2.25.1 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
