[PATCH 5.6 004/194] xprtrdma: Fix trace point use-after-free race

Greg Kroah-Hartman
2020-05-18T18:14:09Z

From: Chuck Lever <chuck.lever@oracle.com>

[ Upstream commit bdb2ce82818577ba6e57b7d68b698b8d17329281 ]

It's not safe to use resources pointed to by the @send_wr of
ib_post_send() _after_ that function returns. Those resources are
typically freed by the Send completion handler, which can run before
ib_post_send() returns.

Thus the trace points currently around ib_post_send() in the
client's RPC/RDMA transport are a hazard, even when they are
disabled. Rearrange them so that they touch the Work Request only
_before_ ib_post_send() is invoked.

Fixes: ab03eff58eb5 ("xprtrdma: Add trace points in RPC Call transmit paths")
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 | 12 ++++--------
net/sunrpc/xprtrdma/verbs.c | 2 +-
2 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/include/trace/events/rpcrdma.h b/include/trace/events/rpcrdma.h
index fa14adf242353..43158151821c4 100644
--- a/include/trace/events/rpcrdma.h
+++ b/include/trace/events/rpcrdma.h
@@ -721,11 +721,10 @@ TRACE_EVENT(xprtrdma_prepsend_failed,

TRACE_EVENT(xprtrdma_post_send,
TP_PROTO(
- const struct rpcrdma_req *req,
- int status
+ const struct rpcrdma_req *req
),

- TP_ARGS(req, status),
+ TP_ARGS(req),

TP_STRUCT__entry(
__field(const void *, req)
@@ -734,7 +733,6 @@ TRACE_EVENT(xprtrdma_post_send,
__field(unsigned int, client_id)
__field(int, num_sge)
__field(int, signaled)
- __field(int, status)
),

TP_fast_assign(
@@ -747,15 +745,13 @@ TRACE_EVENT(xprtrdma_post_send,
__entry->sc = req->rl_sendctx;
__entry->num_sge = req->rl_wr.num_sge;
__entry->signaled = req->rl_wr.send_flags & IB_SEND_SIGNALED;
- __entry->status = status;
),

- TP_printk("task:%u@%u req=%p sc=%p (%d SGE%s) %sstatus=%d",
+ TP_printk("task:%u@%u req=%p sc=%p (%d SGE%s) %s",
__entry->task_id, __entry->client_id,
__entry->req, __entry->sc, __entry->num_sge,
(__entry->num_sge == 1 ? "" : "s"),
- (__entry->signaled ? "signaled " : ""),
- __entry->status
+ (__entry->signaled ? "signaled" : "")
)
);

diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 4b9fbf69b4955..a48b99f3682c3 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -1523,8 +1523,8 @@ int rpcrdma_post_sends(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req)
--ep->rep_send_count;
}

+ trace_xprtrdma_post_send(req);
rc = frwr_send(r_xprt, req);
- trace_xprtrdma_post_send(req, rc);
if (rc)
return -ENOTCONN;
return 0;
--
2.20.1