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
This commit is contained in:
John Baldwin 2024-09-05 17:14:36 -04:00
parent 157802238b
commit bedfac1f02

View File

@ -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,