* [PATCH 6.6.y 2/4] svcrdma: Fix SQ wake-ups
2026-09-09 0:36 ` [PATCH 6.6.y 1/4] svcrdma: Add back svcxprt_rdma::sc_read_complete_q Sasha Levin
@ 2026-09-09 0:36 ` Sasha Levin
2026-09-09 0:36 ` [PATCH 6.6.y 3/4] svcrdma: Fix retry loop in svc_rdma_send() Sasha Levin
2026-09-09 0:36 ` [PATCH 6.6.y 4/4] svcrdma: Reject inline replies that overflow the pull-up buffer Sasha Levin
2 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-09-09 0:36 UTC (permalink / raw)
To: stable; +Cc: Chuck Lever, Sasha Levin
From: Chuck Lever <chuck.lever@oracle.com>
[ Upstream commit 5b9a85899c93430ff5173748fbcb79f28af21388 ]
Ensure there is a wake-up when increasing sc_sq_avail.
Likewise, if a wake-up is done, sc_sq_avail needs to be updated,
otherwise the wait_event() conditional is never going to be met.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
For the stable backport, retain the existing one-argument SQ tracepoint.
Use the existing wake-up helper both when returning an SQ entry after
failed reservation and when ib_post_send() fails, and retry as soon as
one entry is available.
Also prepare this tree for 0fbe20dfe74b ("svcrdma: Reject inline replies
that overflow the pull-up buffer"). Pass the Write chunk list directly
to the two existing pull-up helpers, deriving it locally in
svc_rdma_map_reply_msg() so its external interface stays unchanged.
Make the nonempty Reply chunk branch explicit in svc_rdma_sendto(),
retaining the stable send_reply_chunk implementation. This aligns the
target's merge context without importing newer WR-chain machinery or
adding functions. The target's overflow check remains in the target.
The preceding sc_read_complete_q dependency also introduced a
svc_rdma_read_complete() path that refers to the absent rc_pages field.
This stable tree still waits synchronously in svc_rdma_process_read_list()
and has no producer for sc_read_complete_q. Drop that unreachable helper,
its dequeue branch, and its label, retaining the existing synchronous
Read handling and the queue's declaration/initialization/flush support.
This fixes the inherited build failure without adding functions or
backporting the asynchronous Read machinery.
Stable-dep-of: 0fbe20dfe74b ("svcrdma: Reject inline replies that overflow the pull-up buffer")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 32 ----------------------
net/sunrpc/xprtrdma/svc_rdma_sendto.c | 36 ++++++++++++++-----------
2 files changed, 20 insertions(+), 48 deletions(-)
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index b83671f9d64db..d968dd4c48a14 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -764,30 +764,6 @@ static bool svc_rdma_is_reverse_direction_reply(struct svc_xprt *xprt,
return true;
}
-static noinline void svc_rdma_read_complete(struct svc_rqst *rqstp,
- struct svc_rdma_recv_ctxt *ctxt)
-{
- int i;
-
- /* Transfer the Read chunk pages into @rqstp.rq_pages, replacing
- * the rq_pages that were already allocated for this rqstp.
- */
- release_pages(rqstp->rq_respages, ctxt->rc_page_count);
- for (i = 0; i < ctxt->rc_page_count; i++)
- rqstp->rq_pages[i] = ctxt->rc_pages[i];
-
- /* Update @rqstp's result send buffer to start after the
- * last page in the RDMA Read payload.
- */
- rqstp->rq_respages = &rqstp->rq_pages[ctxt->rc_page_count];
- rqstp->rq_next_page = rqstp->rq_respages + 1;
-
- /* Prevent svc_rdma_recv_ctxt_put() from releasing the
- * pages in ctxt::rc_pages a second time.
- */
- ctxt->rc_page_count = 0;
-}
-
/**
* svc_rdma_recvfrom - Receive an RPC call
* @rqstp: request structure into which to receive an RPC Call
@@ -833,13 +809,6 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
rqstp->rq_xprt_ctxt = NULL;
spin_lock(&rdma_xprt->sc_rq_dto_lock);
- ctxt = svc_rdma_next_recv_ctxt(&rdma_xprt->sc_read_complete_q);
- if (ctxt) {
- list_del(&ctxt->rc_list);
- spin_unlock_bh(&rdma_xprt->sc_rq_dto_lock);
- svc_rdma_read_complete(rqstp, ctxt);
- goto complete;
- }
ctxt = svc_rdma_next_recv_ctxt(&rdma_xprt->sc_rq_dto_q);
if (ctxt)
list_del(&ctxt->rc_list);
@@ -877,7 +846,6 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
goto out_readfail;
}
-complete:
rqstp->rq_xprt_ctxt = ctxt;
rqstp->rq_prot = IPPROTO_MAX;
svc_xprt_copy_addrs(rqstp, xprt);
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index c6644cca52c57..3247a0aa2004b 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -326,11 +326,11 @@ int svc_rdma_send(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt)
/* If the SQ is full, wait until an SQ entry is available */
while (1) {
if ((atomic_dec_return(&rdma->sc_sq_avail) < 0)) {
+ svc_rdma_wake_send_waiters(rdma, 1);
percpu_counter_inc(&svcrdma_stat_sq_starve);
trace_svcrdma_sq_full(rdma);
- atomic_inc(&rdma->sc_sq_avail);
wait_event(rdma->sc_send_wait,
- atomic_read(&rdma->sc_sq_avail) > 1);
+ atomic_read(&rdma->sc_sq_avail) > 0);
if (test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags))
return -ENOTCONN;
trace_svcrdma_sq_retry(rdma);
@@ -346,7 +346,7 @@ int svc_rdma_send(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt)
trace_svcrdma_sq_post_err(rdma, ret);
svc_xprt_deferred_close(&rdma->sc_xprt);
- wake_up(&rdma->sc_send_wait);
+ svc_rdma_wake_send_waiters(rdma, 1);
return ret;
}
@@ -653,7 +653,7 @@ static int svc_rdma_xb_count_sges(const struct xdr_buf *xdr,
* svc_rdma_pull_up_needed - Determine whether to use pull-up
* @rdma: controlling transport
* @sctxt: send_ctxt for the Send WR
- * @rctxt: Write and Reply chunks provided by client
+ * @write_pcl: Write chunk list provided by client
* @xdr: xdr_buf containing RPC message to transmit
*
* Returns:
@@ -662,7 +662,7 @@ static int svc_rdma_xb_count_sges(const struct xdr_buf *xdr,
*/
static bool svc_rdma_pull_up_needed(const struct svcxprt_rdma *rdma,
const struct svc_rdma_send_ctxt *sctxt,
- const struct svc_rdma_recv_ctxt *rctxt,
+ const struct svc_rdma_pcl *write_pcl,
const struct xdr_buf *xdr)
{
/* Resources needed for the transport header */
@@ -672,7 +672,7 @@ static bool svc_rdma_pull_up_needed(const struct svcxprt_rdma *rdma,
};
int ret;
- ret = pcl_process_nonpayloads(&rctxt->rc_write_pcl, xdr,
+ ret = pcl_process_nonpayloads(write_pcl, xdr,
svc_rdma_xb_count_sges, &args);
if (ret < 0)
return false;
@@ -728,7 +728,7 @@ static int svc_rdma_xb_linearize(const struct xdr_buf *xdr,
* svc_rdma_pull_up_reply_msg - Copy Reply into a single buffer
* @rdma: controlling transport
* @sctxt: send_ctxt for the Send WR; xprt hdr is already prepared
- * @rctxt: Write and Reply chunks provided by client
+ * @write_pcl: Write chunk list provided by client
* @xdr: prepared xdr_buf containing RPC message
*
* The device is not capable of sending the reply directly.
@@ -743,7 +743,7 @@ static int svc_rdma_xb_linearize(const struct xdr_buf *xdr,
*/
static int svc_rdma_pull_up_reply_msg(const struct svcxprt_rdma *rdma,
struct svc_rdma_send_ctxt *sctxt,
- const struct svc_rdma_recv_ctxt *rctxt,
+ const struct svc_rdma_pcl *write_pcl,
const struct xdr_buf *xdr)
{
struct svc_rdma_pullup_data args = {
@@ -751,7 +751,7 @@ static int svc_rdma_pull_up_reply_msg(const struct svcxprt_rdma *rdma,
};
int ret;
- ret = pcl_process_nonpayloads(&rctxt->rc_write_pcl, xdr,
+ ret = pcl_process_nonpayloads(write_pcl, xdr,
svc_rdma_xb_linearize, &args);
if (ret < 0)
return ret;
@@ -779,6 +779,7 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma,
const struct svc_rdma_recv_ctxt *rctxt,
const struct xdr_buf *xdr)
{
+ const struct svc_rdma_pcl *write_pcl = &rctxt->rc_write_pcl;
struct svc_rdma_map_data args = {
.md_rdma = rdma,
.md_ctxt = sctxt,
@@ -797,10 +798,10 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma,
/* For pull-up, svc_rdma_send() will sync the transport header.
* No additional DMA mapping is necessary.
*/
- if (svc_rdma_pull_up_needed(rdma, sctxt, rctxt, xdr))
- return svc_rdma_pull_up_reply_msg(rdma, sctxt, rctxt, xdr);
+ if (svc_rdma_pull_up_needed(rdma, sctxt, write_pcl, xdr))
+ return svc_rdma_pull_up_reply_msg(rdma, sctxt, write_pcl, xdr);
- return pcl_process_nonpayloads(&rctxt->rc_write_pcl, xdr,
+ return pcl_process_nonpayloads(write_pcl, xdr,
svc_rdma_xb_dma_map, &args);
}
@@ -972,10 +973,13 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
if (!p)
goto put_ctxt;
- ret = svc_rdma_send_reply_chunk(rdma, rctxt, &rqstp->rq_res);
- if (ret < 0)
- goto reply_chunk;
- rc_size = ret;
+ rc_size = 0;
+ if (!pcl_is_empty(&rctxt->rc_reply_pcl)) {
+ ret = svc_rdma_send_reply_chunk(rdma, rctxt, &rqstp->rq_res);
+ if (ret < 0)
+ goto reply_chunk;
+ rc_size = ret;
+ }
*p++ = *rdma_argp;
*p++ = *(rdma_argp + 1);
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 6.6.y 3/4] svcrdma: Fix retry loop in svc_rdma_send()
2026-09-09 0:36 ` [PATCH 6.6.y 1/4] svcrdma: Add back svcxprt_rdma::sc_read_complete_q Sasha Levin
2026-09-09 0:36 ` [PATCH 6.6.y 2/4] svcrdma: Fix SQ wake-ups Sasha Levin
@ 2026-09-09 0:36 ` Sasha Levin
2026-09-09 0:36 ` [PATCH 6.6.y 4/4] svcrdma: Reject inline replies that overflow the pull-up buffer Sasha Levin
2 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-09-09 0:36 UTC (permalink / raw)
To: stable; +Cc: Chuck Lever, Sasha Levin
From: Chuck Lever <chuck.lever@oracle.com>
[ Upstream commit fc709d82dda6405862a681cc425386bfaf049539 ]
Don't call ib_post_send() at all if the transport is already
shutting down.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
For this stable dependency, retain the existing SQ tracepoint signatures:
full/retry take only rdma, and post_err takes rdma and status. This tree
has no local completion-ID copy in svc_rdma_send(), so omit the upstream
comment about copying context fields and describe the existing single
Send WR instead of a WR chain.
Keep the shutdown check at the top of the retry loop, before reserving
an SQ entry or posting a Send. On ib_post_send() failure, trace the actual
status, schedule transport closure, restore the reserved SQ entry and
wake waiters; return -ENOTCONN for either failure or shutdown.
The preceding dependency already prepared the pull-up helper arguments
and Reply chunk branch for 0fbe20dfe74b. Preserve that preparation; the
target applies cleanly with a three-way application. No functions added.
Stable-dep-of: 0fbe20dfe74b ("svcrdma: Reject inline replies that overflow the pull-up buffer")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sunrpc/xprtrdma/svc_rdma_sendto.c | 28 ++++++++++++++++-----------
1 file changed, 17 insertions(+), 11 deletions(-)
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index 3247a0aa2004b..175d3a0478c26 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -307,8 +307,9 @@ static void svc_rdma_wc_send(struct ib_cq *cq, struct ib_wc *wc)
* @rdma: transport on which to post the WR
* @ctxt: send ctxt with a Send WR ready to post
*
- * Returns zero if the Send WR was posted successfully. Otherwise, a
- * negative errno is returned.
+ * Return values:
+ * %0: @ctxt's Send WR was posted successfully
+ * %-ENOTCONN: The connection was lost
*/
int svc_rdma_send(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt)
{
@@ -324,30 +325,35 @@ int svc_rdma_send(struct svcxprt_rdma *rdma, struct svc_rdma_send_ctxt *ctxt)
DMA_TO_DEVICE);
/* If the SQ is full, wait until an SQ entry is available */
- while (1) {
+ while (!test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags)) {
if ((atomic_dec_return(&rdma->sc_sq_avail) < 0)) {
svc_rdma_wake_send_waiters(rdma, 1);
+
+ /* When the transport is torn down, assume
+ * ib_drain_sq() will trigger enough Send
+ * completions to wake us. The XPT_CLOSE test
+ * above should then cause the while loop to
+ * exit.
+ */
percpu_counter_inc(&svcrdma_stat_sq_starve);
trace_svcrdma_sq_full(rdma);
wait_event(rdma->sc_send_wait,
atomic_read(&rdma->sc_sq_avail) > 0);
- if (test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags))
- return -ENOTCONN;
trace_svcrdma_sq_retry(rdma);
continue;
}
trace_svcrdma_post_send(ctxt);
ret = ib_post_send(rdma->sc_qp, wr, NULL);
- if (ret)
+ if (ret) {
+ trace_svcrdma_sq_post_err(rdma, ret);
+ svc_xprt_deferred_close(&rdma->sc_xprt);
+ svc_rdma_wake_send_waiters(rdma, 1);
break;
+ }
return 0;
}
-
- trace_svcrdma_sq_post_err(rdma, ret);
- svc_xprt_deferred_close(&rdma->sc_xprt);
- svc_rdma_wake_send_waiters(rdma, 1);
- return ret;
+ return -ENOTCONN;
}
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 6.6.y 4/4] svcrdma: Reject inline replies that overflow the pull-up buffer
2026-09-09 0:36 ` [PATCH 6.6.y 1/4] svcrdma: Add back svcxprt_rdma::sc_read_complete_q Sasha Levin
2026-09-09 0:36 ` [PATCH 6.6.y 2/4] svcrdma: Fix SQ wake-ups Sasha Levin
2026-09-09 0:36 ` [PATCH 6.6.y 3/4] svcrdma: Fix retry loop in svc_rdma_send() Sasha Levin
@ 2026-09-09 0:36 ` Sasha Levin
2 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-09-09 0:36 UTC (permalink / raw)
To: stable; +Cc: Chuck Lever, Chris Mason, Sasha Levin
From: Chuck Lever <cel@kernel.org>
[ Upstream commit 0fbe20dfe74b783d255bf389a6ea77aa25dc7860 ]
An RPC-over-RDMA client can request a reply, such as an NFS READ
payload, without providing a Write list or a Reply chunk to carry
it. When such a reply needs more scatter/gather entries than the
device's Send Queue supports, svc_rdma_pull_up_needed() selects
pull-up and svc_rdma_pull_up_reply_msg() linearizes the whole
reply into sctxt->sc_xprt_buf. That buffer is only sc_max_req_size
bytes, while the reply on this path is bounded only by the client's
request, so svc_rdma_xb_linearize() copies past the end of the
buffer and corrupts adjacent slab memory. The oversized length is
then stored in sc_sges[0].length and posted, so the device also
reads beyond the mapped region.
The SGE-exhaustion branch is the only pull-up path that can exceed
the buffer: the threshold branch pulls up only replies smaller
than RPCRDMA_PULLUP_THRESH, and replies that fit the device's SGE
budget are sent directly without linearization. Make
svc_rdma_pull_up_needed() report -E2BIG when the reply it would
pull up cannot fit sc_max_req_size, and fail the request with
ERR_CHUNK as RFC 8166 Section 4.5.3 directs rather than dropping
the connection.
The helper no longer answers a simple yes/no question: it now
reports pull-up, no pull-up, or -E2BIG for a reply too large to
linearize. Rename svc_rdma_pull_up_needed() to
svc_rdma_check_pull_up() so its name no longer implies a boolean
predicate.
Fixes: e248aa7be86e ("svcrdma: Remove max_sge check at connect time")
Cc: stable@vger.kernel.org
Reported-by: Chris Mason <clm@meta.com>
Assisted-by: kres:claude-opus-4-7
Link: https://patch.msgid.link/20260623014728.826032-1-cel@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
net/sunrpc/xprtrdma/svc_rdma_sendto.c | 47 ++++++++++++++++++---------
1 file changed, 32 insertions(+), 15 deletions(-)
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index 175d3a0478c26..078157b66418f 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -656,20 +656,21 @@ static int svc_rdma_xb_count_sges(const struct xdr_buf *xdr,
}
/**
- * svc_rdma_pull_up_needed - Determine whether to use pull-up
+ * svc_rdma_check_pull_up - Determine whether to use pull-up
* @rdma: controlling transport
* @sctxt: send_ctxt for the Send WR
* @write_pcl: Write chunk list provided by client
* @xdr: xdr_buf containing RPC message to transmit
*
* Returns:
- * %true if pull-up must be used
- * %false otherwise
+ * %1 if pull-up must be used
+ * %0 if pull-up is not needed
+ * %-E2BIG if the reply is too large to be pulled up
*/
-static bool svc_rdma_pull_up_needed(const struct svcxprt_rdma *rdma,
- const struct svc_rdma_send_ctxt *sctxt,
- const struct svc_rdma_pcl *write_pcl,
- const struct xdr_buf *xdr)
+static int svc_rdma_check_pull_up(const struct svcxprt_rdma *rdma,
+ const struct svc_rdma_send_ctxt *sctxt,
+ const struct svc_rdma_pcl *write_pcl,
+ const struct xdr_buf *xdr)
{
/* Resources needed for the transport header */
struct svc_rdma_pullup_data args = {
@@ -681,11 +682,22 @@ static bool svc_rdma_pull_up_needed(const struct svcxprt_rdma *rdma,
ret = pcl_process_nonpayloads(write_pcl, xdr,
svc_rdma_xb_count_sges, &args);
if (ret < 0)
- return false;
+ return 0;
if (args.pd_length < RPCRDMA_PULLUP_THRESH)
- return true;
- return args.pd_num_sges >= rdma->sc_max_send_sges;
+ return 1;
+ if (args.pd_num_sges < rdma->sc_max_send_sges)
+ return 0;
+
+ /*
+ * The reply has too many SGEs to Send inline, so it has to be
+ * linearized into sc_xprt_buf. That buffer holds only
+ * sc_max_req_size bytes, so a larger reply cannot be pulled up.
+ * RFC 8166 Section 4.5.3 requires responding with ERR_CHUNK.
+ */
+ if (args.pd_length > rdma->sc_max_req_size)
+ return -E2BIG;
+ return 1;
}
/**
@@ -741,7 +753,7 @@ static int svc_rdma_xb_linearize(const struct xdr_buf *xdr,
* Assemble the elements of @xdr into the transport header buffer.
*
* Assumptions:
- * pull_up_needed has determined that @xdr will fit in the buffer.
+ * check_pull_up has determined that @xdr will fit in the buffer.
*
* Returns:
* %0 if pull-up was successful
@@ -775,6 +787,7 @@ static int svc_rdma_pull_up_reply_msg(const struct svcxprt_rdma *rdma,
*
* Returns:
* %0 if DMA mapping was successful.
+ * %-E2BIG if the reply is too large to be pulled up
* %-EMSGSIZE if a buffer manipulation problem occurred
* %-EIO if DMA mapping failed
*
@@ -790,6 +803,7 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma,
.md_rdma = rdma,
.md_ctxt = sctxt,
};
+ int ret;
/* Set up the (persistently-mapped) transport header SGE. */
sctxt->sc_send_wr.num_sge = 1;
@@ -804,7 +818,10 @@ int svc_rdma_map_reply_msg(struct svcxprt_rdma *rdma,
/* For pull-up, svc_rdma_send() will sync the transport header.
* No additional DMA mapping is necessary.
*/
- if (svc_rdma_pull_up_needed(rdma, sctxt, write_pcl, xdr))
+ ret = svc_rdma_check_pull_up(rdma, sctxt, write_pcl, xdr);
+ if (ret < 0)
+ return ret;
+ if (ret)
return svc_rdma_pull_up_reply_msg(rdma, sctxt, write_pcl, xdr);
return pcl_process_nonpayloads(write_pcl, xdr,
@@ -983,7 +1000,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
if (!pcl_is_empty(&rctxt->rc_reply_pcl)) {
ret = svc_rdma_send_reply_chunk(rdma, rctxt, &rqstp->rq_res);
if (ret < 0)
- goto reply_chunk;
+ goto send_err;
rc_size = ret;
}
@@ -1004,10 +1021,10 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
ret = svc_rdma_send_reply_msg(rdma, sctxt, rctxt, rqstp);
if (ret < 0)
- goto put_ctxt;
+ goto send_err;
return 0;
-reply_chunk:
+send_err:
if (ret != -E2BIG && ret != -EINVAL)
goto put_ctxt;
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread