git: 01dd6a83b5ff - main - nvmf: Add a transport hook to limit the size of host data transfers

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Mon, 10 Nov 2025 15:51:21 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=01dd6a83b5ffce7a99ab8a7c2c9dcb82088357cd

commit 01dd6a83b5ffce7a99ab8a7c2c9dcb82088357cd
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2025-11-10 15:50:47 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2025-11-10 15:50:47 +0000

    nvmf: Add a transport hook to limit the size of host data transfers
    
    Smart NIC offload transports may have a cap on the size of the largest
    data PDU that can be received.  Allow these transports to enforce a
    cap on the size of an I/O request submitted by the nvmf(4) host.
    
    NB: The controller is able to advertise a maximum-supported PDU size
    during TCP negotiation, but there is no way in the protocol to
    advertise a maximum size that the host can receive.
    
    Sponsored by:   Chelsio Communications
---
 sys/dev/nvmf/nvmf_tcp.c                | 7 +++++++
 sys/dev/nvmf/nvmf_transport.c          | 6 ++++++
 sys/dev/nvmf/nvmf_transport.h          | 8 ++++++++
 sys/dev/nvmf/nvmf_transport_internal.h | 3 +++
 4 files changed, 24 insertions(+)

diff --git a/sys/dev/nvmf/nvmf_tcp.c b/sys/dev/nvmf/nvmf_tcp.c
index e50d7ff48d2b..0e31c0495775 100644
--- a/sys/dev/nvmf/nvmf_tcp.c
+++ b/sys/dev/nvmf/nvmf_tcp.c
@@ -1602,6 +1602,12 @@ tcp_free_qpair(struct nvmf_qpair *nq)
 	tcp_release_qpair(qp);
 }
 
+static uint64_t
+tcp_max_xfer_size(struct nvmf_qpair *nq)
+{
+	return (0);
+}
+
 static struct nvmf_capsule *
 tcp_allocate_capsule(struct nvmf_qpair *nq, int how)
 {
@@ -1872,6 +1878,7 @@ tcp_send_controller_data(struct nvmf_capsule *nc, uint32_t data_offset,
 struct nvmf_transport_ops tcp_ops = {
 	.allocate_qpair = tcp_allocate_qpair,
 	.free_qpair = tcp_free_qpair,
+	.max_xfer_size = tcp_max_xfer_size,
 	.allocate_capsule = tcp_allocate_capsule,
 	.free_capsule = tcp_free_capsule,
 	.transmit_capsule = tcp_transmit_capsule,
diff --git a/sys/dev/nvmf/nvmf_transport.c b/sys/dev/nvmf/nvmf_transport.c
index 1d3f5ea4cf69..d552393f7adf 100644
--- a/sys/dev/nvmf/nvmf_transport.c
+++ b/sys/dev/nvmf/nvmf_transport.c
@@ -188,6 +188,12 @@ nvmf_sqhd_valid(struct nvmf_capsule *nc)
 	return (nc->nc_sqhd_valid);
 }
 
+uint64_t
+nvmf_max_xfer_size(struct nvmf_qpair *qp)
+{
+	return (qp->nq_ops->max_xfer_size(qp));
+}
+
 uint8_t
 nvmf_validate_command_capsule(struct nvmf_capsule *nc)
 {
diff --git a/sys/dev/nvmf/nvmf_transport.h b/sys/dev/nvmf/nvmf_transport.h
index b192baeaccc1..38b661ab3c91 100644
--- a/sys/dev/nvmf/nvmf_transport.h
+++ b/sys/dev/nvmf/nvmf_transport.h
@@ -81,6 +81,14 @@ void *nvmf_capsule_sqe(struct nvmf_capsule *nc);
 void *nvmf_capsule_cqe(struct nvmf_capsule *nc);
 bool	nvmf_sqhd_valid(struct nvmf_capsule *nc);
 
+/* Host-specific APIs. */
+
+/*
+ * Largest I/O request size for a single command supported by the
+ * transport.  If the transport does not have a limit, returns 0.
+ */
+uint64_t nvmf_max_xfer_size(struct nvmf_qpair *qp);
+
 /* Controller-specific APIs. */
 
 /*
diff --git a/sys/dev/nvmf/nvmf_transport_internal.h b/sys/dev/nvmf/nvmf_transport_internal.h
index eb819a5c83b9..511aac120fdc 100644
--- a/sys/dev/nvmf/nvmf_transport_internal.h
+++ b/sys/dev/nvmf/nvmf_transport_internal.h
@@ -25,6 +25,9 @@ struct nvmf_transport_ops {
 	    const nvlist_t *nvl);
 	void (*free_qpair)(struct nvmf_qpair *qp);
 
+	/* Limit on transfer size. */
+	uint64_t (*max_xfer_size)(struct nvmf_qpair *qp);
+
 	/* Capsule operations. */
 	struct nvmf_capsule *(*allocate_capsule)(struct nvmf_qpair *qp,
 	    int how);