pNFS: Fix use after free issues in pnfs_do_read()
authorTrond Myklebust <trond.myklebust@primarydata.com>
Tue, 25 Apr 2017 15:26:53 +0000 (11:26 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 24 Mar 2018 10:00:15 +0000 (11:00 +0100)
[ Upstream commit 6aeafd05eca9bc8ab6b03d7e56d09ffd18190f44 ]

The assumption should be that if the caller returns PNFS_ATTEMPTED, then hdr
has been consumed, and so we should not be testing hdr->task.tk_status.
If the caller returns PNFS_TRY_AGAIN, then we need to recoalesce and
free hdr.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Sasha Levin <alexander.levin@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/nfs/pnfs.c

index b8e4474..e9a697e 100644 (file)
@@ -2308,10 +2308,20 @@ pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr)
        enum pnfs_try_status trypnfs;
 
        trypnfs = pnfs_try_to_read_data(hdr, call_ops, lseg);
-       if (trypnfs == PNFS_TRY_AGAIN)
-               pnfs_read_resend_pnfs(hdr);
-       if (trypnfs == PNFS_NOT_ATTEMPTED || hdr->task.tk_status)
+       switch (trypnfs) {
+       case PNFS_NOT_ATTEMPTED:
                pnfs_read_through_mds(desc, hdr);
+       case PNFS_ATTEMPTED:
+               break;
+       case PNFS_TRY_AGAIN:
+               /* cleanup hdr and prepare to redo pnfs */
+               if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
+                       struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
+                       list_splice_init(&hdr->pages, &mirror->pg_list);
+                       mirror->pg_recoalesce = 1;
+               }
+               hdr->mds_ops->rpc_release(hdr);
+       }
 }
 
 static void pnfs_readhdr_free(struct nfs_pgio_header *hdr)