From bdb4da9e1921c2284e149b6c420ee40a0192383e Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 27 Mar 2025 13:56:06 +0800 Subject: [PATCH] f2fs: fix to set atomic write status more clear [ Upstream commit db03c20c0850dc8d2bcabfa54b9438f7d666c863 ] 1. After we start atomic write in a database file, before committing all data, we'd better not set inode w/ vfs dirty status to avoid redundant updates, instead, we only set inode w/ atomic dirty status. 2. After we commit all data, before committing metadata, we need to clear atomic dirty status, and set vfs dirty status to allow vfs flush dirty inode. Cc: Daeho Jeong Reported-by: Zhiguo Niu Signed-off-by: Chao Yu Reviewed-by: Daeho Jeong Reviewed-by: Zhiguo Niu Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin --- fs/f2fs/inode.c | 4 +++- fs/f2fs/segment.c | 6 ++++++ fs/f2fs/super.c | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 21d3eabe95e0..66721c2093c0 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -35,7 +35,9 @@ void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync) if (f2fs_inode_dirtied(inode, sync)) return; - if (f2fs_is_atomic_file(inode)) + /* only atomic file w/ FI_ATOMIC_COMMITTED can be set vfs dirty */ + if (f2fs_is_atomic_file(inode) && + !is_inode_flag_set(inode, FI_ATOMIC_COMMITTED)) return; mark_inode_dirty_sync(inode); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 156d92b94525..c7714e954cb5 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -372,7 +372,13 @@ out: } else { sbi->committed_atomic_block += fi->atomic_write_cnt; set_inode_flag(inode, FI_ATOMIC_COMMITTED); + + /* + * inode may has no FI_ATOMIC_DIRTIED flag due to no write + * before commit. + */ if (is_inode_flag_set(inode, FI_ATOMIC_DIRTIED)) { + /* clear atomic dirty status and set vfs dirty status */ clear_inode_flag(inode, FI_ATOMIC_DIRTIED); f2fs_mark_inode_dirty_sync(inode, true); } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 50170e7cf3f9..702137eafaa6 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1500,7 +1500,9 @@ int f2fs_inode_dirtied(struct inode *inode, bool sync) } spin_unlock(&sbi->inode_lock[DIRTY_META]); - if (!ret && f2fs_is_atomic_file(inode)) + /* if atomic write is not committed, set inode w/ atomic dirty */ + if (!ret && f2fs_is_atomic_file(inode) && + !is_inode_flag_set(inode, FI_ATOMIC_COMMITTED)) set_inode_flag(inode, FI_ATOMIC_DIRTIED); return ret;