diff options
Diffstat (limited to 'sys/kern/uipc_mbuf2.c')
-rw-r--r-- | sys/kern/uipc_mbuf2.c | 146 |
1 files changed, 104 insertions, 42 deletions
diff --git a/sys/kern/uipc_mbuf2.c b/sys/kern/uipc_mbuf2.c index b00bf7f..f2ce41f 100644 --- a/sys/kern/uipc_mbuf2.c +++ b/sys/kern/uipc_mbuf2.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: uipc_mbuf2.c,v 1.15 2000/02/22 14:01:37 itojun Exp $ */ +/* $KAME: uipc_mbuf2.c,v 1.29 2001/02/14 13:42:10 itojun Exp $ */ /* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */ /* @@ -75,6 +75,9 @@ #include <sys/mbuf.h> #include <sys/mutex.h> +/* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */ +static struct mbuf *m_dup1 __P((struct mbuf *, int, int, int)); + /* * ensure that [off, off + len) is contiguous on the mbuf chain "m". * packet chain before "off" is kept untouched. @@ -125,20 +128,47 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp) } /* + * XXX: This code is flawed because it considers a "writable" mbuf + * data region to require all of the following: + * (i) mbuf _has_ to have M_EXT set; if it is just a regular + * mbuf, it is still not considered "writable." + * (ii) since mbuf has M_EXT, the ext_type _has_ to be + * EXT_CLUSTER. Anything else makes it non-writable. + * (iii) M_WRITABLE() must evaluate true. + * Ideally, the requirement should only be (iii). + * + * If we're writable, we're sure we're writable, because the ref. count + * cannot increase from 1, as that would require posession of mbuf + * n by someone else (which is impossible). However, if we're _not_ + * writable, we may eventually become writable )if the ref. count drops + * to 1), but we'll fail to notice it unless we re-evaluate + * M_WRITABLE(). For now, we only evaluate once at the beginning and + * live with this. + */ + /* + * XXX: This is dumb. If we're just a regular mbuf with no M_EXT, + * then we're not "writable," according to this code. + */ + writable = 0; + if ((n->m_flags & M_EXT) == 0 || + (n->m_ext.ext_type == EXT_CLUSTER && M_WRITABLE(n))) + writable = 1; + + /* * the target data is on <n, off>. * if we got enough data on the mbuf "n", we're done. */ - if ((off == 0 || offp) && len <= n->m_len - off) + if ((off == 0 || offp) && len <= n->m_len - off && writable) goto ok; /* - * when len < n->m_len - off and off != 0, it is a special case. + * when len <= n->m_len - off and off != 0, it is a special case. * len bytes from <n, off> sits in single mbuf, but the caller does * not like the starting position (off). * chop the current mbuf into two pieces, set off to 0. */ - if (len < n->m_len - off) { - o = m_copym(n, off, n->m_len - off, M_DONTWAIT); + if (len <= n->m_len - off) { + o = m_dup1(n, off, n->m_len - off, M_DONTWAIT); if (o == NULL) { m_freem(m); return NULL; /* ENOBUFS */ @@ -175,33 +205,6 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp) * easy cases first. * we need to use m_copydata() to get data from <n->m_next, 0>. */ - /* - * XXX: This code is flawed because it considers a "writable" mbuf - * data region to require all of the following: - * (i) mbuf _has_ to have M_EXT set; if it is just a regular - * mbuf, it is still not considered "writable." - * (ii) since mbuf has M_EXT, the ext_type _has_ to be - * EXT_CLUSTER. Anything else makes it non-writable. - * (iii) M_WRITABLE() must evaluate true. - * Ideally, the requirement should only be (iii). - * - * If we're writable, we're sure we're writable, because the ref. count - * cannot increase from 1, as that would require posession of mbuf - * n by someone else (which is impossible). However, if we're _not_ - * writable, we may eventually become writable )if the ref. count drops - * to 1), but we'll fail to notice it unless we re-evaluate - * M_WRITABLE(). For now, we only evaluate once at the beginning and - * live with this. - */ - /* - * XXX: This is dumb. If we're just a regular mbuf with no M_EXT, - * then we're not "writable," according to this code. - */ - writable = 0; - if ((n->m_flags & M_EXT) && (n->m_ext.ext_type == EXT_CLUSTER) && - M_WRITABLE(n)) - writable = 1; - if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen && writable) { m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len); @@ -225,18 +228,17 @@ m_pulldown(struct mbuf *m, int off, int len, int *offp) * on both end. */ MGET(o, M_DONTWAIT, m->m_type); - if (o == NULL) { - m_freem(m); - return NULL; /* ENOBUFS */ - } - if (len > MHLEN) { /* use MHLEN just for safety */ + if (o && len > MLEN) { MCLGET(o, M_DONTWAIT); if ((o->m_flags & M_EXT) == 0) { - m_freem(m); m_free(o); - return NULL; /* ENOBUFS */ + o = NULL; } } + if (!o) { + m_freem(m); + return NULL; /* ENOBUFS */ + } /* get hlen from <n, off> into <o, 0> */ o->m_len = hlen; bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen); @@ -265,12 +267,46 @@ ok: return n; } +static struct mbuf * +m_dup1(struct mbuf *m, int off, int len, int wait) +{ + struct mbuf *n; + int l; + int copyhdr; + + if (len > MCLBYTES) + return NULL; + if (off == 0 && (m->m_flags & M_PKTHDR) != 0) { + copyhdr = 1; + MGETHDR(n, wait, m->m_type); + l = MHLEN; + } else { + copyhdr = 0; + MGET(n, wait, m->m_type); + l = MLEN; + } + if (n && len > l) { + MCLGET(n, wait); + if ((n->m_flags & M_EXT) == 0) { + m_free(n); + n = NULL; + } + } + if (!n) + return NULL; + + if (copyhdr) + M_COPY_PKTHDR(n, m); + m_copydata(m, off, len, mtod(n, caddr_t)); + return n; +} + /* * pkthdr.aux chain manipulation. * we don't allow clusters at this moment. */ struct mbuf * -m_aux_add(struct mbuf *m, int af, int type) +m_aux_add2(struct mbuf *m, int af, int type, void *p) { struct mbuf *n; struct mauxtag *t; @@ -287,8 +323,10 @@ m_aux_add(struct mbuf *m, int af, int type) return NULL; t = mtod(n, struct mauxtag *); + bzero(t, sizeof(*t)); t->af = af; t->type = type; + t->p = p; n->m_data += sizeof(struct mauxtag); n->m_len = 0; n->m_next = m->m_pkthdr.aux; @@ -297,7 +335,7 @@ m_aux_add(struct mbuf *m, int af, int type) } struct mbuf * -m_aux_find(struct mbuf *m, int af, int type) +m_aux_find2(struct mbuf *m, int af, int type, void *p) { struct mbuf *n; struct mauxtag *t; @@ -307,12 +345,30 @@ m_aux_find(struct mbuf *m, int af, int type) for (n = m->m_pkthdr.aux; n; n = n->m_next) { t = (struct mauxtag *)n->m_dat; - if (t->af == af && t->type == type) + if (n->m_data != ((caddr_t)t) + sizeof(struct mauxtag)) { + printf("m_aux_find: invalid m_data for mbuf=%p (%p %p)\n", n, t, n->m_data); + continue; + } + if (t->af == af && t->type == type && t->p == p) return n; } return NULL; } +struct mbuf * +m_aux_find(struct mbuf *m, int af, int type) +{ + + return m_aux_find2(m, af, type, NULL); +} + +struct mbuf * +m_aux_add(struct mbuf *m, int af, int type) +{ + + return m_aux_add2(m, af, type, NULL); +} + void m_aux_delete(struct mbuf *m, struct mbuf *victim) { @@ -327,6 +383,12 @@ m_aux_delete(struct mbuf *m, struct mbuf *victim) while (n) { t = (struct mauxtag *)n->m_dat; next = n->m_next; + if (n->m_data != ((caddr_t)t) + sizeof(struct mauxtag)) { + printf("m_aux_delete: invalid m_data for mbuf=%p (%p %p)\n", n, t, n->m_data); + prev = n; + n = next; + continue; + } if (n == victim) { if (prev) prev->m_next = n->m_next; |