cxgbei: Rework the pdu_append_data hook to support M_WAITOK.

- Only allocate 16K jumbo mbufs if the region of data to be
  appended is sufficiently large, and use a loop.

- Use m_getm2() to allocate a chain for data less than 16K, or
  if m_getjcl() fails.

- Use ENOMEM as the return value instead of '1' if the hook fails due
  to a memory allocation error.

Sponsored by:	Chelsio Communications
Differential Revision:	https://reviews.freebsd.org/D29909
This commit is contained in:
John Baldwin 2021-05-14 12:17:14 -07:00
parent 46bee8043e
commit 31df8ff73e

View File

@ -324,35 +324,70 @@ int
icl_cxgbei_conn_pdu_append_data(struct icl_conn *ic, struct icl_pdu *ip,
const void *addr, size_t len, int flags)
{
struct mbuf *m;
#ifdef INVARIANTS
struct icl_cxgbei_pdu *icp = ip_to_icp(ip);
#endif
struct mbuf *m, *m_tail;
const char *src;
MPASS(icp->icp_signature == CXGBEI_PDU_SIGNATURE);
MPASS(ic == ip->ip_conn);
KASSERT(len > 0, ("%s: len is %jd", __func__, (intmax_t)len));
m = ip->ip_data_mbuf;
if (m == NULL) {
m_tail = ip->ip_data_mbuf;
if (m_tail != NULL)
for (; m_tail->m_next != NULL; m_tail = m_tail->m_next)
;
src = (const char *)addr;
/* Allocate as jumbo mbufs of size MJUM16BYTES. */
while (len >= MJUM16BYTES) {
m = m_getjcl(M_NOWAIT, MT_DATA, 0, MJUM16BYTES);
if (__predict_false(m == NULL)) {
if ((flags & M_WAITOK) != 0) {
/* Fall back to non-jumbo mbufs. */
break;
}
return (ENOMEM);
}
memcpy(mtod(m, void *), src, MJUM16BYTES);
m->m_len = MJUM16BYTES;
if (ip->ip_data_mbuf == NULL) {
ip->ip_data_mbuf = m_tail = m;
ip->ip_data_len = MJUM16BYTES;
} else {
m_tail->m_next = m;
m_tail = m_tail->m_next;
ip->ip_data_len += MJUM16BYTES;
}
src += MJUM16BYTES;
len -= MJUM16BYTES;
}
/* Allocate mbuf chain for the remaining data. */
if (len != 0) {
m = m_getm2(NULL, len, flags, MT_DATA, 0);
if (__predict_false(m == NULL))
return (ENOMEM);
ip->ip_data_mbuf = m;
}
if (__predict_true(m_append(m, len, addr) != 0)) {
ip->ip_data_len += len;
MPASS(ip->ip_data_len <= ic->ic_max_data_segment_length);
return (0);
} else {
if (flags & M_WAITOK) {
CXGBE_UNIMPLEMENTED("fail safe append");
if (ip->ip_data_mbuf == NULL) {
ip->ip_data_mbuf = m;
ip->ip_data_len = len;
} else {
m_tail->m_next = m;
ip->ip_data_len += len;
}
ip->ip_data_len = m_length(m, NULL);
return (1);
for (; m != NULL; m = m->m_next) {
m->m_len = min(len, M_SIZE(m));
memcpy(mtod(m, void *), src, m->m_len);
src += m->m_len;
len -= m->m_len;
}
MPASS(len == 0);
}
MPASS(ip->ip_data_len <= ic->ic_max_data_segment_length);
return (0);
}
void