NFSv4/pnfs: Fix a page lock leak in nfs_pageio_resend() [Linux 4.19.70]

This Linux kernel change "NFSv4/pnfs: Fix a page lock leak in nfs_pageio_resend()" is included in the Linux 4.19.70 release. This change is authored by Trond Myklebust <trond.myklebust [at] hammerspace.com> on Mon Aug 12 15:19:54 2019 -0400. The commit for this change in Linux stable tree is 812de6d (patch) which is from upstream commit f4340e9. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream f4340e9.

NFSv4/pnfs: Fix a page lock leak in nfs_pageio_resend()

[ Upstream commit f4340e9314dbfadc48758945f85fc3b16612d06f ]

If the attempt to resend the pages fails, we need to ensure that we
clean up those pages that were not transmitted.

Fixes: d600ad1f2bdb ("NFS41: pop some layoutget errors to application")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Cc: stable@vger.kernel.org # v4.5+
Signed-off-by: Sasha Levin <sashal@kernel.org>

There are 16 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 fs/nfs/pagelist.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index d40bf56..9cbd829 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -1232,20 +1232,22 @@ static void nfs_pageio_complete_mirror(struct nfs_pageio_descriptor *desc,
 int nfs_pageio_resend(struct nfs_pageio_descriptor *desc,
              struct nfs_pgio_header *hdr)
 {
-   LIST_HEAD(failed);
+   LIST_HEAD(pages);

    desc->pg_io_completion = hdr->io_completion;
    desc->pg_dreq = hdr->dreq;
-   while (!list_empty(&hdr->pages)) {
-       struct nfs_page *req = nfs_list_entry(hdr->pages.next);
+   list_splice_init(&hdr->pages, &pages);
+   while (!list_empty(&pages)) {
+       struct nfs_page *req = nfs_list_entry(pages.next);

        if (!nfs_pageio_add_request(desc, req))
-           nfs_list_move_request(req, &failed);
+           break;
    }
    nfs_pageio_complete(desc);
-   if (!list_empty(&failed)) {
-       list_move(&failed, &hdr->pages);
-       return desc->pg_error < 0 ? desc->pg_error : -EIO;
+   if (!list_empty(&pages)) {
+       int err = desc->pg_error < 0 ? desc->pg_error : -EIO;
+       hdr->completion_ops->error_cleanup(&pages, err);
+       return err;
    }
    return 0;
 }

Leave a Reply

Your email address will not be published. Required fields are marked *