]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
NFS: Fix an Oops when truncating a file
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 3 Feb 2010 13:27:22 +0000 (08:27 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 3 Feb 2010 13:27:22 +0000 (08:27 -0500)
The VM/VFS does not allow mapping->a_ops->invalidatepage() to fail.
Unfortunately, nfs_wb_page_cancel() may fail if a fatal signal occurs.
Since the NFS code assumes that the page stays mapped for as long as the
writeback is active, we can end up Oopsing (among other things).

The only safe fix here is to convert nfs_wait_on_request(), so as to make
it uninterruptible (as is already the case with wait_on_page_writeback()).

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@kernel.org
fs/nfs/pagelist.c

index e2975939126abe4b949e3e7f0d09f8790ba81260..a12c45b65dd42bc1712f23c7050923a6d83eed28 100644 (file)
@@ -176,6 +176,12 @@ void nfs_release_request(struct nfs_page *req)
        kref_put(&req->wb_kref, nfs_free_request);
 }
 
+static int nfs_wait_bit_uninterruptible(void *word)
+{
+       io_schedule();
+       return 0;
+}
+
 /**
  * nfs_wait_on_request - Wait for a request to complete.
  * @req: request to wait upon.
@@ -186,14 +192,9 @@ void nfs_release_request(struct nfs_page *req)
 int
 nfs_wait_on_request(struct nfs_page *req)
 {
-       int ret = 0;
-
-       if (!test_bit(PG_BUSY, &req->wb_flags))
-               goto out;
-       ret = out_of_line_wait_on_bit(&req->wb_flags, PG_BUSY,
-                       nfs_wait_bit_killable, TASK_KILLABLE);
-out:
-       return ret;
+       return wait_on_bit(&req->wb_flags, PG_BUSY,
+                       nfs_wait_bit_uninterruptible,
+                       TASK_UNINTERRUPTIBLE);
 }
 
 /**