SUNRPC: Add svcxdr_encode_opaque_payload()

The encoder functions that xdrgen emits handle a variable-length
opaque with xdr_stream_encode_opaque(), which copies the opaque
content into the RPC buffer. On the server, an NFS READ payload
already resides in the pages of rqstp->rq_res, placed there by an
underlying file system read. Copying that payload into the RPC
Reply buffer adds a data copy on every READ and prevents a
transport capable of direct data placement from conveying the
payload separately from the rest of the Reply.

Add a helper that encodes a page-resident opaque by reference: it
encodes the length, inserts the payload pages into the XDR stream,
then marks the byte range as a result payload.

Generated code calls this helper, so its parameters are limited to
the xdr_stream and the payload length. It recovers the svc_rqst
with svcxdr_rqst(), and takes the reply's page array from the
stream's buffer.

Acked-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260908134234.512312-4-cel@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
This commit is contained in:
Chuck Lever 2026-09-08 09:42:27 -04:00
parent 4ab20626ad
commit e679ac4bb8

View File

@ -608,6 +608,41 @@ static inline void svcxdr_encode_opaque_pages(struct svc_rqst *rqstp,
xdr->page_ptr = rqstp->rq_next_page - 1;
}
/**
* svcxdr_encode_opaque_payload - Encode a page-resident opaque data item
* @xdr: xdr_stream to be updated
* @len: number of octets of content in the data item
*
* Context: Process context. @xdr must have been initialized by
* svcxdr_init_encode() and still be positioned in the reply
* head.
*
* Return:
* %true: Success
* %false: The reply head cannot hold the length prefix and XDR
* padding, or the transport could not accommodate the result payload
*/
static inline bool svcxdr_encode_opaque_payload(struct xdr_stream *xdr, u32 len)
{
struct svc_rqst *rqstp = svcxdr_rqst(xdr);
struct xdr_buf *buf = xdr->buf;
/*
* The length prefix and any pad word must land in the reply
* head. A prefix that spills into the first Reply page lands
* on the payload itself, and xdr_write_pages() BUGs when the
* pad word does not fit.
*/
if ((xdr->end - xdr->p) * XDR_UNIT < XDR_UNIT + xdr_pad_size(len))
return false;
if (xdr_stream_encode_u32(xdr, len) < 0)
return false;
svcxdr_encode_opaque_pages(rqstp, xdr, buf->pages, buf->page_base, len);
if (svc_encode_result_payload(rqstp, buf->head->iov_len, len) < 0)
return false;
return true;
}
/**
* svcxdr_set_auth_slack -
* @rqstp: RPC transaction