Commit f57dcf4c authored by Trond Myklebust's avatar Trond Myklebust

NFS: Fix I/O request leakages

When we fail to add the request to the I/O queue, we currently leave it
to the caller to free the failed request. However since some of the
requests that fail are actually created by nfs_pageio_add_request()
itself, and are not passed back the caller, this leads to a leakage
issue, which can again cause page locks to leak.

This commit addresses the leakage by freeing the created requests on
error, using desc->pg_completion_ops->error_cleanup()
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Fixes: a7d42ddb ("nfs: add mirroring support to pgio layer")
Cc: stable@vger.kernel.org # v4.0: c18b96a1: nfs: clean up rest of reqs
Cc: stable@vger.kernel.org # v4.0: d600ad1f: NFS41: pop some layoutget
Cc: stable@vger.kernel.org # v4.0+
parent 2137397c
...@@ -988,6 +988,17 @@ static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) ...@@ -988,6 +988,17 @@ static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
} }
} }
static void
nfs_pageio_cleanup_request(struct nfs_pageio_descriptor *desc,
struct nfs_page *req)
{
LIST_HEAD(head);
nfs_list_remove_request(req);
nfs_list_add_request(req, &head);
desc->pg_completion_ops->error_cleanup(&head);
}
/** /**
* nfs_pageio_add_request - Attempt to coalesce a request into a page list. * nfs_pageio_add_request - Attempt to coalesce a request into a page list.
* @desc: destination io descriptor * @desc: destination io descriptor
...@@ -1025,10 +1036,8 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, ...@@ -1025,10 +1036,8 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
nfs_page_group_unlock(req); nfs_page_group_unlock(req);
desc->pg_moreio = 1; desc->pg_moreio = 1;
nfs_pageio_doio(desc); nfs_pageio_doio(desc);
if (desc->pg_error < 0) if (desc->pg_error < 0 || mirror->pg_recoalesce)
return 0; goto out_cleanup_subreq;
if (mirror->pg_recoalesce)
return 0;
/* retry add_request for this subreq */ /* retry add_request for this subreq */
nfs_page_group_lock(req); nfs_page_group_lock(req);
continue; continue;
...@@ -1061,6 +1070,10 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, ...@@ -1061,6 +1070,10 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
desc->pg_error = PTR_ERR(subreq); desc->pg_error = PTR_ERR(subreq);
nfs_page_group_unlock(req); nfs_page_group_unlock(req);
return 0; return 0;
out_cleanup_subreq:
if (req != subreq)
nfs_pageio_cleanup_request(desc, subreq);
return 0;
} }
static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
...@@ -1168,11 +1181,14 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, ...@@ -1168,11 +1181,14 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
if (nfs_pgio_has_mirroring(desc)) if (nfs_pgio_has_mirroring(desc))
desc->pg_mirror_idx = midx; desc->pg_mirror_idx = midx;
if (!nfs_pageio_add_request_mirror(desc, dupreq)) if (!nfs_pageio_add_request_mirror(desc, dupreq))
goto out_failed; goto out_cleanup_subreq;
} }
return 1; return 1;
out_cleanup_subreq:
if (req != dupreq)
nfs_pageio_cleanup_request(desc, dupreq);
out_failed: out_failed:
nfs_pageio_error_cleanup(desc); nfs_pageio_error_cleanup(desc);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment