aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@kernel.dk>2010-11-25 05:47:15 -0500
committerBoaz Harrosh <bharrosh@panasas.com>2011-03-15 09:02:50 -0400
commit97178b7b6c84bd14660b89474d27931a1ea65c66 (patch)
treeb763cc48e6456b944e7bed877ad2a996809124eb
parenta8f1418f9e9bd4c487a7b703ff26c5dd5ceb2bf3 (diff)
exofs: simple fsync race fix
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> Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
-rw-r--r--fs/exofs/file.c5
-rw-r--r--fs/exofs/inode.c3
2 files changed, 2 insertions, 6 deletions
diff --git a/fs/exofs/file.c b/fs/exofs/file.c
index b905c79b4f0a..4c0d6bac9143 100644
--- a/fs/exofs/file.c
+++ b/fs/exofs/file.c
@@ -48,11 +48,6 @@ static int exofs_file_fsync(struct file *filp, int datasync)
48 struct inode *inode = filp->f_mapping->host; 48 struct inode *inode = filp->f_mapping->host;
49 struct super_block *sb; 49 struct super_block *sb;
50 50
51 if (!(inode->i_state & I_DIRTY))
52 return 0;
53 if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
54 return 0;
55
56 ret = sync_inode_metadata(inode, 1); 51 ret = sync_inode_metadata(inode, 1);
57 52
58 /* This is a good place to write the sb */ 53 /* This is a good place to write the sb */
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index c8f58a96e597..fb9d38056103 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -1290,7 +1290,8 @@ out:
1290 1290
1291int exofs_write_inode(struct inode *inode, struct writeback_control *wbc) 1291int exofs_write_inode(struct inode *inode, struct writeback_control *wbc)
1292{ 1292{
1293 return exofs_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL); 1293 /* FIXME: fix fsync and use wbc->sync_mode == WB_SYNC_ALL */
1294 return exofs_update_inode(inode, 1);
1294} 1295}
1295 1296
1296/* 1297/*