summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorAlexander Bluhm <bluhm@cvs.openbsd.org>2011-04-10 23:25:03 +0000
committerAlexander Bluhm <bluhm@cvs.openbsd.org>2011-04-10 23:25:03 +0000
commitc9cd1d1912597449202f0e007473207271f18388 (patch)
treef631c386bfc76f1827d1df4c0c5aa3589ecc4ed1 /sys/kern
parentf374b593aec371e55fbf19040c154a01a3723e3e (diff)
Backout m_split_mbuf() from revision 1.150. It seems that m_split()
got broken. Most /usr/src/regress/sys/kern/splice/args-oobinline-* regression tests fail when they split an mbuf at out-of-band data. ok claudio@, deraadt@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/uipc_mbuf.c186
1 files changed, 100 insertions, 86 deletions
diff --git a/sys/kern/uipc_mbuf.c b/sys/kern/uipc_mbuf.c
index 4f5800d9d50..36390a9acb5 100644
--- a/sys/kern/uipc_mbuf.c
+++ b/sys/kern/uipc_mbuf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uipc_mbuf.c,v 1.153 2011/04/06 15:52:13 art Exp $ */
+/* $OpenBSD: uipc_mbuf.c,v 1.154 2011/04/10 23:25:02 bluhm Exp $ */
/* $NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $ */
/*
@@ -110,8 +110,6 @@ struct pool mclpools[MCLPOOLS];
int m_clpool(u_int);
-struct mbuf *m_split_mbuf(struct mbuf *, int, int, struct mbuf *);
-
int max_linkhdr; /* largest link-level header */
int max_protohdr; /* largest protocol header */
int max_hdr; /* largest link+protocol header */
@@ -1081,117 +1079,133 @@ m_getptr(struct mbuf *m, int loc, int *off)
}
/*
- * Inject a new mbuf chain of length len in mbuf chain m at
- * position off. Returns a pointer to the first injected mbuf, or
- * NULL on failure (m is left undisturbed). Note that if there is
- * enough space for an object of size len in the appropriate position,
+ * Inject a new mbuf chain of length siz in mbuf chain m0 at
+ * position len0. Returns a pointer to the first injected mbuf, or
+ * NULL on failure (m0 is left undisturbed). Note that if there is
+ * enough space for an object of size siz in the appropriate position,
* no memory will be allocated. Also, there will be no data movement in
- * the first off bytes (pointers to that will remain valid).
+ * the first len0 bytes (pointers to that will remain valid).
*
- * XXX It is assumed that len is less than the size of an mbuf at the moment.
+ * XXX It is assumed that siz is less than the size of an mbuf at the moment.
*/
struct mbuf *
-m_inject(struct mbuf *m, int off, int len, int wait)
+m_inject(struct mbuf *m0, int len0, int siz, int wait)
{
- struct mbuf *n, *o, *p;
- int off1;
-
- if (len > MHLEN || len <= 0)
- return (NULL);
+ struct mbuf *m, *n, *n2 = NULL, *n3;
+ unsigned len = len0, remain;
- if ((n = m_getptr(m, off, &off1)) == NULL)
- return (NULL);
-
- if ((o = m_get(wait, MT_DATA)) == NULL)
+ if ((siz >= MHLEN) || (len0 <= 0))
+ return (NULL);
+ for (m = m0; m && len > m->m_len; m = m->m_next)
+ len -= m->m_len;
+ if (m == NULL)
return (NULL);
+ remain = m->m_len - len;
+ if (remain == 0) {
+ if ((m->m_next) && (M_LEADINGSPACE(m->m_next) >= siz)) {
+ m->m_next->m_len += siz;
+ if (m0->m_flags & M_PKTHDR)
+ m0->m_pkthdr.len += siz;
+ m->m_next->m_data -= siz;
+ return m->m_next;
+ }
+ } else {
+ n2 = m_copym2(m, len, remain, wait);
+ if (n2 == NULL)
+ return (NULL);
+ }
- if ((p = m_split_mbuf(n, off1, wait, NULL)) == NULL) {
- m_freem(o);
+ MGET(n, wait, MT_DATA);
+ if (n == NULL) {
+ if (n2)
+ m_freem(n2);
return (NULL);
}
- o->m_len = len;
- o->m_next = p;
- n->m_next = o;
-
- if (m->m_flags & M_PKTHDR)
- m->m_pkthdr.len += len;
-
- return (o);
+ n->m_len = siz;
+ if (m0->m_flags & M_PKTHDR)
+ m0->m_pkthdr.len += siz;
+ m->m_len -= remain; /* Trim */
+ if (n2) {
+ for (n3 = n; n3->m_next != NULL; n3 = n3->m_next)
+ ;
+ n3->m_next = n2;
+ } else
+ n3 = n;
+ for (; n3->m_next != NULL; n3 = n3->m_next)
+ ;
+ n3->m_next = m->m_next;
+ m->m_next = n;
+ return n;
}
/*
- * Split a single mbuf, leaving the chain intact.
+ * Partition an mbuf chain in two pieces, returning the tail --
+ * all but the first len0 bytes. In case of failure, it returns NULL and
+ * attempts to restore the chain to its original state.
*/
struct mbuf *
-m_split_mbuf(struct mbuf *m, int off, int wait, struct mbuf *mhdr)
+m_split(struct mbuf *m0, int len0, int wait)
{
- struct mbuf *n;
- int copyhdr;
-
- if (off > m->m_len)
- return (NULL);
+ struct mbuf *m, *n;
+ unsigned len = len0, remain, olen;
- copyhdr = (mhdr && mhdr->m_flags & M_PKTHDR);
-
- if (copyhdr)
- n = m_gethdr(wait, MT_DATA);
- else
- n = m_get(wait, MT_DATA);
- if (!n)
+ for (m = m0; m && len > m->m_len; m = m->m_next)
+ len -= m->m_len;
+ if (m == NULL)
return (NULL);
-
- if (m->m_len - off > (copyhdr ? MHLEN : MLEN)) {
- MCLGET(n, wait);
- if (!(n->m_flags & M_EXT)) {
- m_free(n);
+ remain = m->m_len - len;
+ if (m0->m_flags & M_PKTHDR) {
+ MGETHDR(n, wait, m0->m_type);
+ if (n == NULL)
+ return (NULL);
+ if (m_dup_pkthdr(n, m0, wait)) {
+ m_freem(n);
return (NULL);
}
+ n->m_pkthdr.len -= len0;
+ olen = m0->m_pkthdr.len;
+ m0->m_pkthdr.len = len0;
+ if (m->m_flags & M_EXT)
+ goto extpacket;
+ if (remain > MHLEN) {
+ /* m can't be the lead packet */
+ MH_ALIGN(n, 0);
+ n->m_next = m_split(m, len, wait);
+ if (n->m_next == NULL) {
+ (void) m_free(n);
+ m0->m_pkthdr.len = olen;
+ return (NULL);
+ } else
+ return (n);
+ } else
+ MH_ALIGN(n, remain);
+ } else if (remain == 0) {
+ n = m->m_next;
+ m->m_next = NULL;
+ return (n);
+ } else {
+ MGET(n, wait, m->m_type);
+ if (n == NULL)
+ return (NULL);
+ M_ALIGN(n, remain);
}
-
- if (copyhdr && m_dup_pkthdr(mhdr, n, wait)) {
- m_free(n);
- return (NULL);
+extpacket:
+ if (m->m_flags & M_EXT) {
+ n->m_ext = m->m_ext;
+ MCLADDREFERENCE(m, n);
+ n->m_data = m->m_data + len;
+ } else {
+ bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
}
-
- bcopy(mtod(m, caddr_t) + off, mtod(n, caddr_t), m->m_len - off);
-
- n->m_len = m->m_len - off;
- m->m_len = off;
+ n->m_len = remain;
+ m->m_len = len;
n->m_next = m->m_next;
- m->m_next = n;
-
+ m->m_next = NULL;
return (n);
}
/*
- * Break mbuf chain into two parts at the specified offset.
- */
-struct mbuf *
-m_split(struct mbuf *m, int off, int wait)
-{
- struct mbuf *n, *o;
- int off1, copyhdr;
-
- copyhdr = m->m_flags & M_PKTHDR;
-
- if ((n = m_getptr(m, off, &off1)) == NULL)
- return (NULL);
-
- if ((o = m_split_mbuf(n, off1, wait, m)) == NULL)
- return (NULL);
-
- if (copyhdr) {
- o->m_pkthdr.len = m->m_pkthdr.len - off;
- m->m_pkthdr.len = off;
- }
-
- n->m_next = NULL;
-
- return (o);
-}
-
-/*
* Routine to copy from device local memory into mbufs.
*/
struct mbuf *