nfs: Fix a missed page unlock after pg_doio()
authorBenjamin Coddington <bcodding@redhat.com>
Thu, 18 Oct 2018 19:01:48 +0000 (15:01 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 13 Nov 2018 19:08:49 +0000 (11:08 -0800)
commit fdbd1a2e4a71adcb1ae219fcfd964930d77a7f84 upstream.

We must check pg_error and call error_cleanup after any call to pg_doio.
Currently, we are skipping the unlock of a page if we encounter an error in
nfs_pageio_complete() before handing off the work to the RPC layer.

Signed-off-by: Benjamin Coddington <bcodding@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfs/pagelist.c

index bb5476a..3dbd15b 100644 (file)
@@ -1111,6 +1111,20 @@ static int nfs_pageio_add_request_mirror(struct nfs_pageio_descriptor *desc,
        return ret;
 }
 
+static void nfs_pageio_error_cleanup(struct nfs_pageio_descriptor *desc)
+{
+       u32 midx;
+       struct nfs_pgio_mirror *mirror;
+
+       if (!desc->pg_error)
+               return;
+
+       for (midx = 0; midx < desc->pg_mirror_count; midx++) {
+               mirror = &desc->pg_mirrors[midx];
+               desc->pg_completion_ops->error_cleanup(&mirror->pg_list);
+       }
+}
+
 int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
                           struct nfs_page *req)
 {
@@ -1161,25 +1175,11 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
        return 1;
 
 out_failed:
-       /*
-        * We might have failed before sending any reqs over wire.
-        * Clean up rest of the reqs in mirror pg_list.
-        */
-       if (desc->pg_error) {
-               struct nfs_pgio_mirror *mirror;
-               void (*func)(struct list_head *);
-
-               /* remember fatal errors */
-               if (nfs_error_is_fatal(desc->pg_error))
-                       nfs_context_set_write_error(req->wb_context,
-                                                   desc->pg_error);
-
-               func = desc->pg_completion_ops->error_cleanup;
-               for (midx = 0; midx < desc->pg_mirror_count; midx++) {
-                       mirror = &desc->pg_mirrors[midx];
-                       func(&mirror->pg_list);
-               }
-       }
+       /* remember fatal errors */
+       if (nfs_error_is_fatal(desc->pg_error))
+               nfs_context_set_write_error(req->wb_context,
+                                               desc->pg_error);
+       nfs_pageio_error_cleanup(desc);
        return 0;
 }
 
@@ -1251,6 +1251,8 @@ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
        for (midx = 0; midx < desc->pg_mirror_count; midx++)
                nfs_pageio_complete_mirror(desc, midx);
 
+       if (desc->pg_error < 0)
+               nfs_pageio_error_cleanup(desc);
        if (desc->pg_ops->pg_cleanup)
                desc->pg_ops->pg_cleanup(desc);
        nfs_pageio_cleanup_mirroring(desc);