aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2021-05-14 19:17:14 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2021-05-14 19:17:14 +0000
commit31df8ff73e3aa809146fae9baa6a96e1adf8526b (patch)
treedc2d72ef29f0a091c8c7bfe80f216662aa49e4d9
parent46bee8043ee2bd352d420cd573e0364ca45f813e (diff)
downloadsrc-31df8ff73e3aa809146fae9baa6a96e1adf8526b.tar.gz
src-31df8ff73e3aa809146fae9baa6a96e1adf8526b.zip
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
-rw-r--r--sys/dev/cxgbe/cxgbei/icl_cxgbei.c65
1 files changed, 50 insertions, 15 deletions
diff --git a/sys/dev/cxgbe/cxgbei/icl_cxgbei.c b/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
index 5770599eeeef..f91b9ee38616 100644
--- a/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
+++ b/sys/dev/cxgbe/cxgbei/icl_cxgbei.c
@@ -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 (__predict_false(m == NULL)) {
+ if ((flags & M_WAITOK) != 0) {
+ /* Fall back to non-jumbo mbufs. */
+ break;
+ }
return (ENOMEM);
-
- ip->ip_data_mbuf = m;
+ }
+ 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;
}
- 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");
+ /* 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);
+ 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