2.6.38-stable review patch.  If anyone has any objections, please let us know.

------------------

From: Trond Myklebust <[email protected]>

commit b8413f98f997bb3ed7327e6d7117e7e91ce010c3 upstream.

When one of the two waits in nfs_commit_inode() is interrupted, it
returns a non-negative value, which causes nfs_wb_page() to think
that the operation was successful causing it to busy-loop rather
than exiting.
It also causes nfs_file_fsync() to incorrectly report the file as
being successfully committed to disk.

This patch fixes both problems by ensuring that we return an error
if the attempts to wait fail.

Signed-off-by: Trond Myklebust <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 fs/nfs/write.c |   31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)

--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -1214,13 +1214,17 @@ int nfs_writeback_done(struct rpc_task *
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 static int nfs_commit_set_lock(struct nfs_inode *nfsi, int may_wait)
 {
+       int ret;
+
        if (!test_and_set_bit(NFS_INO_COMMIT, &nfsi->flags))
                return 1;
-       if (may_wait && !out_of_line_wait_on_bit_lock(&nfsi->flags,
-                               NFS_INO_COMMIT, nfs_wait_bit_killable,
-                               TASK_KILLABLE))
-               return 1;
-       return 0;
+       if (!may_wait)
+               return 0;
+       ret = out_of_line_wait_on_bit_lock(&nfsi->flags,
+                               NFS_INO_COMMIT,
+                               nfs_wait_bit_killable,
+                               TASK_KILLABLE);
+       return (ret < 0) ? ret : 1;
 }
 
 static void nfs_commit_clear_lock(struct nfs_inode *nfsi)
@@ -1396,9 +1400,10 @@ int nfs_commit_inode(struct inode *inode
 {
        LIST_HEAD(head);
        int may_wait = how & FLUSH_SYNC;
-       int res = 0;
+       int res;
 
-       if (!nfs_commit_set_lock(NFS_I(inode), may_wait))
+       res = nfs_commit_set_lock(NFS_I(inode), may_wait);
+       if (res <= 0)
                goto out_mark_dirty;
        spin_lock(&inode->i_lock);
        res = nfs_scan_commit(inode, &head, 0, 0);
@@ -1407,12 +1412,14 @@ int nfs_commit_inode(struct inode *inode
                int error = nfs_commit_list(inode, &head, how);
                if (error < 0)
                        return error;
-               if (may_wait)
-                       wait_on_bit(&NFS_I(inode)->flags, NFS_INO_COMMIT,
-                                       nfs_wait_bit_killable,
-                                       TASK_KILLABLE);
-               else
+               if (!may_wait)
                        goto out_mark_dirty;
+               error = wait_on_bit(&NFS_I(inode)->flags,
+                               NFS_INO_COMMIT,
+                               nfs_wait_bit_killable,
+                               TASK_KILLABLE);
+               if (error < 0)
+                       return error;
        } else
                nfs_commit_clear_lock(NFS_I(inode));
        return res;


_______________________________________________
stable mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/stable

Reply via email to