[RFC PATCH v1 1/8] sunrpc: introduce XDRBUF_P2PDMA flag

From: Pranjal Shrivastava

Date: Tue Oct 06 2026 - 19:35:07 EST


The NFS client will soon pass PCI peer-to-peer DMA (P2PDMA) pages
to the transport as READ or WRITE payload. Only a transport that
can DMA directly to and from that memory may move it.

Introduce XDRBUF_P2PDMA and a helper, xprt_rqst_has_p2pdma(), to
mark and detect requests whose pages are P2PDMA memory. The TCP
(including TLS), UDP and AF_LOCAL transports return -EREMOTEIO for
such a request before touching the socket. iov_iter_extract_pages()
returns the same error today for P2PDMA pages the caller did not allow.
Thus, users see no new error code.

Signed-off-by: Pranjal Shrivastava <praan@xxxxxxxxxx>
---
include/linux/sunrpc/xdr.h | 1 +
include/linux/sunrpc/xprt.h | 5 +++++
net/sunrpc/xprtsock.c | 12 ++++++++++++
3 files changed, 18 insertions(+)

diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index b102b4f21e6b..79526f47be2d 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -65,6 +65,7 @@ struct xdr_buf {
#define XDRBUF_READ 0x01 /* target of file read */
#define XDRBUF_WRITE 0x02 /* source of file write */
#define XDRBUF_SPARSE_PAGES 0x04 /* Page array is sparse */
+#define XDRBUF_P2PDMA 0x08 /* Pages are P2PDMA memory */

unsigned int buflen, /* Total length of storage buffer */
len; /* Length of XDR encoded message */
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index a82045804d34..08ab04fa4509 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -134,6 +134,11 @@ static inline int xprt_rqst_add_seqno(struct rpc_rqst *req, u32 seqno)
return 0;
}

+static inline bool xprt_rqst_has_p2pdma(const struct rpc_rqst *req)
+{
+ return (req->rq_snd_buf.flags | req->rq_rcv_buf.flags) & XDRBUF_P2PDMA;
+}
+
/* RPC transport layer security policies */
enum xprtsec_policies {
RPC_XPRTSEC_NONE = 0,
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index f5a5136327ba..9fa6d7ec207e 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -962,6 +962,10 @@ static int xs_local_send_request(struct rpc_rqst *req)
unsigned int sent;
int status;

+ /* Sockets move data via CPU accesses, so refuse P2PDMA pages */
+ if (xprt_rqst_has_p2pdma(req))
+ return -EREMOTEIO;
+
/* Close the stream if the previous transmission was incomplete */
if (xs_send_request_was_aborted(transport, req)) {
xprt_force_disconnect(xprt);
@@ -1031,6 +1035,10 @@ static int xs_udp_send_request(struct rpc_rqst *req)
unsigned int sent;
int status;

+ /* Sockets move data via CPU accesses, so refuse P2PDMA pages */
+ if (xprt_rqst_has_p2pdma(req))
+ return -EREMOTEIO;
+
xs_pktdump("packet data:",
req->rq_svec->iov_base,
req->rq_svec->iov_len);
@@ -1118,6 +1126,10 @@ static int xs_tcp_send_request(struct rpc_rqst *req)
unsigned int sent;
int status;

+ /* Sockets move data via CPU accesses, so refuse P2PDMA pages */
+ if (xprt_rqst_has_p2pdma(req))
+ return -EREMOTEIO;
+
/* Close the stream if the previous transmission was incomplete */
if (xs_send_request_was_aborted(transport, req)) {
if (transport->sock != NULL)
--
2.56.0.rc1.315.gc6ed9934b7-goog