git: bedfac1f026f - main - nvmf_tcp: Fully honor kern.nvmf.tcp.max_transmit_data for C2H_DATA PDUs
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 05 Sep 2024 21:15:06 UTC
The branch main has been updated by jhb:
URL: https://cgit.FreeBSD.org/src/commit/?id=bedfac1f026fa8e2e6572ca380d89d74a01d5def
commit bedfac1f026fa8e2e6572ca380d89d74a01d5def
Author: John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-09-05 21:14:36 +0000
Commit: John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-09-05 21:14:36 +0000
nvmf_tcp: Fully honor kern.nvmf.tcp.max_transmit_data for C2H_DATA PDUs
The previous version of tcp_send_controller_data avoided sending a
chain of multiple mbufs that exceeded the limit, but if an individual
mbuf was larger than the limit it was sent as a single, over-sized
PDU. Fix by using m_split() to split individual mbufs larger than the
limit.
Note that this is not a protocol error, per se, as there is no limit
on C2H_DATA PDU lengths (unlike the MAXH2CDATA parameter). This fix
just honors the administrative limit more faithfully. This case is
also very unlikely with the default limit of 256k.
Sponsored by: Chelsio Communications
---
sys/dev/nvmf/nvmf_tcp.c | 31 +++++++++++++++++++------------
1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/sys/dev/nvmf/nvmf_tcp.c b/sys/dev/nvmf/nvmf_tcp.c
index 67d239b63faf..22275aaa835b 100644
--- a/sys/dev/nvmf/nvmf_tcp.c
+++ b/sys/dev/nvmf/nvmf_tcp.c
@@ -1784,7 +1784,6 @@ tcp_send_controller_data(struct nvmf_capsule *nc, uint32_t data_offset,
{
struct nvmf_tcp_qpair *qp = TQP(nc->nc_qpair);
struct nvme_sgl_descriptor *sgl;
- struct mbuf *n, *p;
uint32_t data_len;
bool last_pdu, last_xfer;
@@ -1813,21 +1812,29 @@ tcp_send_controller_data(struct nvmf_capsule *nc, uint32_t data_offset,
/* Queue one more C2H_DATA PDUs containing the data from 'm'. */
while (m != NULL) {
+ struct mbuf *n;
uint32_t todo;
- todo = m->m_len;
- p = m;
- n = p->m_next;
- while (n != NULL) {
- if (todo + n->m_len > qp->max_tx_data) {
- p->m_next = NULL;
- break;
- }
- todo += n->m_len;
- p = n;
+ if (m->m_len > qp->max_tx_data) {
+ n = m_split(m, qp->max_tx_data, M_WAITOK);
+ todo = m->m_len;
+ } else {
+ struct mbuf *p;
+
+ todo = m->m_len;
+ p = m;
n = p->m_next;
+ while (n != NULL) {
+ if (todo + n->m_len > qp->max_tx_data) {
+ p->m_next = NULL;
+ break;
+ }
+ todo += n->m_len;
+ p = n;
+ n = p->m_next;
+ }
+ MPASS(m_length(m, NULL) == todo);
}
- MPASS(m_length(m, NULL) == todo);
last_pdu = (n == NULL && last_xfer);
tcp_send_c2h_pdu(qp, nc->nc_sqe.cid, data_offset, m, todo,