summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2026-02-26 09:47:36 -0500
committerChuck Lever <chuck.lever@oracle.com>2026-03-29 21:25:09 -0400
commit22cc2ba5c27a500040d13cecb1dbfc3e4bccab81 (patch)
treef0b2913a712ef9caa4782417f6053484ac9caba7
parentee66b9e3e1c69efc986f3932555f07121c3460a7 (diff)
SUNRPC: Handle NULL entries in svc_rqst_release_pages
svc_rqst_release_pages() releases response pages between rq_respages and rq_next_page. It currently passes the entire range to release_pages(), which does not expect NULL entries. A subsequent patch preserves the rq_next_page pointer in svc_rdma_save_io_pages() so that it accurately records how many response pages were consumed. After that change, the range [rq_respages, rq_next_page) can contain NULL entries where pages have already been transferred to a send context. Iterate through the range entry by entry, skipping NULLs, to handle this case correctly. Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-rw-r--r--net/sunrpc/svc.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 9abef638b1e0..0ce16e9abdf6 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -990,18 +990,24 @@ EXPORT_SYMBOL_GPL(svc_rqst_replace_page);
* svc_rqst_release_pages - Release Reply buffer pages
* @rqstp: RPC transaction context
*
- * Release response pages that might still be in flight after
- * svc_send, and any spliced filesystem-owned pages.
+ * Release response pages in the range [rq_respages, rq_next_page).
+ * NULL entries in this range are skipped, allowing transports to
+ * transfer pages to a send context before this function runs.
*/
void svc_rqst_release_pages(struct svc_rqst *rqstp)
{
- int i, count = rqstp->rq_next_page - rqstp->rq_respages;
-
- if (count) {
- release_pages(rqstp->rq_respages, count);
- for (i = 0; i < count; i++)
- rqstp->rq_respages[i] = NULL;
+ struct page **pp;
+
+ for (pp = rqstp->rq_respages; pp < rqstp->rq_next_page; pp++) {
+ if (*pp) {
+ if (!folio_batch_add(&rqstp->rq_fbatch,
+ page_folio(*pp)))
+ __folio_batch_release(&rqstp->rq_fbatch);
+ *pp = NULL;
+ }
}
+ if (rqstp->rq_fbatch.nr)
+ __folio_batch_release(&rqstp->rq_fbatch);
}
/**