Skip to content

Commit 23cf1ee

Browse files
committed
svcrdma: Fix leak of svc_rdma_recv_ctxt objects
Utilize the xpo_release_rqst transport method to ensure that each rqstp's svc_rdma_recv_ctxt object is released even when the server cannot return a Reply for that rqstp. Without this fix, each RPC whose Reply cannot be sent leaks one svc_rdma_recv_ctxt. This is a 2.5KB structure, a 4KB DMA-mapped Receive buffer, and any pages that might be part of the Reply message. The leak is infrequent unless the network fabric is unreliable or Kerberos is in use, as GSS sequence window overruns, which result in connection loss, are more common on fast transports. Fixes: 3a88092 ("svcrdma: Preserve Receive buffer until svc_rdma_sendto") Signed-off-by: Chuck Lever <[email protected]>
1 parent e28b4fc commit 23cf1ee

File tree

6 files changed

+30
-18
lines changed

6 files changed

+30
-18
lines changed

include/linux/sunrpc/svc_rdma.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ extern bool svc_rdma_post_recvs(struct svcxprt_rdma *rdma);
170170
extern void svc_rdma_recv_ctxt_put(struct svcxprt_rdma *rdma,
171171
struct svc_rdma_recv_ctxt *ctxt);
172172
extern void svc_rdma_flush_recv_queues(struct svcxprt_rdma *rdma);
173+
extern void svc_rdma_release_rqst(struct svc_rqst *rqstp);
173174
extern int svc_rdma_recvfrom(struct svc_rqst *);
174175

175176
/* svc_rdma_rw.c */

net/sunrpc/svc_xprt.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -908,9 +908,6 @@ int svc_send(struct svc_rqst *rqstp)
908908
if (!xprt)
909909
goto out;
910910

911-
/* release the receive skb before sending the reply */
912-
xprt->xpt_ops->xpo_release_rqst(rqstp);
913-
914911
/* calculate over-all length */
915912
xb = &rqstp->rq_res;
916913
xb->len = xb->head[0].iov_len +

net/sunrpc/svcsock.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,8 @@ static int svc_udp_sendto(struct svc_rqst *rqstp)
527527
unsigned int uninitialized_var(sent);
528528
int err;
529529

530+
svc_release_udp_skb(rqstp);
531+
530532
svc_set_cmsg_data(rqstp, cmh);
531533

532534
err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, 0, &sent);
@@ -1076,6 +1078,8 @@ static int svc_tcp_sendto(struct svc_rqst *rqstp)
10761078
unsigned int uninitialized_var(sent);
10771079
int err;
10781080

1081+
svc_release_skb(rqstp);
1082+
10791083
err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, marker, &sent);
10801084
xdr_free_bvec(xdr);
10811085
if (err < 0 || sent != (xdr->len + sizeof(marker)))

net/sunrpc/xprtrdma/svc_rdma_recvfrom.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,26 @@ void svc_rdma_recv_ctxt_put(struct svcxprt_rdma *rdma,
223223
svc_rdma_recv_ctxt_destroy(rdma, ctxt);
224224
}
225225

226+
/**
227+
* svc_rdma_release_rqst - Release transport-specific per-rqst resources
228+
* @rqstp: svc_rqst being released
229+
*
230+
* Ensure that the recv_ctxt is released whether or not a Reply
231+
* was sent. For example, the client could close the connection,
232+
* or svc_process could drop an RPC, before the Reply is sent.
233+
*/
234+
void svc_rdma_release_rqst(struct svc_rqst *rqstp)
235+
{
236+
struct svc_rdma_recv_ctxt *ctxt = rqstp->rq_xprt_ctxt;
237+
struct svc_xprt *xprt = rqstp->rq_xprt;
238+
struct svcxprt_rdma *rdma =
239+
container_of(xprt, struct svcxprt_rdma, sc_xprt);
240+
241+
rqstp->rq_xprt_ctxt = NULL;
242+
if (ctxt)
243+
svc_rdma_recv_ctxt_put(rdma, ctxt);
244+
}
245+
226246
static int __svc_rdma_post_recv(struct svcxprt_rdma *rdma,
227247
struct svc_rdma_recv_ctxt *ctxt)
228248
{
@@ -820,6 +840,8 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
820840
__be32 *p;
821841
int ret;
822842

843+
rqstp->rq_xprt_ctxt = NULL;
844+
823845
spin_lock(&rdma_xprt->sc_rq_dto_lock);
824846
ctxt = svc_rdma_next_recv_ctxt(&rdma_xprt->sc_read_complete_q);
825847
if (ctxt) {

net/sunrpc/xprtrdma/svc_rdma_sendto.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -926,12 +926,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
926926
ret = svc_rdma_send_reply_msg(rdma, sctxt, rctxt, rqstp);
927927
if (ret < 0)
928928
goto err1;
929-
ret = 0;
930-
931-
out:
932-
rqstp->rq_xprt_ctxt = NULL;
933-
svc_rdma_recv_ctxt_put(rdma, rctxt);
934-
return ret;
929+
return 0;
935930

936931
err2:
937932
if (ret != -E2BIG && ret != -EINVAL)
@@ -940,16 +935,14 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
940935
ret = svc_rdma_send_error_msg(rdma, sctxt, rqstp);
941936
if (ret < 0)
942937
goto err1;
943-
ret = 0;
944-
goto out;
938+
return 0;
945939

946940
err1:
947941
svc_rdma_send_ctxt_put(rdma, sctxt);
948942
err0:
949943
trace_svcrdma_send_failed(rqstp, ret);
950944
set_bit(XPT_CLOSE, &xprt->xpt_flags);
951-
ret = -ENOTCONN;
952-
goto out;
945+
return -ENOTCONN;
953946
}
954947

955948
/**

net/sunrpc/xprtrdma/svc_rdma_transport.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
7171
struct sockaddr *sa, int salen,
7272
int flags);
7373
static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt);
74-
static void svc_rdma_release_rqst(struct svc_rqst *);
7574
static void svc_rdma_detach(struct svc_xprt *xprt);
7675
static void svc_rdma_free(struct svc_xprt *xprt);
7776
static int svc_rdma_has_wspace(struct svc_xprt *xprt);
@@ -552,10 +551,6 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
552551
return NULL;
553552
}
554553

555-
static void svc_rdma_release_rqst(struct svc_rqst *rqstp)
556-
{
557-
}
558-
559554
/*
560555
* When connected, an svc_xprt has at least two references:
561556
*

0 commit comments

Comments
 (0)