ext2_sync_file() forgets to clear the inode's dirty bits, so we write the inode on every fsync(), even if it hasn't changed. Fix that up via the new sync_file() API which correctly manages the inode state bits and the superblock inode lists. When performing file overwrite on IDE with and without writeback caching enabled this patch approximately doubles fsync() speed, bringing it into line with O_SYNC writes. Also, fix up the return value handling in ext2_sync_file(). Credit due to Jeffrey Siegal who noticed the performance discrepancy and wrote a test app. --- 25-akpm/fs/ext2/fsync.c | 19 +++++++++++-------- 25-akpm/fs/ext2/inode.c | 14 +++++++++----- 2 files changed, 20 insertions(+), 13 deletions(-) diff -puN fs/ext2/inode.c~ext2-fsync-speedup-2 fs/ext2/inode.c --- 25/fs/ext2/inode.c~ext2-fsync-speedup-2 2004-04-03 02:59:56.051831768 -0800 +++ 25-akpm/fs/ext2/inode.c 2004-04-03 02:59:56.056831008 -0800 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include "ext2.h" @@ -1246,14 +1247,18 @@ static int ext2_update_inode(struct inod return err; } -void ext2_write_inode (struct inode * inode, int wait) +void ext2_write_inode(struct inode *inode, int wait) { - ext2_update_inode (inode, wait); + ext2_update_inode(inode, wait); } -int ext2_sync_inode (struct inode *inode) +int ext2_sync_inode(struct inode *inode) { - return ext2_update_inode (inode, 1); + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + .nr_to_write = 0, /* sys_fsync did this */ + }; + return sync_inode(inode, &wbc); } int ext2_setattr(struct dentry *dentry, struct iattr *iattr) @@ -1275,4 +1280,3 @@ int ext2_setattr(struct dentry *dentry, error = ext2_acl_chmod(inode); return error; } - diff -puN fs/ext2/fsync.c~ext2-fsync-speedup-2 fs/ext2/fsync.c --- 25/fs/ext2/fsync.c~ext2-fsync-speedup-2 2004-04-03 02:59:56.052831616 -0800 +++ 25-akpm/fs/ext2/fsync.c 2004-04-03 02:59:56.056831008 -0800 @@ -32,17 +32,20 @@ * even pass file to fsync ? */ -int ext2_sync_file(struct file * file, struct dentry *dentry, int datasync) +int ext2_sync_file(struct file *file, struct dentry *dentry, int datasync) { struct inode *inode = dentry->d_inode; int err; - - err = sync_mapping_buffers(inode->i_mapping); + int ret; + + ret = sync_mapping_buffers(inode->i_mapping); if (!(inode->i_state & I_DIRTY)) - return err; + return ret; if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) - return err; - - err |= ext2_sync_inode(inode); - return err ? -EIO : 0; + return ret; + + err = ext2_sync_inode(inode); + if (ret == 0) + ret = err; + return ret; } _