aboutsummaryrefslogtreecommitdiff
path: root/fs/gfs2/file.c
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2011-07-27 10:58:48 +0100
committerSteven Whitehouse <swhiteho@redhat.com>2011-10-21 12:39:18 +0100
commit2f0264d592e34cde99efbad7d616b04af138e913 (patch)
treec3839570b304396513c8cc296a3fc7130b6066f1 /fs/gfs2/file.c
parent4c28d33803d4aeaff32b4ac502af11a9b2aed8f4 (diff)
GFS2: Split data write & wait in fsync
Now that the data writing is part of fsync proper, we can split the waiting part out and do it later on. This reduces the number of waits that we do during fsync on average. There is also no need to take the i_mutex unless we are flushing metadata to disk, so we can move that to within the metadata flushing code. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/file.c')
-rw-r--r--fs/gfs2/file.c34
1 files changed, 24 insertions, 10 deletions
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index edeb9e80290..92c3db424b4 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -551,8 +551,16 @@ static int gfs2_close(struct inode *inode, struct file *file)
* @end: the end position in the file to sync
* @datasync: set if we can ignore timestamp changes
*
- * The VFS will flush data for us. We only need to worry
- * about metadata here.
+ * We split the data flushing here so that we don't wait for the data
+ * until after we've also sent the metadata to disk. Note that for
+ * data=ordered, we will write & wait for the data at the log flush
+ * stage anyway, so this is unlikely to make much of a difference
+ * except in the data=writeback case.
+ *
+ * If the fdatawrite fails due to any reason except -EIO, we will
+ * continue the remainder of the fsync, although we'll still report
+ * the error at the end. This is to match filemap_write_and_wait_range()
+ * behaviour.
*
* Returns: errno
*/
@@ -560,30 +568,36 @@ static int gfs2_close(struct inode *inode, struct file *file)
static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
int datasync)
{
- struct inode *inode = file->f_mapping->host;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
struct gfs2_inode *ip = GFS2_I(inode);
- int ret;
+ int ret, ret1 = 0;
- ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
- if (ret)
- return ret;
- mutex_lock(&inode->i_mutex);
+ if (mapping->nrpages) {
+ ret1 = filemap_fdatawrite_range(mapping, start, end);
+ if (ret1 == -EIO)
+ return ret1;
+ }
if (datasync)
sync_state &= ~I_DIRTY_SYNC;
if (sync_state) {
+ mutex_lock(&inode->i_mutex);
ret = sync_inode_metadata(inode, 1);
if (ret) {
mutex_unlock(&inode->i_mutex);
return ret;
}
gfs2_ail_flush(ip->i_gl);
+ mutex_unlock(&inode->i_mutex);
}
- mutex_unlock(&inode->i_mutex);
- return 0;
+ if (mapping->nrpages)
+ ret = filemap_fdatawait_range(mapping, start, end);
+
+ return ret ? ret : ret1;
}
/**