| From 5926488bd93f9dd67937738751cce515e45b321c Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 11 Jun 2020 12:44:56 -0400 |
| Subject: svcrdma: Fix page leak in svc_rdma_recv_read_chunk() |
| |
| From: Chuck Lever <chuck.lever@oracle.com> |
| |
| [ Upstream commit e814eecbe3bbeaa8b004d25a4b8974d232b765a9 ] |
| |
| Commit 07d0ff3b0cd2 ("svcrdma: Clean up Read chunk path") moved the |
| page saver logic so that it gets executed event when an error occurs. |
| In that case, the I/O is never posted, and those pages are then |
| leaked. Errors in this path, however, are quite rare. |
| |
| Fixes: 07d0ff3b0cd2 ("svcrdma: Clean up Read chunk path") |
| Signed-off-by: Chuck Lever <chuck.lever@oracle.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/sunrpc/xprtrdma/svc_rdma_rw.c | 28 +++++++++++++++++++++------- |
| 1 file changed, 21 insertions(+), 7 deletions(-) |
| |
| diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c |
| index 23c2d3ce0dc9a..e0a0ae39848c4 100644 |
| --- a/net/sunrpc/xprtrdma/svc_rdma_rw.c |
| +++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c |
| @@ -678,7 +678,6 @@ static int svc_rdma_build_read_chunk(struct svc_rqst *rqstp, |
| struct svc_rdma_read_info *info, |
| __be32 *p) |
| { |
| - unsigned int i; |
| int ret; |
| |
| ret = -EINVAL; |
| @@ -701,12 +700,6 @@ static int svc_rdma_build_read_chunk(struct svc_rqst *rqstp, |
| info->ri_chunklen += rs_length; |
| } |
| |
| - /* Pages under I/O have been copied to head->rc_pages. |
| - * Prevent their premature release by svc_xprt_release() . |
| - */ |
| - for (i = 0; i < info->ri_readctxt->rc_page_count; i++) |
| - rqstp->rq_pages[i] = NULL; |
| - |
| return ret; |
| } |
| |
| @@ -801,6 +794,26 @@ static int svc_rdma_build_pz_read_chunk(struct svc_rqst *rqstp, |
| return ret; |
| } |
| |
| +/* Pages under I/O have been copied to head->rc_pages. Ensure they |
| + * are not released by svc_xprt_release() until the I/O is complete. |
| + * |
| + * This has to be done after all Read WRs are constructed to properly |
| + * handle a page that is part of I/O on behalf of two different RDMA |
| + * segments. |
| + * |
| + * Do this only if I/O has been posted. Otherwise, we do indeed want |
| + * svc_xprt_release() to clean things up properly. |
| + */ |
| +static void svc_rdma_save_io_pages(struct svc_rqst *rqstp, |
| + const unsigned int start, |
| + const unsigned int num_pages) |
| +{ |
| + unsigned int i; |
| + |
| + for (i = start; i < num_pages + start; i++) |
| + rqstp->rq_pages[i] = NULL; |
| +} |
| + |
| /** |
| * svc_rdma_recv_read_chunk - Pull a Read chunk from the client |
| * @rdma: controlling RDMA transport |
| @@ -854,6 +867,7 @@ int svc_rdma_recv_read_chunk(struct svcxprt_rdma *rdma, struct svc_rqst *rqstp, |
| ret = svc_rdma_post_chunk_ctxt(&info->ri_cc); |
| if (ret < 0) |
| goto out_err; |
| + svc_rdma_save_io_pages(rqstp, 0, head->rc_page_count); |
| return 0; |
| |
| out_err: |
| -- |
| 2.25.1 |
| |