Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=e893bffd4cf2f000f3058319eea5abeeb1755969
Commit:     e893bffd4cf2f000f3058319eea5abeeb1755969
Parent:     c2cba57e83dd7d2dda4ec425998b536669632c82
Author:     Lachlan McIlroy <[EMAIL PROTECTED]>
AuthorDate: Fri Oct 12 11:13:35 2007 +1000
Committer:  Tim Shimmin <[EMAIL PROTECTED]>
CommitDate: Tue Oct 16 14:22:28 2007 +1000

    [XFS] avoid race in sync_inodes() that can fail to write out all dirty data
    
    In xfs_fs_sync_super() treat a sync the same as a filesystem freeze. This
    is needed to force the log to disk for inodes which are not marked dirty
    in the Linux inode (the inodes are marked dirty on completion of the log
    I/O) and so sync_inodes() will not flush them.
    
    In xfs_fs_write_inode() a synchronous flush will not get an EAGAIN from
    xfs_inode_flush() and if an asynchronous flush returns EAGAIN we should
    pass it on to the caller. If we get an error while flushing the inode then
    re-dirty it so we can try again later.
    
    SGI-PV: 971670
    SGI-Modid: xfs-linux-melb:xfs-kern:29860a
    
    Signed-off-by: Lachlan McIlroy <[EMAIL PROTECTED]>
    Signed-off-by: David Chinner <[EMAIL PROTECTED]>
    Signed-off-by: Tim Shimmin <[EMAIL PROTECTED]>
---
 fs/xfs/linux-2.6/xfs_super.c |   29 ++++++++++++++++++++---------
 1 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index a1e3f3e..02ec14e 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -410,13 +410,12 @@ xfs_fs_write_inode(
                flags |= FLUSH_SYNC;
        }
        error = xfs_inode_flush(XFS_I(inode), flags);
-       if (error == EAGAIN) {
-               if (sync)
-                       error = xfs_inode_flush(XFS_I(inode),
-                                                      flags | FLUSH_LOG);
-               else
-                       error = 0;
-       }
+       /*
+        * if we failed to write out the inode then mark
+        * it dirty again so we'll try again later.
+        */
+       if (error)
+               mark_inode_dirty_sync(inode);
 
        return -error;
 }
@@ -622,7 +621,19 @@ xfs_fs_sync_super(
        int                     error;
        int                     flags;
 
-       if (unlikely(sb->s_frozen == SB_FREEZE_WRITE)) {
+       /*
+        * Treat a sync operation like a freeze.  This is to work
+        * around a race in sync_inodes() which works in two phases
+        * - an asynchronous flush, which can write out an inode
+        * without waiting for file size updates to complete, and a
+        * synchronous flush, which wont do anything because the
+        * async flush removed the inode's dirty flag.  Also
+        * sync_inodes() will not see any files that just have
+        * outstanding transactions to be flushed because we don't
+        * dirty the Linux inode until after the transaction I/O
+        * completes.
+        */
+       if (wait || unlikely(sb->s_frozen == SB_FREEZE_WRITE)) {
                /*
                 * First stage of freeze - no more writers will make progress
                 * now we are here, so we flush delwri and delalloc buffers
@@ -633,7 +644,7 @@ xfs_fs_sync_super(
                 */
                flags = SYNC_DATA_QUIESCE;
        } else
-               flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0);
+               flags = SYNC_FSDATA;
 
        error = xfs_sync(mp, flags);
        sb->s_dirt = 0;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to