From 5a499dad2c794c19bf8ad51429dce1d53d9d3e12 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 27 Jul 2026 12:49:21 +0200 Subject: [PATCH] fs: Fix missed inode writeback when racing with __writeback_single_inode When mmb_fsync_noflush() or simple_fsync_noflush() race with another writeback of the same inode, they can see inode dirty bits are already clear and skip inode writeback although the racing __writeback_single_inode() didn't yet get to writing anything. This can result in fsync(2) returning without properly persisting the inode. We already have I_SYNC bit for this synchronization and writeback_single_inode() properly uses it so just fix mmb_fsync_noflush() and simple_fsync_noflush() to take it into account as well. Signed-off-by: Jan Kara Link: https://patch.msgid.link/20260727104923.3828017-23-jack@suse.cz Signed-off-by: Christian Brauner (Amutable) --- fs/buffer.c | 5 +++-- fs/libfs.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index daaa6614a6d63..7e5ad9f4754d5 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -655,9 +655,10 @@ int mmb_fsync_noflush(struct file *file, struct mapping_metadata_bhs *mmb, if (mmb) ret = mmb_sync(mmb); - if (!(inode_state_read_once(inode) & I_DIRTY_ALL)) + if (!(inode_state_read_once(inode) & (I_DIRTY_ALL | I_SYNC))) goto out; - if (datasync && !(inode_state_read_once(inode) & I_DIRTY_DATASYNC)) + if (datasync && + !(inode_state_read_once(inode) & (I_DIRTY_DATASYNC | I_SYNC))) goto out; err = sync_inode_metadata(inode, 1); diff --git a/fs/libfs.c b/fs/libfs.c index 5a0d276379d13..57e5971b63319 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -1559,9 +1559,10 @@ int simple_fsync_noflush(struct file *file, loff_t start, loff_t end, if (err) return err; - if (!(inode_state_read_once(inode) & I_DIRTY_ALL)) + if (!(inode_state_read_once(inode) & (I_DIRTY_ALL | I_SYNC))) goto out; - if (datasync && !(inode_state_read_once(inode) & I_DIRTY_DATASYNC)) + if (datasync && + !(inode_state_read_once(inode) & (I_DIRTY_DATASYNC | I_SYNC))) goto out; ret = sync_inode_metadata(inode, 1); -- 2.47.3