Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_mbuf.c
Show First 20 Lines • Show All 263 Lines • ▼ Show 20 Lines | |||||
* Zones from which we allocate. | * Zones from which we allocate. | ||||
*/ | */ | ||||
uma_zone_t zone_mbuf; | uma_zone_t zone_mbuf; | ||||
uma_zone_t zone_clust; | uma_zone_t zone_clust; | ||||
uma_zone_t zone_pack; | uma_zone_t zone_pack; | ||||
uma_zone_t zone_jumbop; | uma_zone_t zone_jumbop; | ||||
uma_zone_t zone_jumbo9; | uma_zone_t zone_jumbo9; | ||||
uma_zone_t zone_jumbo16; | uma_zone_t zone_jumbo16; | ||||
uma_zone_t zone_ext_refcnt; | |||||
/* | /* | ||||
* Local prototypes. | * Local prototypes. | ||||
*/ | */ | ||||
static int mb_ctor_mbuf(void *, int, void *, int); | static int mb_ctor_mbuf(void *, int, void *, int); | ||||
static int mb_ctor_clust(void *, int, void *, int); | static int mb_ctor_clust(void *, int, void *, int); | ||||
static int mb_ctor_pack(void *, int, void *, int); | static int mb_ctor_pack(void *, int, void *, int); | ||||
static void mb_dtor_mbuf(void *, int, void *); | static void mb_dtor_mbuf(void *, int, void *); | ||||
static void mb_dtor_clust(void *, int, void *); | |||||
static void mb_dtor_pack(void *, int, void *); | static void mb_dtor_pack(void *, int, void *); | ||||
static int mb_zinit_pack(void *, int, int); | static int mb_zinit_pack(void *, int, int); | ||||
static void mb_zfini_pack(void *, int); | static void mb_zfini_pack(void *, int); | ||||
static void mb_reclaim(uma_zone_t, int); | static void mb_reclaim(uma_zone_t, int); | ||||
static void *mbuf_jumbo_alloc(uma_zone_t, vm_size_t, uint8_t *, int); | static void *mbuf_jumbo_alloc(uma_zone_t, vm_size_t, uint8_t *, int); | ||||
/* Ensure that MSIZE is a power of 2. */ | /* Ensure that MSIZE is a power of 2. */ | ||||
CTASSERT((((MSIZE - 1) ^ MSIZE) + 1) >> 1 == MSIZE); | CTASSERT((((MSIZE - 1) ^ MSIZE) + 1) >> 1 == MSIZE); | ||||
Show All 17 Lines | |||||
#endif | #endif | ||||
MSIZE - 1, UMA_ZONE_MAXBUCKET); | MSIZE - 1, UMA_ZONE_MAXBUCKET); | ||||
if (nmbufs > 0) | if (nmbufs > 0) | ||||
nmbufs = uma_zone_set_max(zone_mbuf, nmbufs); | nmbufs = uma_zone_set_max(zone_mbuf, nmbufs); | ||||
uma_zone_set_warning(zone_mbuf, "kern.ipc.nmbufs limit reached"); | uma_zone_set_warning(zone_mbuf, "kern.ipc.nmbufs limit reached"); | ||||
uma_zone_set_maxaction(zone_mbuf, mb_reclaim); | uma_zone_set_maxaction(zone_mbuf, mb_reclaim); | ||||
zone_clust = uma_zcreate(MBUF_CLUSTER_MEM_NAME, MCLBYTES, | zone_clust = uma_zcreate(MBUF_CLUSTER_MEM_NAME, MCLBYTES, | ||||
mb_ctor_clust, mb_dtor_clust, | mb_ctor_clust, | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
trash_init, trash_fini, | trash_dtor, trash_init, trash_fini, | ||||
#else | #else | ||||
NULL, NULL, | NULL, NULL, NULL, | ||||
#endif | #endif | ||||
UMA_ALIGN_PTR, UMA_ZONE_REFCNT); | UMA_ALIGN_PTR, 0); | ||||
if (nmbclusters > 0) | if (nmbclusters > 0) | ||||
nmbclusters = uma_zone_set_max(zone_clust, nmbclusters); | nmbclusters = uma_zone_set_max(zone_clust, nmbclusters); | ||||
uma_zone_set_warning(zone_clust, "kern.ipc.nmbclusters limit reached"); | uma_zone_set_warning(zone_clust, "kern.ipc.nmbclusters limit reached"); | ||||
uma_zone_set_maxaction(zone_clust, mb_reclaim); | uma_zone_set_maxaction(zone_clust, mb_reclaim); | ||||
zone_pack = uma_zsecond_create(MBUF_PACKET_MEM_NAME, mb_ctor_pack, | zone_pack = uma_zsecond_create(MBUF_PACKET_MEM_NAME, mb_ctor_pack, | ||||
mb_dtor_pack, mb_zinit_pack, mb_zfini_pack, zone_mbuf); | mb_dtor_pack, mb_zinit_pack, mb_zfini_pack, zone_mbuf); | ||||
/* Make jumbo frame zone too. Page size, 9k and 16k. */ | /* Make jumbo frame zone too. Page size, 9k and 16k. */ | ||||
zone_jumbop = uma_zcreate(MBUF_JUMBOP_MEM_NAME, MJUMPAGESIZE, | zone_jumbop = uma_zcreate(MBUF_JUMBOP_MEM_NAME, MJUMPAGESIZE, | ||||
mb_ctor_clust, mb_dtor_clust, | mb_ctor_clust, | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
trash_init, trash_fini, | trash_dtor, trash_init, trash_fini, | ||||
#else | #else | ||||
NULL, NULL, | NULL, NULL, NULL, | ||||
#endif | #endif | ||||
UMA_ALIGN_PTR, UMA_ZONE_REFCNT); | UMA_ALIGN_PTR, 0); | ||||
if (nmbjumbop > 0) | if (nmbjumbop > 0) | ||||
nmbjumbop = uma_zone_set_max(zone_jumbop, nmbjumbop); | nmbjumbop = uma_zone_set_max(zone_jumbop, nmbjumbop); | ||||
uma_zone_set_warning(zone_jumbop, "kern.ipc.nmbjumbop limit reached"); | uma_zone_set_warning(zone_jumbop, "kern.ipc.nmbjumbop limit reached"); | ||||
uma_zone_set_maxaction(zone_jumbop, mb_reclaim); | uma_zone_set_maxaction(zone_jumbop, mb_reclaim); | ||||
zone_jumbo9 = uma_zcreate(MBUF_JUMBO9_MEM_NAME, MJUM9BYTES, | zone_jumbo9 = uma_zcreate(MBUF_JUMBO9_MEM_NAME, MJUM9BYTES, | ||||
mb_ctor_clust, mb_dtor_clust, | mb_ctor_clust, | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
trash_init, trash_fini, | trash_dtor, trash_init, trash_fini, | ||||
#else | #else | ||||
NULL, NULL, | NULL, NULL, NULL, | ||||
#endif | #endif | ||||
UMA_ALIGN_PTR, UMA_ZONE_REFCNT); | UMA_ALIGN_PTR, 0); | ||||
uma_zone_set_allocf(zone_jumbo9, mbuf_jumbo_alloc); | uma_zone_set_allocf(zone_jumbo9, mbuf_jumbo_alloc); | ||||
if (nmbjumbo9 > 0) | if (nmbjumbo9 > 0) | ||||
nmbjumbo9 = uma_zone_set_max(zone_jumbo9, nmbjumbo9); | nmbjumbo9 = uma_zone_set_max(zone_jumbo9, nmbjumbo9); | ||||
uma_zone_set_warning(zone_jumbo9, "kern.ipc.nmbjumbo9 limit reached"); | uma_zone_set_warning(zone_jumbo9, "kern.ipc.nmbjumbo9 limit reached"); | ||||
uma_zone_set_maxaction(zone_jumbo9, mb_reclaim); | uma_zone_set_maxaction(zone_jumbo9, mb_reclaim); | ||||
zone_jumbo16 = uma_zcreate(MBUF_JUMBO16_MEM_NAME, MJUM16BYTES, | zone_jumbo16 = uma_zcreate(MBUF_JUMBO16_MEM_NAME, MJUM16BYTES, | ||||
mb_ctor_clust, mb_dtor_clust, | mb_ctor_clust, | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
trash_init, trash_fini, | trash_dtor, trash_init, trash_fini, | ||||
#else | #else | ||||
NULL, NULL, | NULL, NULL, NULL, | ||||
#endif | #endif | ||||
UMA_ALIGN_PTR, UMA_ZONE_REFCNT); | UMA_ALIGN_PTR, 0); | ||||
uma_zone_set_allocf(zone_jumbo16, mbuf_jumbo_alloc); | uma_zone_set_allocf(zone_jumbo16, mbuf_jumbo_alloc); | ||||
if (nmbjumbo16 > 0) | if (nmbjumbo16 > 0) | ||||
nmbjumbo16 = uma_zone_set_max(zone_jumbo16, nmbjumbo16); | nmbjumbo16 = uma_zone_set_max(zone_jumbo16, nmbjumbo16); | ||||
uma_zone_set_warning(zone_jumbo16, "kern.ipc.nmbjumbo16 limit reached"); | uma_zone_set_warning(zone_jumbo16, "kern.ipc.nmbjumbo16 limit reached"); | ||||
uma_zone_set_maxaction(zone_jumbo16, mb_reclaim); | uma_zone_set_maxaction(zone_jumbo16, mb_reclaim); | ||||
zone_ext_refcnt = uma_zcreate(MBUF_EXTREFCNT_MEM_NAME, sizeof(u_int), | |||||
NULL, NULL, | |||||
NULL, NULL, | |||||
UMA_ALIGN_PTR, UMA_ZONE_ZINIT); | |||||
/* | /* | ||||
* Hook event handler for low-memory situation, used to | * Hook event handler for low-memory situation, used to | ||||
* drain protocols and push data back to the caches (UMA | * drain protocols and push data back to the caches (UMA | ||||
* later pushes it back to VM). | * later pushes it back to VM). | ||||
*/ | */ | ||||
EVENTHANDLER_REGISTER(vm_lowmem, mb_reclaim, NULL, | EVENTHANDLER_REGISTER(vm_lowmem, mb_reclaim, NULL, | ||||
EVENTHANDLER_PRI_FIRST); | EVENTHANDLER_PRI_FIRST); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | mb_dtor_pack(void *mem, int size, void *arg) | ||||
/* Make sure we've got a clean cluster back. */ | /* Make sure we've got a clean cluster back. */ | ||||
KASSERT((m->m_flags & M_EXT) == M_EXT, ("%s: M_EXT not set", __func__)); | KASSERT((m->m_flags & M_EXT) == M_EXT, ("%s: M_EXT not set", __func__)); | ||||
KASSERT(m->m_ext.ext_buf != NULL, ("%s: ext_buf == NULL", __func__)); | KASSERT(m->m_ext.ext_buf != NULL, ("%s: ext_buf == NULL", __func__)); | ||||
KASSERT(m->m_ext.ext_free == NULL, ("%s: ext_free != NULL", __func__)); | KASSERT(m->m_ext.ext_free == NULL, ("%s: ext_free != NULL", __func__)); | ||||
KASSERT(m->m_ext.ext_arg1 == NULL, ("%s: ext_arg1 != NULL", __func__)); | KASSERT(m->m_ext.ext_arg1 == NULL, ("%s: ext_arg1 != NULL", __func__)); | ||||
KASSERT(m->m_ext.ext_arg2 == NULL, ("%s: ext_arg2 != NULL", __func__)); | KASSERT(m->m_ext.ext_arg2 == NULL, ("%s: ext_arg2 != NULL", __func__)); | ||||
KASSERT(m->m_ext.ext_size == MCLBYTES, ("%s: ext_size != MCLBYTES", __func__)); | KASSERT(m->m_ext.ext_size == MCLBYTES, ("%s: ext_size != MCLBYTES", __func__)); | ||||
KASSERT(m->m_ext.ext_type == EXT_PACKET, ("%s: ext_type != EXT_PACKET", __func__)); | KASSERT(m->m_ext.ext_type == EXT_PACKET, ("%s: ext_type != EXT_PACKET", __func__)); | ||||
KASSERT(*m->m_ext.ext_cnt == 1, ("%s: ext_cnt != 1", __func__)); | |||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
trash_dtor(m->m_ext.ext_buf, MCLBYTES, arg); | trash_dtor(m->m_ext.ext_buf, MCLBYTES, arg); | ||||
#endif | #endif | ||||
/* | /* | ||||
* If there are processes blocked on zone_clust, waiting for pages | * If there are processes blocked on zone_clust, waiting for pages | ||||
* to be freed up, * cause them to be woken up by draining the | * to be freed up, * cause them to be woken up by draining the | ||||
* packet zone. We are exposed to a race here * (in the check for | * packet zone. We are exposed to a race here * (in the check for | ||||
* the UMA_ZFLAG_FULL) where we might miss the flag set, but that | * the UMA_ZFLAG_FULL) where we might miss the flag set, but that | ||||
Show All 11 Lines | |||||
* are configuring cluster storage for. If 'arg' is | * are configuring cluster storage for. If 'arg' is | ||||
* empty we allocate just the cluster without setting | * empty we allocate just the cluster without setting | ||||
* the mbuf to it. See mbuf.h. | * the mbuf to it. See mbuf.h. | ||||
*/ | */ | ||||
static int | static int | ||||
mb_ctor_clust(void *mem, int size, void *arg, int how) | mb_ctor_clust(void *mem, int size, void *arg, int how) | ||||
{ | { | ||||
struct mbuf *m; | struct mbuf *m; | ||||
u_int *refcnt; | |||||
int type; | |||||
uma_zone_t zone; | |||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
trash_ctor(mem, size, arg, how); | trash_ctor(mem, size, arg, how); | ||||
#endif | #endif | ||||
switch (size) { | |||||
case MCLBYTES: | |||||
type = EXT_CLUSTER; | |||||
zone = zone_clust; | |||||
break; | |||||
#if MJUMPAGESIZE != MCLBYTES | |||||
case MJUMPAGESIZE: | |||||
type = EXT_JUMBOP; | |||||
zone = zone_jumbop; | |||||
break; | |||||
#endif | |||||
case MJUM9BYTES: | |||||
type = EXT_JUMBO9; | |||||
zone = zone_jumbo9; | |||||
break; | |||||
case MJUM16BYTES: | |||||
type = EXT_JUMBO16; | |||||
zone = zone_jumbo16; | |||||
break; | |||||
default: | |||||
panic("unknown cluster size"); | |||||
break; | |||||
} | |||||
m = (struct mbuf *)arg; | m = (struct mbuf *)arg; | ||||
refcnt = uma_find_refcnt(zone, mem); | |||||
*refcnt = 1; | |||||
if (m != NULL) { | if (m != NULL) { | ||||
m->m_ext.ext_buf = (caddr_t)mem; | m->m_ext.ext_buf = (caddr_t)mem; | ||||
m->m_data = m->m_ext.ext_buf; | m->m_data = m->m_ext.ext_buf; | ||||
m->m_flags |= M_EXT; | m->m_flags |= M_EXT; | ||||
m->m_ext.ext_free = NULL; | m->m_ext.ext_free = NULL; | ||||
m->m_ext.ext_arg1 = NULL; | m->m_ext.ext_arg1 = NULL; | ||||
m->m_ext.ext_arg2 = NULL; | m->m_ext.ext_arg2 = NULL; | ||||
m->m_ext.ext_size = size; | m->m_ext.ext_size = size; | ||||
m->m_ext.ext_type = type; | m->m_ext.ext_type = m_gettype(size); | ||||
m->m_ext.ext_flags = 0; | m->m_ext.ext_flags = EXT_FLAG_EMBREF; | ||||
m->m_ext.ext_cnt = refcnt; | m->m_ext.ext_count = 1; | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* The Mbuf Cluster zone destructor. | |||||
*/ | |||||
static void | |||||
mb_dtor_clust(void *mem, int size, void *arg) | |||||
{ | |||||
#ifdef INVARIANTS | |||||
uma_zone_t zone; | |||||
zone = m_getzone(size); | |||||
KASSERT(*(uma_find_refcnt(zone, mem)) <= 1, | |||||
("%s: refcnt incorrect %u", __func__, | |||||
*(uma_find_refcnt(zone, mem))) ); | |||||
trash_dtor(mem, size, arg); | |||||
#endif | |||||
} | |||||
/* | |||||
* The Packet secondary zone's init routine, executed on the | * The Packet secondary zone's init routine, executed on the | ||||
* object's transition from mbuf keg slab to zone cache. | * object's transition from mbuf keg slab to zone cache. | ||||
*/ | */ | ||||
static int | static int | ||||
mb_zinit_pack(void *mem, int size, int how) | mb_zinit_pack(void *mem, int size, int how) | ||||
{ | { | ||||
struct mbuf *m; | struct mbuf *m; | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Clean up after mbufs with M_EXT storage attached to them if the | * Clean up after mbufs with M_EXT storage attached to them if the | ||||
* reference count hits 1. | * reference count hits 1. | ||||
*/ | */ | ||||
void | void | ||||
mb_free_ext(struct mbuf *m) | mb_free_ext(struct mbuf *m) | ||||
{ | { | ||||
volatile u_int *refcnt; | |||||
struct mbuf *mref; | |||||
int freembuf; | int freembuf; | ||||
KASSERT(m->m_flags & M_EXT, ("%s: M_EXT not set on %p", __func__, m)); | KASSERT(m->m_flags & M_EXT, ("%s: M_EXT not set on %p", __func__, m)); | ||||
/* | /* See if this is the mbuf that holds the embedded refcount. */ | ||||
* Check if the header is embedded in the cluster. | if (m->m_ext.ext_flags & EXT_FLAG_EMBREF) { | ||||
*/ | refcnt = &m->m_ext.ext_count; | ||||
freembuf = (m->m_flags & M_NOFREE) ? 0 : 1; | mref = m; | ||||
} else { | |||||
switch (m->m_ext.ext_type) { | |||||
case EXT_SFBUF: | |||||
sf_ext_free(m->m_ext.ext_arg1, m->m_ext.ext_arg2); | |||||
break; | |||||
case EXT_SFBUF_NOCACHE: | |||||
sf_ext_free_nocache(m->m_ext.ext_arg1, m->m_ext.ext_arg2); | |||||
break; | |||||
default: | |||||
KASSERT(m->m_ext.ext_cnt != NULL, | KASSERT(m->m_ext.ext_cnt != NULL, | ||||
("%s: no refcounting pointer on %p", __func__, m)); | ("%s: no refcounting pointer on %p", __func__, m)); | ||||
/* | refcnt = m->m_ext.ext_cnt; | ||||
* Free attached storage if this mbuf is the only | mref = __containerof(refcnt, struct mbuf, m_ext.ext_count); | ||||
* reference to it. | |||||
*/ | |||||
if (*(m->m_ext.ext_cnt) != 1) { | |||||
if (atomic_fetchadd_int(m->m_ext.ext_cnt, -1) != 1) | |||||
break; | |||||
} | } | ||||
/* Check if the header is embedded in the cluster. */ | |||||
freembuf = (m->m_flags & M_NOFREE) ? 0 : 1; | |||||
/* Free attached storage if this mbuf is the only reference to it. */ | |||||
if (*refcnt == 1 || atomic_fetchadd_int(refcnt, -1) == 1) { | |||||
switch (m->m_ext.ext_type) { | switch (m->m_ext.ext_type) { | ||||
case EXT_PACKET: /* The packet zone is special. */ | case EXT_PACKET: | ||||
if (*(m->m_ext.ext_cnt) == 0) | /* The packet zone is special. */ | ||||
*(m->m_ext.ext_cnt) = 1; | if (*refcnt == 0) | ||||
uma_zfree(zone_pack, m); | *refcnt = 1; | ||||
return; /* Job done. */ | uma_zfree(zone_pack, mref); | ||||
goto freem; | |||||
case EXT_CLUSTER: | case EXT_CLUSTER: | ||||
uma_zfree(zone_clust, m->m_ext.ext_buf); | uma_zfree(zone_clust, m->m_ext.ext_buf); | ||||
break; | break; | ||||
case EXT_JUMBOP: | case EXT_JUMBOP: | ||||
uma_zfree(zone_jumbop, m->m_ext.ext_buf); | uma_zfree(zone_jumbop, m->m_ext.ext_buf); | ||||
break; | break; | ||||
case EXT_JUMBO9: | case EXT_JUMBO9: | ||||
uma_zfree(zone_jumbo9, m->m_ext.ext_buf); | uma_zfree(zone_jumbo9, m->m_ext.ext_buf); | ||||
break; | break; | ||||
case EXT_JUMBO16: | case EXT_JUMBO16: | ||||
uma_zfree(zone_jumbo16, m->m_ext.ext_buf); | uma_zfree(zone_jumbo16, m->m_ext.ext_buf); | ||||
break; | break; | ||||
case EXT_SFBUF: | |||||
sf_ext_free(m->m_ext.ext_arg1, m->m_ext.ext_arg2); | |||||
break; | |||||
case EXT_SFBUF_NOCACHE: | |||||
sf_ext_free_nocache(m->m_ext.ext_arg1, | |||||
m->m_ext.ext_arg2); | |||||
break; | |||||
case EXT_NET_DRV: | case EXT_NET_DRV: | ||||
case EXT_MOD_TYPE: | case EXT_MOD_TYPE: | ||||
case EXT_DISPOSABLE: | case EXT_DISPOSABLE: | ||||
*(m->m_ext.ext_cnt) = 0; | |||||
uma_zfree(zone_ext_refcnt, __DEVOLATILE(u_int *, | |||||
m->m_ext.ext_cnt)); | |||||
/* FALLTHROUGH */ | |||||
case EXT_EXTREF: | case EXT_EXTREF: | ||||
KASSERT(m->m_ext.ext_free != NULL, | KASSERT(m->m_ext.ext_free != NULL, | ||||
("%s: ext_free not set", __func__)); | ("%s: ext_free not set", __func__)); | ||||
(*(m->m_ext.ext_free))(m, m->m_ext.ext_arg1, | (*(m->m_ext.ext_free))(m, m->m_ext.ext_arg1, | ||||
m->m_ext.ext_arg2); | m->m_ext.ext_arg2); | ||||
break; | break; | ||||
default: | default: | ||||
KASSERT(m->m_ext.ext_type == 0, | KASSERT(m->m_ext.ext_type == 0, | ||||
("%s: unknown ext_type", __func__)); | ("%s: unknown ext_type", __func__)); | ||||
} | } | ||||
uma_zfree(zone_mbuf, mref); | |||||
} | } | ||||
if (freembuf) | freem: | ||||
/* | |||||
* Important is that we can't touch any of the mbuf fields | |||||
* after we have freed the external storage, since mbuf | |||||
* could have been embedded in it. | |||||
*/ | |||||
if (freembuf && m != mref) | |||||
uma_zfree(zone_mbuf, m); | uma_zfree(zone_mbuf, m); | ||||
} | } | ||||
/* | /* | ||||
* Official mbuf(9) allocation KPI for stack and drivers: | * Official mbuf(9) allocation KPI for stack and drivers: | ||||
* | * | ||||
* m_get() - a single mbuf without any attachments, sys/mbuf.h. | * m_get() - a single mbuf without any attachments, sys/mbuf.h. | ||||
* m_gethdr() - a single mbuf initialized as M_PKTHDR, sys/mbuf.h. | * m_gethdr() - a single mbuf initialized as M_PKTHDR, sys/mbuf.h. | ||||
▲ Show 20 Lines • Show All 173 Lines • ▼ Show 20 Lines | m_getm2(struct mbuf *m, int len, int how, short type, int flags) | ||||
} else | } else | ||||
m = nm; | m = nm; | ||||
return (m); | return (m); | ||||
} | } | ||||
/*- | /*- | ||||
* Configure a provided mbuf to refer to the provided external storage | * Configure a provided mbuf to refer to the provided external storage | ||||
* buffer and setup a reference count for said buffer. If the setting | * buffer and setup a reference count for said buffer. | ||||
* up of the reference count fails, the M_EXT bit will not be set. If | |||||
* successfull, the M_EXT bit is set in the mbuf's flags. | |||||
* | * | ||||
* Arguments: | * Arguments: | ||||
* mb The existing mbuf to which to attach the provided buffer. | * mb The existing mbuf to which to attach the provided buffer. | ||||
* buf The address of the provided external storage buffer. | * buf The address of the provided external storage buffer. | ||||
* size The size of the provided buffer. | * size The size of the provided buffer. | ||||
* freef A pointer to a routine that is responsible for freeing the | * freef A pointer to a routine that is responsible for freeing the | ||||
* provided external storage buffer. | * provided external storage buffer. | ||||
* args A pointer to an argument structure (of any type) to be passed | * args A pointer to an argument structure (of any type) to be passed | ||||
* to the provided freef routine (may be NULL). | * to the provided freef routine (may be NULL). | ||||
* flags Any other flags to be passed to the provided mbuf. | * flags Any other flags to be passed to the provided mbuf. | ||||
* type The type that the external storage buffer should be | * type The type that the external storage buffer should be | ||||
* labeled with. | * labeled with. | ||||
* | * | ||||
* Returns: | * Returns: | ||||
* Nothing. | * Nothing. | ||||
*/ | */ | ||||
int | void | ||||
m_extadd(struct mbuf *mb, caddr_t buf, u_int size, | m_extadd(struct mbuf *mb, caddr_t buf, u_int size, | ||||
void (*freef)(struct mbuf *, void *, void *), void *arg1, void *arg2, | void (*freef)(struct mbuf *, void *, void *), void *arg1, void *arg2, | ||||
int flags, int type, int wait) | int flags, int type) | ||||
{ | { | ||||
KASSERT(type != EXT_CLUSTER, ("%s: EXT_CLUSTER not allowed", __func__)); | KASSERT(type != EXT_CLUSTER, ("%s: EXT_CLUSTER not allowed", __func__)); | ||||
if (type != EXT_EXTREF) | |||||
mb->m_ext.ext_cnt = uma_zalloc(zone_ext_refcnt, wait); | |||||
if (mb->m_ext.ext_cnt == NULL) | |||||
return (ENOMEM); | |||||
*(mb->m_ext.ext_cnt) = 1; | |||||
mb->m_flags |= (M_EXT | flags); | mb->m_flags |= (M_EXT | flags); | ||||
mb->m_ext.ext_buf = buf; | mb->m_ext.ext_buf = buf; | ||||
mb->m_data = mb->m_ext.ext_buf; | mb->m_data = mb->m_ext.ext_buf; | ||||
mb->m_ext.ext_size = size; | mb->m_ext.ext_size = size; | ||||
mb->m_ext.ext_free = freef; | mb->m_ext.ext_free = freef; | ||||
mb->m_ext.ext_arg1 = arg1; | mb->m_ext.ext_arg1 = arg1; | ||||
mb->m_ext.ext_arg2 = arg2; | mb->m_ext.ext_arg2 = arg2; | ||||
mb->m_ext.ext_type = type; | mb->m_ext.ext_type = type; | ||||
mb->m_ext.ext_flags = 0; | |||||
return (0); | if (type != EXT_EXTREF) { | ||||
mb->m_ext.ext_count = 1; | |||||
mb->m_ext.ext_flags = EXT_FLAG_EMBREF; | |||||
} else | |||||
mb->m_ext.ext_flags = 0; | |||||
} | } | ||||
/* | /* | ||||
* Free an entire chain of mbufs and associated external buffers, if | * Free an entire chain of mbufs and associated external buffers, if | ||||
* applicable. | * applicable. | ||||
*/ | */ | ||||
void | void | ||||
m_freem(struct mbuf *mb) | m_freem(struct mbuf *mb) | ||||
{ | { | ||||
while (mb != NULL) | while (mb != NULL) | ||||
mb = m_free(mb); | mb = m_free(mb); | ||||
} | } |