diff options
author | Sam Leffler <sam@FreeBSD.org> | 2008-01-17 21:25:09 +0000 |
---|---|---|
committer | Sam Leffler <sam@FreeBSD.org> | 2008-01-17 21:25:09 +0000 |
commit | eeb76a1889b36f16bded9cfc8140b4cabcf6e792 (patch) | |
tree | 08d1ba96d0307c83ac3232beee589e8446489976 /sys/kern/uipc_mbuf.c | |
parent | 7500fac915ea79d73461185f90fccb2026f8c62d (diff) | |
download | src-eeb76a1889b36f16bded9cfc8140b4cabcf6e792.tar.gz src-eeb76a1889b36f16bded9cfc8140b4cabcf6e792.zip |
promote ath_defrag to m_collapse (and retire private+unused
m_collapse from cxgb)
Reviewed by: pyun, jhb, kmacy
MFC after: 2 weeks
Notes
Notes:
svn path=/head/; revision=175414
Diffstat (limited to 'sys/kern/uipc_mbuf.c')
-rw-r--r-- | sys/kern/uipc_mbuf.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index 3fefecc17b83..a7fa18c83bbd 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -1539,6 +1539,92 @@ nospace: return (NULL); } +/* + * Defragment an mbuf chain, returning at most maxfrags separate + * mbufs+clusters. If this is not possible NULL is returned and + * the original mbuf chain is left in it's present (potentially + * modified) state. We use two techniques: collapsing consecutive + * mbufs and replacing consecutive mbufs by a cluster. + * + * NB: this should really be named m_defrag but that name is taken + */ +struct mbuf * +m_collapse(struct mbuf *m0, int how, int maxfrags) +{ + struct mbuf *m, *n, *n2, **prev; + u_int curfrags; + + /* + * Calculate the current number of frags. + */ + curfrags = 0; + for (m = m0; m != NULL; m = m->m_next) + curfrags++; + /* + * First, try to collapse mbufs. Note that we always collapse + * towards the front so we don't need to deal with moving the + * pkthdr. This may be suboptimal if the first mbuf has much + * less data than the following. + */ + m = m0; +again: + for (;;) { + n = m->m_next; + if (n == NULL) + break; + if ((m->m_flags & M_RDONLY) == 0 && + n->m_len < M_TRAILINGSPACE(m)) { + bcopy(mtod(n, void *), mtod(m, char *) + m->m_len, + n->m_len); + m->m_len += n->m_len; + m->m_next = n->m_next; + m_free(n); + if (--curfrags <= maxfrags) + return m0; + } else + m = n; + } + KASSERT(maxfrags > 1, + ("maxfrags %u, but normal collapse failed", maxfrags)); + /* + * Collapse consecutive mbufs to a cluster. + */ + prev = &m0->m_next; /* NB: not the first mbuf */ + while ((n = *prev) != NULL) { + if ((n2 = n->m_next) != NULL && + n->m_len + n2->m_len < MCLBYTES) { + m = m_getcl(how, MT_DATA, 0); + if (m == NULL) + goto bad; + bcopy(mtod(n, void *), mtod(m, void *), n->m_len); + bcopy(mtod(n2, void *), mtod(m, char *) + n->m_len, + n2->m_len); + m->m_len = n->m_len + n2->m_len; + m->m_next = n2->m_next; + *prev = m; + m_free(n); + m_free(n2); + if (--curfrags <= maxfrags) /* +1 cl -2 mbufs */ + return m0; + /* + * Still not there, try the normal collapse + * again before we allocate another cluster. + */ + goto again; + } + prev = &n->m_next; + } + /* + * No place where we can collapse to a cluster; punt. + * This can occur if, for example, you request 2 frags + * but the packet requires that both be clusters (we + * never reallocate the first mbuf to avoid moving the + * packet header). + */ +bad: + return NULL; +} + #ifdef MBUF_STRESS_TEST /* |