xfs: implement optimized fdatasync
authorChristoph Hellwig <hch@infradead.org>
Mon, 15 Feb 2010 09:44:49 +0000 (09:44 +0000)
committerAlex Elder <aelder@sgi.com>
Mon, 1 Mar 2010 22:34:45 +0000 (16:34 -0600)
Allow us to track the difference between timestamp and size updates
by using mark_inode_dirty from the I/O completion code, and checking
the VFS inode flags in xfs_file_fsync.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <david@fromorbit.com>
Signed-off-by: Alex Elder <aelder@sgi.com>
fs/xfs/linux-2.6/xfs_aops.c
fs/xfs/linux-2.6/xfs_file.c
fs/xfs/linux-2.6/xfs_iops.c
fs/xfs/xfs_inode.h

index 66abe36..ce369a8 100644 (file)
@@ -187,7 +187,7 @@ xfs_setfilesize(
        isize = xfs_ioend_new_eof(ioend);
        if (isize) {
                ip->i_d.di_size = isize;
-               xfs_mark_inode_dirty_sync(ip);
+               xfs_mark_inode_dirty(ip);
        }
 
        xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -341,7 +341,7 @@ xfs_submit_ioend_bio(
         * but don't update the inode size until I/O completion.
         */
        if (xfs_ioend_new_eof(ioend))
-               xfs_mark_inode_dirty_sync(XFS_I(ioend->io_inode));
+               xfs_mark_inode_dirty(XFS_I(ioend->io_inode));
 
        submit_bio(wbc->sync_mode == WB_SYNC_ALL ?
                   WRITE_SYNC_PLUG : WRITE, bio);
index 6c283b7..43f9554 100644 (file)
@@ -97,16 +97,6 @@ xfs_iozero(
        return (-status);
 }
 
-/*
- * We ignore the datasync flag here because a datasync is effectively
- * identical to an fsync. That is, datasync implies that we need to write
- * only the metadata needed to be able to access the data that is written
- * if we crash after the call completes. Hence if we are writing beyond
- * EOF we have to log the inode size change as well, which makes it a
- * full fsync. If we don't write beyond EOF, the inode core will be
- * clean in memory and so we don't need to log the inode, just like
- * fsync.
- */
 STATIC int
 xfs_file_fsync(
        struct file             *file,
@@ -139,7 +129,18 @@ xfs_file_fsync(
         */
        xfs_ilock(ip, XFS_ILOCK_SHARED);
 
-       if (ip->i_update_core) {
+       /*
+        * First check if the VFS inode is marked dirty.  All the dirtying
+        * of non-transactional updates no goes through mark_inode_dirty*,
+        * which allows us to distinguish beteeen pure timestamp updates
+        * and i_size updates which need to be caught for fdatasync.
+        * After that also theck for the dirty state in the XFS inode, which
+        * might gets cleared when the inode gets written out via the AIL
+        * or xfs_iflush_cluster.
+        */
+       if (((dentry->d_inode->i_state & I_DIRTY_DATASYNC) ||
+           ((dentry->d_inode->i_state & I_DIRTY_SYNC) && !datasync)) &&
+           ip->i_update_core) {
                /*
                 * Kick off a transaction to log the inode core to get the
                 * updates.  The sync transaction will also force the log.
index e8566bb..61a9960 100644 (file)
@@ -91,6 +91,16 @@ xfs_mark_inode_dirty_sync(
                mark_inode_dirty_sync(inode);
 }
 
+void
+xfs_mark_inode_dirty(
+       xfs_inode_t     *ip)
+{
+       struct inode    *inode = VFS_I(ip);
+
+       if (!(inode->i_state & (I_WILL_FREE|I_FREEING|I_CLEAR)))
+               mark_inode_dirty(inode);
+}
+
 /*
  * Change the requested timestamp in the given inode.
  * We don't lock across timestamp updates, and we don't log them but
index 6c912b0..41e8a4e 100644 (file)
@@ -480,6 +480,7 @@ void                xfs_lock_inodes(xfs_inode_t **, int, uint);
 void           xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
 
 void           xfs_synchronize_times(xfs_inode_t *);
+void           xfs_mark_inode_dirty(xfs_inode_t *);
 void           xfs_mark_inode_dirty_sync(xfs_inode_t *);
 
 #define IHOLD(ip) \