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 <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-23-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
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);
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);