Commit 7176142a authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] speed up ext2 fsync() and fdatasync()

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 <jbs@quiotix.com> who noticed the performance
discrepancy and wrote a test app.
parent a1ff5989
...@@ -32,17 +32,20 @@ ...@@ -32,17 +32,20 @@
* even pass file to fsync ? * 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; struct inode *inode = dentry->d_inode;
int err; int err;
int ret;
err = sync_mapping_buffers(inode->i_mapping);
ret = sync_mapping_buffers(inode->i_mapping);
if (!(inode->i_state & I_DIRTY)) if (!(inode->i_state & I_DIRTY))
return err; return ret;
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
return err; return ret;
err |= ext2_sync_inode(inode); err = ext2_sync_inode(inode);
return err ? -EIO : 0; if (ret == 0)
ret = err;
return ret;
} }
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/mpage.h> #include <linux/mpage.h>
#include "ext2.h" #include "ext2.h"
...@@ -1246,14 +1247,18 @@ static int ext2_update_inode(struct inode * inode, int do_sync) ...@@ -1246,14 +1247,18 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
return err; 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) int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
...@@ -1275,4 +1280,3 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) ...@@ -1275,4 +1280,3 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
error = ext2_acl_chmod(inode); error = ext2_acl_chmod(inode);
return error; return error;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment