xprtrdma: Clear receive-side ownership pointers on release

Three small ownership-state cleanups land the transport in a
state that lets future reviewers reason about each pointer
locally rather than tracing the whole reply path:

rpcrdma_rep_put() clears rep->rr_rqst before the rep enters
rb_free_reps so that no rep on the free list still carries a
stale rqst pointer.  rpcrdma_reply_handler() and
rpcrdma_unpin_rqst() are the only sites that set rr_rqst;
rpcrdma_reply_handler() hands the rep through
rpcrdma_rep_put(), and rpcrdma_unpin_rqst() NULLs rr_rqst
directly because its error path abandons the rep for
teardown cleanup rather than returning it to rb_free_reps.

rpcrdma_reply_put() NULLs req->rl_reply before calling
rpcrdma_rep_put().  The previous order placed the rep on
rb_free_reps while req->rl_reply still pointed at it; the
window was harmless because xprt_rdma_free_slot() holds the
req exclusively across the pair, but closing it makes the
invariant 'rep on rb_free_reps implies no req references it'
strictly checkable.

rpcrdma_sendctx_unmap() and rpcrdma_sendctx_cancel() clear
req->rl_sendctx after dropping the sendctx pointer in the
sendctx ring.  Without this, req->rl_sendctx survives across
Send completion and points at a sendctx that may already have
been reassigned by rpcrdma_sendctx_get_locked() to a different
req.  No caller dereferences the stale pointer today --
rpcrdma_prepare_send_sges() overwrites it before the next
Send -- but a NULL is a more honest representation of 'the
Send is no longer outstanding' and lets the assertion patch
that follows trip on any future regression.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
This commit is contained in:
Chuck Lever 2026-05-26 10:14:04 -04:00 committed by Anna Schumaker
parent 64bf689205
commit 2ae8e7afbc
2 changed files with 14 additions and 2 deletions

View File

@ -493,6 +493,7 @@ void rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc)
rpcrdma_sendctx_dma_unmap(sc);
sc->sc_req = NULL;
req->rl_sendctx = NULL;
rpcrdma_req_put(req);
}
@ -501,8 +502,11 @@ void rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc)
*/
static void rpcrdma_sendctx_cancel(struct rpcrdma_sendctx *sc)
{
struct rpcrdma_req *req = sc->sc_req;
rpcrdma_sendctx_dma_unmap(sc);
sc->sc_req = NULL;
req->rl_sendctx = NULL;
}
/* Prepare an SGE for the RPC-over-RDMA transport header.

View File

@ -1043,9 +1043,15 @@ static struct rpcrdma_rep *rpcrdma_rep_get_locked(struct rpcrdma_buffer *buf)
* @buf: buffer pool
* @rep: rep to release
*
* The rep's transient association with an rpc_rqst, established
* by rpcrdma_reply_handler() and torn down here, must not survive
* onto rb_free_reps: rpcrdma_post_recvs() pulls reps from the free
* list to re-post them, and a non-NULL rr_rqst on a free-listed rep
* would imply the rep is still referenced by a req.
*/
void rpcrdma_rep_put(struct rpcrdma_buffer *buf, struct rpcrdma_rep *rep)
{
rep->rr_rqst = NULL;
llist_add(&rep->rr_node, &buf->rb_free_reps);
}
@ -1247,9 +1253,11 @@ rpcrdma_mr_get(struct rpcrdma_xprt *r_xprt)
*/
void rpcrdma_reply_put(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req)
{
if (req->rl_reply) {
rpcrdma_rep_put(buffers, req->rl_reply);
struct rpcrdma_rep *rep = req->rl_reply;
if (rep) {
req->rl_reply = NULL;
rpcrdma_rep_put(buffers, rep);
}
}