diff options
author | andre <andre@FreeBSD.org> | 2006-11-02 17:37:22 +0000 |
---|---|---|
committer | andre <andre@FreeBSD.org> | 2006-11-02 17:37:22 +0000 |
commit | d1cc5b22d78b6226d2469a4044e415f618ab894a (patch) | |
tree | 8d00998734eae5e0a44b4233c21fbe5312956685 /sys/kern/uipc_mbuf.c | |
parent | 72eb46ae51bea2bdc5f1deb6728f9bdd26092ed5 (diff) | |
download | FreeBSD-src-d1cc5b22d78b6226d2469a4044e415f618ab894a.zip FreeBSD-src-d1cc5b22d78b6226d2469a4044e415f618ab894a.tar.gz |
Rename m_getm() to m_getm2() and rewrite it to allocate up to page sized
mbuf clusters. Add a flags parameter to accept M_PKTHDR and M_EOR mbuf
chain flags. Provide compatibility macro for m_getm() calling m_getm2()
with M_PKTHDR set.
Rewrite m_uiotombuf() to use m_getm2() for mbuf allocation and do the
uiomove() in a tight loop over the mbuf chain. Add a flags parameter to
accept mbuf flags to be passed to m_getm2(). Adjust all callers for the
extra parameter.
Sponsored by: TCP/IP Optimization Fundraise 2005
MFC after: 3 month
Diffstat (limited to 'sys/kern/uipc_mbuf.c')
-rw-r--r-- | sys/kern/uipc_mbuf.c | 175 |
1 files changed, 89 insertions, 86 deletions
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c index 216ff54..3a4fb4c 100644 --- a/sys/kern/uipc_mbuf.c +++ b/sys/kern/uipc_mbuf.c @@ -94,61 +94,61 @@ SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragrandomfailures, CTLFLAG_RW, * chain. */ struct mbuf * -m_getm(struct mbuf *m, int len, int how, short type) +m_getm2(struct mbuf *m, int len, int how, short type, int flags) { - struct mbuf *mb, *top, *cur, *mtail; - int num, rem; - int i; + struct mbuf *mb, *nm = NULL, *mtail = NULL; - KASSERT(len >= 0, ("m_getm(): len is < 0")); + KASSERT(len >= 0, ("%s: len is < 0", __func__)); - /* If m != NULL, we will append to the end of that chain. */ - if (m != NULL) - for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next); - else - mtail = NULL; + /* Validate flags. */ + flags &= (M_PKTHDR | M_EOR); - /* - * Calculate how many mbufs+clusters ("packets") we need and how much - * leftover there is after that and allocate the first mbuf+cluster - * if required. - */ - num = len / MCLBYTES; - rem = len % MCLBYTES; - top = cur = NULL; - if (num > 0) { - if ((top = cur = m_getcl(how, type, 0)) == NULL) - goto failed; - top->m_len = 0; - } - num--; - - for (i = 0; i < num; i++) { - mb = m_getcl(how, type, 0); - if (mb == NULL) - goto failed; - mb->m_len = 0; - cur = (cur->m_next = mb); - } - if (rem > 0) { - mb = (rem >= MINCLSIZE) ? - m_getcl(how, type, 0) : m_get(how, type); - if (mb == NULL) - goto failed; - mb->m_len = 0; - if (cur == NULL) - top = mb; + /* Packet header mbuf must be first in chain. */ + if ((flags & M_PKTHDR) && m != NULL) + flags &= ~M_PKTHDR; + + /* Loop and append maximum sized mbufs to the chain tail. */ + while (len > 0) { + if (len > MCLBYTES) + mb = m_getjcl(how, type, (flags & M_PKTHDR), + MJUMPAGESIZE); + else if (len >= MINCLSIZE) + mb = m_getcl(how, type, (flags & M_PKTHDR)); + else if (flags & M_PKTHDR) + mb = m_gethdr(how, type); else - cur->m_next = mb; + mb = m_get(how, type); + + /* Fail the whole operation if one mbuf can't be allocated. */ + if (mb == NULL) { + if (nm != NULL) + m_freem(nm); + return (NULL); + } + + /* Book keeping. */ + len -= (mb->m_flags & M_EXT) ? mb->m_ext.ext_size : + ((mb->m_flags & M_PKTHDR) ? MHLEN : MLEN); + if (mtail != NULL) + mtail->m_next = mb; + else + nm = mb; + mtail = mb; + flags &= ~M_PKTHDR; /* Only valid on the first mbuf. */ } + if (flags & M_EOR) + mtail->m_flags |= M_EOR; /* Only valid on the last mbuf. */ + + /* If mbuf was supplied, append new chain to the end of it. */ + if (m != NULL) { + for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next) + ; + mtail->m_next = nm; + mtail->m_flags &= ~M_EOR; + } else + m = nm; - if (mtail != NULL) - mtail->m_next = top; - return top; -failed: - if (top != NULL) - m_freem(top); - return NULL; + return (m); } /* @@ -1610,55 +1610,58 @@ nospace: #endif +/* + * Copy the contents of uio into a properly sized mbuf chain. + */ struct mbuf * -m_uiotombuf(struct uio *uio, int how, int len, int align) +m_uiotombuf(struct uio *uio, int how, int len, int align, int flags) { - struct mbuf *m_new = NULL, *m_final = NULL; - int progress = 0, error = 0, length, total; + struct mbuf *m, *mb; + int error, length, total; + int progress = 0; + /* + * len can be zero or an arbitrary large value bound by + * the total data supplied by the uio. + */ if (len > 0) total = min(uio->uio_resid, len); else total = uio->uio_resid; + + /* + * The smallest unit returned by m_getm2() is a single mbuf + * with pkthdr. We can't align past it. Align align itself. + */ + if (align) + align &= ~(sizeof(long) - 1); if (align >= MHLEN) - goto nospace; - if (total + align > MHLEN) - m_final = m_getcl(how, MT_DATA, M_PKTHDR); - else - m_final = m_gethdr(how, MT_DATA); - if (m_final == NULL) - goto nospace; - m_final->m_data += align; - m_new = m_final; - while (progress < total) { - length = total - progress; - if (length > MCLBYTES) - length = MCLBYTES; - if (m_new == NULL) { - if (length > MLEN) - m_new = m_getcl(how, MT_DATA, 0); - else - m_new = m_get(how, MT_DATA); - if (m_new == NULL) - goto nospace; + return (NULL); + + /* Give us all or nothing. */ + m = m_getm2(NULL, total + align, how, MT_DATA, flags); + if (m == NULL) + return (NULL); + m->m_data += align; + + /* Fill all mbufs with uio data and update header information. */ + for (mb = m; mb != NULL; mb = mb->m_next) { + length = min(M_TRAILINGSPACE(mb), total - progress); + + error = uiomove(mtod(mb, void *), length, uio); + if (error) { + m_freem(m); + return (NULL); } - error = uiomove(mtod(m_new, void *), length, uio); - if (error) - goto nospace; + + mb->m_len = length; progress += length; - m_new->m_len = length; - if (m_new != m_final) - m_cat(m_final, m_new); - m_new = NULL; + if (flags & M_PKTHDR) + m->m_pkthdr.len += length; } - m_fixhdr(m_final); - return (m_final); -nospace: - if (m_new) - m_free(m_new); - if (m_final) - m_freem(m_final); - return (NULL); + KASSERT(progress == total, ("%s: progress != total", __func__)); + + return (m); } /* |