]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
fs: Fix missed inode writeback when racing with __writeback_single_inode
authorJan Kara <jack@suse.cz>
Mon, 27 Jul 2026 10:49:21 +0000 (12:49 +0200)
committerChristian Brauner <brauner@kernel.org>
Mon, 27 Jul 2026 14:25:31 +0000 (16:25 +0200)
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>
fs/buffer.c
fs/libfs.c

index daaa6614a6d63c9aff2a40700937044efa63d7b3..7e5ad9f4754d5fe9bef4eae40d62366867035932 100644 (file)
@@ -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);
index 5a0d276379d13b5f1c790b9582572d7a11b00bf7..57e5971b6331970b48cb24aa4564115b36859500 100644 (file)
@@ -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);