]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
xprtrdma: Prevent leak of rpcrdma_rep objects
authorChuck Lever <chuck.lever@oracle.com>
Fri, 7 Dec 2018 16:11:44 +0000 (11:11 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Dec 2019 08:20:59 +0000 (09:20 +0100)
[ Upstream commit 07e10308ee5da8e6132e0b737ece1c99dd651fb6 ]

If a reply has been processed but the RPC is later retransmitted
anyway, the req->rl_reply field still contains the only pointer to
the old rpcrdma rep. When the next reply comes in, the reply handler
will stomp on the rl_reply field, leaking the old rep.

A trace event is added to capture such leaks.

This problem seems to be worsened by the restructuring of the RPC
Call path in v4.20. Fully addressing this issue will require at
least a re-architecture of the disconnect logic, which is not
appropriate during -rc.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
include/trace/events/rpcrdma.h
net/sunrpc/xprtrdma/rpc_rdma.c

index 53df203b8057afd417ebbcb93a298f51af791a49..4c91cadd1871d682891fb15d623ae77c830b6467 100644 (file)
@@ -917,6 +917,34 @@ TRACE_EVENT(xprtrdma_cb_setup,
 DEFINE_CB_EVENT(xprtrdma_cb_call);
 DEFINE_CB_EVENT(xprtrdma_cb_reply);
 
+TRACE_EVENT(xprtrdma_leaked_rep,
+       TP_PROTO(
+               const struct rpc_rqst *rqst,
+               const struct rpcrdma_rep *rep
+       ),
+
+       TP_ARGS(rqst, rep),
+
+       TP_STRUCT__entry(
+               __field(unsigned int, task_id)
+               __field(unsigned int, client_id)
+               __field(u32, xid)
+               __field(const void *, rep)
+       ),
+
+       TP_fast_assign(
+               __entry->task_id = rqst->rq_task->tk_pid;
+               __entry->client_id = rqst->rq_task->tk_client->cl_clid;
+               __entry->xid = be32_to_cpu(rqst->rq_xid);
+               __entry->rep = rep;
+       ),
+
+       TP_printk("task:%u@%u xid=0x%08x rep=%p",
+               __entry->task_id, __entry->client_id, __entry->xid,
+               __entry->rep
+       )
+);
+
 /**
  ** Server-side RPC/RDMA events
  **/
index c8ae983c6cc017ae342ac71604625e25bb7fe777..f2eaf264726be9bbf37ab5a63175a1d9d7ea83b8 100644 (file)
@@ -1360,6 +1360,10 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep)
        spin_unlock(&xprt->recv_lock);
 
        req = rpcr_to_rdmar(rqst);
+       if (req->rl_reply) {
+               trace_xprtrdma_leaked_rep(rqst, req->rl_reply);
+               rpcrdma_recv_buffer_put(req->rl_reply);
+       }
        req->rl_reply = rep;
        rep->rr_rqst = rqst;
        clear_bit(RPCRDMA_REQ_F_PENDING, &req->rl_flags);