diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2011-07-27 10:58:48 +0100 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2011-10-21 12:39:18 +0100 |
commit | 2f0264d592e34cde99efbad7d616b04af138e913 (patch) | |
tree | c3839570b304396513c8cc296a3fc7130b6066f1 /fs/gfs2/file.c | |
parent | 4c28d33803d4aeaff32b4ac502af11a9b2aed8f4 (diff) | |
download | lwn-2f0264d592e34cde99efbad7d616b04af138e913.tar.gz lwn-2f0264d592e34cde99efbad7d616b04af138e913.zip |
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.c | 34 |
1 files changed, 24 insertions, 10 deletions
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index edeb9e802903..92c3db424b40 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; } /** |