[patch 2/7] fs: simple fsync race fix

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: npiggin
Date: Tuesday, November 23, 2010 - 7:06 am

It is incorrect to test inode dirty bits without participating in the inode
writeback protocol. Inode writeback sets I_SYNC and clears I_DIRTY_?, then
writes out the particular bits, then clears I_SYNC when it is done. BTW. it
may not completely write all pages out, so I_DIRTY_PAGES would get set
again.

This is a standard pattern used throughout the kernel's writeback caches
(I_SYNC ~= I_WRITEBACK, if that makes it clearer).

And so it is not possible to determine an inode's dirty status just by
checking I_DIRTY bits. Especially not for the purpose of data integrity
syncs.

Missing the check for these bits means that fsync can complete while
writeback to the inode is underway. Inode writeback functions get this
right, so call into them rather than try to shortcut things by testing
dirty state improperly.

Signed-off-by: Nick Piggin <npiggin@kernel.dk>


Index: linux-2.6/fs/libfs.c
===================================================================
--- linux-2.6.orig/fs/libfs.c	2010-11-19 16:44:39.000000000 +1100
+++ linux-2.6/fs/libfs.c	2010-11-19 16:49:42.000000000 +1100
@@ -895,11 +895,6 @@ int generic_file_fsync(struct file *file
 	int ret;
 
 	ret = sync_mapping_buffers(inode->i_mapping);
-	if (!(inode->i_state & I_DIRTY))
-		return ret;
-	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
-		return ret;
-
 	err = sync_inode_metadata(inode, 1);
 	if (ret == 0)
 		ret = err;
Index: linux-2.6/fs/exofs/file.c
===================================================================
--- linux-2.6.orig/fs/exofs/file.c	2010-11-19 16:50:00.000000000 +1100
+++ linux-2.6/fs/exofs/file.c	2010-11-19 16:50:07.000000000 +1100
@@ -48,11 +48,6 @@ static int exofs_file_fsync(struct file
 	struct inode *inode = filp->f_mapping->host;
 	struct super_block *sb;
 
-	if (!(inode->i_state & I_DIRTY))
-		return 0;
-	if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
-		return 0;
-
 	ret = sync_inode_metadata(inode, 1);
 
 	/* This is a good place to write the sb */


--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[patch 0/7] icache dirty / sync fixes, npiggin, (Tue Nov 23, 7:06 am)
[patch 1/7] fs: mark_inode_dirty barrier fix, npiggin, (Tue Nov 23, 7:06 am)
[patch 2/7] fs: simple fsync race fix, npiggin, (Tue Nov 23, 7:06 am)
[patch 5/7] fs: ext2 inode sync fix, npiggin, (Tue Nov 23, 7:06 am)
[patch 6/7] fs: fsync optimisations, npiggin, (Tue Nov 23, 7:06 am)
Re: [patch 2/7] fs: simple fsync race fix, Christoph Hellwig, (Mon Nov 29, 7:58 am)
Re: [patch 4/7] fs: preserve inode dirty bits on failed me ..., Christoph Hellwig, (Mon Nov 29, 7:59 am)
Re: [patch 6/7] fs: fsync optimisations, Christoph Hellwig, (Mon Nov 29, 8:03 am)
Re: [patch 3/7] fs: introduce inode writeback helpers, Christoph Hellwig, (Mon Nov 29, 8:13 am)
Re: [patch 6/7] fs: fsync optimisations, Nick Piggin, (Mon Nov 29, 5:11 pm)
Re: [patch 3/7] fs: introduce inode writeback helpers, Nick Piggin, (Mon Nov 29, 5:22 pm)