The functions m_copym() and m_copypacket() return read-only copies,
because in the case of mbuf clusters they only increment the reference count rather than actually copying the data. Add comments to this effect, and add a new routine called m_dup() that returns a real, writable copy of an mbuf chain. This is preliminary work required for implementing 'ipfw tee'. Reviewed by: julian
This commit is contained in:
parent
63e2ac54d1
commit
1c38f2ea70
@ -423,6 +423,8 @@ m_prepend(m, len, how)
|
|||||||
* Make a copy of an mbuf chain starting "off0" bytes from the beginning,
|
* Make a copy of an mbuf chain starting "off0" bytes from the beginning,
|
||||||
* continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
|
* continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
|
||||||
* The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
|
* The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
|
||||||
|
* Note that the copy is read-only, because clusters are not copied,
|
||||||
|
* only their reference counts are incremented.
|
||||||
*/
|
*/
|
||||||
#define MCFail (mbstat.m_mcfail)
|
#define MCFail (mbstat.m_mcfail)
|
||||||
|
|
||||||
@ -499,6 +501,8 @@ nospace:
|
|||||||
/*
|
/*
|
||||||
* Copy an entire packet, including header (which must be present).
|
* Copy an entire packet, including header (which must be present).
|
||||||
* An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'.
|
* An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'.
|
||||||
|
* Note that the copy is read-only, because clusters are not copied,
|
||||||
|
* only their reference counts are incremented.
|
||||||
*/
|
*/
|
||||||
struct mbuf *
|
struct mbuf *
|
||||||
m_copypacket(m, how)
|
m_copypacket(m, how)
|
||||||
@ -592,6 +596,80 @@ m_copydata(m, off, len, cp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copy a packet header mbuf chain into a completely new chain, including
|
||||||
|
* copying any mbuf clusters. Use this instead of m_copypacket() when
|
||||||
|
* you need a writable copy of an mbuf chain.
|
||||||
|
*/
|
||||||
|
struct mbuf *
|
||||||
|
m_dup(m, how)
|
||||||
|
struct mbuf *m;
|
||||||
|
int how;
|
||||||
|
{
|
||||||
|
struct mbuf **p, *top = NULL;
|
||||||
|
int remain, moff, nsize;
|
||||||
|
|
||||||
|
/* Sanity check */
|
||||||
|
if (m == NULL)
|
||||||
|
return (0);
|
||||||
|
KASSERT((m->m_flags & M_PKTHDR) != 0, ("%s: !PKTHDR", __FUNCTION__));
|
||||||
|
|
||||||
|
/* While there's more data, get a new mbuf, tack it on, and fill it */
|
||||||
|
remain = m->m_pkthdr.len;
|
||||||
|
moff = 0;
|
||||||
|
p = ⊤
|
||||||
|
while (remain > 0 || top == NULL) { /* allow m->m_pkthdr.len == 0 */
|
||||||
|
struct mbuf *n;
|
||||||
|
|
||||||
|
/* Get the next new mbuf */
|
||||||
|
MGET(n, how, m->m_type);
|
||||||
|
if (n == NULL)
|
||||||
|
goto nospace;
|
||||||
|
if (top == NULL) { /* first one, must be PKTHDR */
|
||||||
|
M_COPY_PKTHDR(n, m);
|
||||||
|
nsize = MHLEN;
|
||||||
|
} else /* not the first one */
|
||||||
|
nsize = MLEN;
|
||||||
|
if (remain >= MINCLSIZE) {
|
||||||
|
MCLGET(n, how);
|
||||||
|
if ((n->m_flags & M_EXT) == 0) {
|
||||||
|
(void)m_free(n);
|
||||||
|
goto nospace;
|
||||||
|
}
|
||||||
|
nsize = MCLBYTES;
|
||||||
|
}
|
||||||
|
n->m_len = 0;
|
||||||
|
|
||||||
|
/* Link it into the new chain */
|
||||||
|
*p = n;
|
||||||
|
p = &n->m_next;
|
||||||
|
|
||||||
|
/* Copy data from original mbuf(s) into new mbuf */
|
||||||
|
while (n->m_len < nsize && m != NULL) {
|
||||||
|
int chunk = min(nsize - n->m_len, m->m_len - moff);
|
||||||
|
|
||||||
|
bcopy(m->m_data + moff, n->m_data + n->m_len, chunk);
|
||||||
|
moff += chunk;
|
||||||
|
n->m_len += chunk;
|
||||||
|
remain -= chunk;
|
||||||
|
if (moff == m->m_len) {
|
||||||
|
m = m->m_next;
|
||||||
|
moff = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check correct total mbuf length */
|
||||||
|
KASSERT((remain > 0 && m != NULL) || (remain == 0 && m == NULL),
|
||||||
|
("%s: bogus m_pkthdr.len", __FUNCTION__));
|
||||||
|
}
|
||||||
|
return (top);
|
||||||
|
|
||||||
|
nospace:
|
||||||
|
m_freem(top);
|
||||||
|
MCFail++;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Concatenate mbuf chain n to m.
|
* Concatenate mbuf chain n to m.
|
||||||
* Both chains must be of the same type (e.g. MT_DATA).
|
* Both chains must be of the same type (e.g. MT_DATA).
|
||||||
|
@ -417,6 +417,7 @@ struct mbuf *m_copym __P((struct mbuf *, int, int, int));
|
|||||||
struct mbuf *m_copypacket __P((struct mbuf *, int));
|
struct mbuf *m_copypacket __P((struct mbuf *, int));
|
||||||
struct mbuf *m_devget __P((char *, int, int, struct ifnet *,
|
struct mbuf *m_devget __P((char *, int, int, struct ifnet *,
|
||||||
void (*copy)(char *, caddr_t, u_int)));
|
void (*copy)(char *, caddr_t, u_int)));
|
||||||
|
struct mbuf *m_dup __P((struct mbuf *, int));
|
||||||
struct mbuf *m_free __P((struct mbuf *));
|
struct mbuf *m_free __P((struct mbuf *));
|
||||||
struct mbuf *m_get __P((int, int));
|
struct mbuf *m_get __P((int, int));
|
||||||
struct mbuf *m_getclr __P((int, int));
|
struct mbuf *m_getclr __P((int, int));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user