diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2017-04-25 11:26:53 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2017-04-25 15:42:34 -0400 |
commit | 6aeafd05eca9bc8ab6b03d7e56d09ffd18190f44 (patch) | |
tree | 4cdc02f84e2246efef3fe50dfb138e9cff9aeadd | |
parent | b3230e80a6d115d2eb50fe3f4794ad04d84766de (diff) | |
download | linux-6aeafd05eca9bc8ab6b03d7e56d09ffd18190f44.tar.gz linux-6aeafd05eca9bc8ab6b03d7e56d09ffd18190f44.tar.bz2 linux-6aeafd05eca9bc8ab6b03d7e56d09ffd18190f44.zip |
pNFS: Fix use after free issues in pnfs_do_read()
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>
-rw-r--r-- | fs/nfs/pnfs.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 634adb3f8524..eff266ea813c 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -2419,10 +2419,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) |