1/*-
2 * Copyright (c) 2004, 2005,
3 * Bosko Milekic <bmilekic@FreeBSD.org>. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/kern/kern_mbuf.c 150644 2005-09-27 20:28:43Z rwatson $");
30
31#include "opt_mac.h"
32#include "opt_param.h"
33
34#include <sys/param.h>
35#include <sys/mac.h>
36#include <sys/malloc.h>
37#include <sys/systm.h>
38#include <sys/mbuf.h>
39#include <sys/domain.h>
40#include <sys/eventhandler.h>
41#include <sys/kernel.h>
42#include <sys/protosw.h>
43#include <sys/smp.h>
44#include <sys/sysctl.h>
45
46#include <vm/vm.h>
47#include <vm/vm_page.h>
48#include <vm/uma.h>
49#include <vm/uma_int.h>
50#include <vm/uma_dbg.h>
51
52/*
53 * In FreeBSD, Mbufs and Mbuf Clusters are allocated from UMA
54 * Zones.
55 *
56 * Mbuf Clusters (2K, contiguous) are allocated from the Cluster
57 * Zone. The Zone can be capped at kern.ipc.nmbclusters, if the
58 * administrator so desires.
59 *
60 * Mbufs are allocated from a UMA Master Zone called the Mbuf
61 * Zone.
62 *
63 * Additionally, FreeBSD provides a Packet Zone, which it
64 * configures as a Secondary Zone to the Mbuf Master Zone,
65 * thus sharing backend Slab kegs with the Mbuf Master Zone.
66 *
67 * Thus common-case allocations and locking are simplified:
68 *
69 * m_clget() m_getcl()
70 * | |
71 * | .------------>[(Packet Cache)] m_get(), m_gethdr()
72 * | | [ Packet ] |
73 * [(Cluster Cache)] [ Secondary ] [ (Mbuf Cache) ]
74 * [ Cluster Zone ] [ Zone ] [ Mbuf Master Zone ]
75 * | \________ |
76 * [ Cluster Keg ] \ /
77 * | [ Mbuf Keg ]
78 * [ Cluster Slabs ] |
79 * | [ Mbuf Slabs ]
80 * \____________(VM)_________________/
81 */
82
83int nmbclusters;
84struct mbstat mbstat;
85
86static void
87tunable_mbinit(void *dummy)
88{
89
90 /* This has to be done before VM init. */
91 nmbclusters = 1024 + maxusers * 64;
92 TUNABLE_INT_FETCH("kern.ipc.nmbclusters", &nmbclusters);
93}
94SYSINIT(tunable_mbinit, SI_SUB_TUNABLES, SI_ORDER_ANY, tunable_mbinit, NULL);
95
96SYSCTL_DECL(_kern_ipc);
97SYSCTL_INT(_kern_ipc, OID_AUTO, nmbclusters, CTLFLAG_RW, &nmbclusters, 0,
98 "Maximum number of mbuf clusters allowed");
99SYSCTL_STRUCT(_kern_ipc, OID_AUTO, mbstat, CTLFLAG_RD, &mbstat, mbstat,
100 "Mbuf general information and statistics");
101
102/*
103 * Zones from which we allocate.
104 */
105uma_zone_t zone_mbuf;
106uma_zone_t zone_clust;
107uma_zone_t zone_pack;
108
109/*
110 * Local prototypes.
111 */
112static int mb_ctor_mbuf(void *, int, void *, int);
113static int mb_ctor_clust(void *, int, void *, int);
114static int mb_ctor_pack(void *, int, void *, int);
115static void mb_dtor_mbuf(void *, int, void *);
116static void mb_dtor_clust(void *, int, void *); /* XXX */
117static void mb_dtor_pack(void *, int, void *); /* XXX */
118static int mb_init_pack(void *, int, int);
119static void mb_fini_pack(void *, int);
120
121static void mb_reclaim(void *);
122static void mbuf_init(void *);
123
124/* Ensure that MSIZE doesn't break dtom() - it must be a power of 2 */
125CTASSERT((((MSIZE - 1) ^ MSIZE) + 1) >> 1 == MSIZE);
126
127/*
128 * Initialize FreeBSD Network buffer allocation.
129 */
130SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbuf_init, NULL)
131static void
132mbuf_init(void *dummy)
133{
134
135 /*
136 * Configure UMA zones for Mbufs, Clusters, and Packets.
137 */
138 zone_mbuf = uma_zcreate(MBUF_MEM_NAME, MSIZE, mb_ctor_mbuf,
139 mb_dtor_mbuf,
140#ifdef INVARIANTS
141 trash_init, trash_fini, MSIZE - 1, UMA_ZONE_MAXBUCKET);
142#else
143 NULL, NULL, MSIZE - 1, UMA_ZONE_MAXBUCKET);
144#endif
145 zone_clust = uma_zcreate(MBUF_CLUSTER_MEM_NAME, MCLBYTES,
146 mb_ctor_clust,
147#ifdef INVARIANTS
148 mb_dtor_clust, trash_init, trash_fini, UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
149#else
150 mb_dtor_clust, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
151#endif
152 if (nmbclusters > 0)
153 uma_zone_set_max(zone_clust, nmbclusters);
154 zone_pack = uma_zsecond_create(MBUF_PACKET_MEM_NAME, mb_ctor_pack,
155 mb_dtor_pack, mb_init_pack, mb_fini_pack, zone_mbuf);
156
157 /* uma_prealloc() goes here */
158
159 /*
160 * Hook event handler for low-memory situation, used to
161 * drain protocols and push data back to the caches (UMA
162 * later pushes it back to VM).
163 */
164 EVENTHANDLER_REGISTER(vm_lowmem, mb_reclaim, NULL,
165 EVENTHANDLER_PRI_FIRST);
166
167 /*
168 * [Re]set counters and local statistics knobs.
169 * XXX Some of these should go and be replaced, but UMA stat
170 * gathering needs to be revised.
171 */
172 mbstat.m_mbufs = 0;
173 mbstat.m_mclusts = 0;
174 mbstat.m_drain = 0;
175 mbstat.m_msize = MSIZE;
176 mbstat.m_mclbytes = MCLBYTES;
177 mbstat.m_minclsize = MINCLSIZE;
178 mbstat.m_mlen = MLEN;
179 mbstat.m_mhlen = MHLEN;
180 mbstat.m_numtypes = MT_NTYPES;
181
182 mbstat.m_mcfail = mbstat.m_mpfail = 0;
183 mbstat.sf_iocnt = 0;
184 mbstat.sf_allocwait = mbstat.sf_allocfail = 0;
185}
186
187/*
188 * Constructor for Mbuf master zone.
189 *
190 * The 'arg' pointer points to a mb_args structure which
191 * contains call-specific information required to support the
192 * mbuf allocation API.
193 */
194static int
195mb_ctor_mbuf(void *mem, int size, void *arg, int how)
196{
197 struct mbuf *m;
198 struct mb_args *args;
199#ifdef MAC
200 int error;
201#endif
202 int flags;
203 short type;
204
205#ifdef INVARIANTS
206 trash_ctor(mem, size, arg, how);
207#endif
208 m = (struct mbuf *)mem;
209 args = (struct mb_args *)arg;
210 flags = args->flags;
211 type = args->type;
212
213 m->m_type = type;
214 m->m_next = NULL;
215 m->m_nextpkt = NULL;
216 m->m_flags = flags;
217 if (flags & M_PKTHDR) {
218 m->m_data = m->m_pktdat;
219 m->m_pkthdr.rcvif = NULL;
220 m->m_pkthdr.csum_flags = 0;
221 SLIST_INIT(&m->m_pkthdr.tags);
222#ifdef MAC
223 /* If the label init fails, fail the alloc */
224 error = mac_init_mbuf(m, how);
225 if (error)
226 return (error);
227#endif
228 } else
229 m->m_data = m->m_dat;
230 return (0);
231}
232
233/*
234 * The Mbuf master zone and Packet secondary zone destructor.
235 */
236static void
237mb_dtor_mbuf(void *mem, int size, void *arg)
238{
239 struct mbuf *m;
240
241 m = (struct mbuf *)mem;
242 if ((m->m_flags & M_PKTHDR) != 0)
243 m_tag_delete_chain(m, NULL);
244#ifdef INVARIANTS
245 trash_dtor(mem, size, arg);
246#endif
247}
248
249/* XXX Only because of stats */
250static void
251mb_dtor_pack(void *mem, int size, void *arg)
252{
253 struct mbuf *m;
254
255 m = (struct mbuf *)mem;
256 if ((m->m_flags & M_PKTHDR) != 0)
257 m_tag_delete_chain(m, NULL);
258#ifdef INVARIANTS
259 trash_dtor(m->m_ext.ext_buf, MCLBYTES, arg);
260#endif
261}
262
263/*
264 * The Cluster zone constructor.
265 *
266 * Here the 'arg' pointer points to the Mbuf which we
267 * are configuring cluster storage for.
268 */
269static int
270mb_ctor_clust(void *mem, int size, void *arg, int how)
271{
272 struct mbuf *m;
273
274#ifdef INVARIANTS
275 trash_ctor(mem, size, arg, how);
276#endif
277 m = (struct mbuf *)arg;
278 m->m_ext.ext_buf = (caddr_t)mem;
279 m->m_data = m->m_ext.ext_buf;
280 m->m_flags |= M_EXT;
281 m->m_ext.ext_free = NULL;
282 m->m_ext.ext_args = NULL;
283 m->m_ext.ext_size = MCLBYTES;
284 m->m_ext.ext_type = EXT_CLUSTER;
285 m->m_ext.ref_cnt = NULL; /* Lazy counter assign. */
286 return (0);
287}
288
289/* XXX */
290static void
291mb_dtor_clust(void *mem, int size, void *arg)
292{
293#ifdef INVARIANTS
294 trash_dtor(mem, size, arg);
295#endif
296}
297
298/*
299 * The Packet secondary zone's init routine, executed on the
300 * object's transition from keg slab to zone cache.
301 */
302static int
303mb_init_pack(void *mem, int size, int how)
304{
305 struct mbuf *m;
306
307 m = (struct mbuf *)mem;
308 m->m_ext.ext_buf = NULL;
309 uma_zalloc_arg(zone_clust, m, how);
310 if (m->m_ext.ext_buf == NULL)
311 return (ENOMEM);
312#ifdef INVARIANTS
313 trash_init(m->m_ext.ext_buf, MCLBYTES, how);
314#endif
315 return (0);
316}
317
318/*
319 * The Packet secondary zone's fini routine, executed on the
320 * object's transition from zone cache to keg slab.
321 */
322static void
323mb_fini_pack(void *mem, int size)
324{
325 struct mbuf *m;
326
327 m = (struct mbuf *)mem;
328#ifdef INVARIANTS
329 trash_fini(m->m_ext.ext_buf, MCLBYTES);
330#endif
331 uma_zfree_arg(zone_clust, m->m_ext.ext_buf, NULL);
332 m->m_ext.ext_buf = NULL;
333#ifdef INVARIANTS
334 trash_dtor(mem, size, NULL);
335#endif
336}
337
338/*
339 * The "packet" keg constructor.
340 */
341static int
342mb_ctor_pack(void *mem, int size, void *arg, int how)
343{
344 struct mbuf *m;
345 struct mb_args *args;
346#ifdef MAC
347 int error;
348#endif
349 int flags;
350 short type;
351
352 m = (struct mbuf *)mem;
353 args = (struct mb_args *)arg;
354 flags = args->flags;
355 type = args->type;
356
357#ifdef INVARIANTS
358 trash_ctor(m->m_ext.ext_buf, MCLBYTES, arg, how);
359#endif
360 m->m_type = type;
361 m->m_next = NULL;
362 m->m_nextpkt = NULL;
363 m->m_data = m->m_ext.ext_buf;
364 m->m_flags = flags|M_EXT;
365 m->m_ext.ext_free = NULL;
366 m->m_ext.ext_args = NULL;
367 m->m_ext.ext_size = MCLBYTES;
368 m->m_ext.ext_type = EXT_PACKET;
369 m->m_ext.ref_cnt = NULL; /* Lazy counter assign. */
370
371 if (flags & M_PKTHDR) {
372 m->m_pkthdr.rcvif = NULL;
373 m->m_pkthdr.csum_flags = 0;
374 SLIST_INIT(&m->m_pkthdr.tags);
375#ifdef MAC
376 /* If the label init fails, fail the alloc */
377 error = mac_init_mbuf(m, how);
378 if (error)
379 return (error);
380#endif
381 }
382 return (0);
383}
384
385/*
386 * This is the protocol drain routine.
387 *
388 * No locks should be held when this is called. The drain routines have to
389 * presently acquire some locks which raises the possibility of lock order
390 * reversal.
391 */
392static void
393mb_reclaim(void *junk)
394{
395 struct domain *dp;
396 struct protosw *pr;
397
398 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK | WARN_PANIC, NULL,
399 "mb_reclaim()");
400
401 for (dp = domains; dp != NULL; dp = dp->dom_next)
402 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
403 if (pr->pr_drain != NULL)
404 (*pr->pr_drain)();
405}
2 * Copyright (c) 2004, 2005,
3 * Bosko Milekic <bmilekic@FreeBSD.org>. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice unmodified, this list of conditions and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/kern/kern_mbuf.c 150644 2005-09-27 20:28:43Z rwatson $");
30
31#include "opt_mac.h"
32#include "opt_param.h"
33
34#include <sys/param.h>
35#include <sys/mac.h>
36#include <sys/malloc.h>
37#include <sys/systm.h>
38#include <sys/mbuf.h>
39#include <sys/domain.h>
40#include <sys/eventhandler.h>
41#include <sys/kernel.h>
42#include <sys/protosw.h>
43#include <sys/smp.h>
44#include <sys/sysctl.h>
45
46#include <vm/vm.h>
47#include <vm/vm_page.h>
48#include <vm/uma.h>
49#include <vm/uma_int.h>
50#include <vm/uma_dbg.h>
51
52/*
53 * In FreeBSD, Mbufs and Mbuf Clusters are allocated from UMA
54 * Zones.
55 *
56 * Mbuf Clusters (2K, contiguous) are allocated from the Cluster
57 * Zone. The Zone can be capped at kern.ipc.nmbclusters, if the
58 * administrator so desires.
59 *
60 * Mbufs are allocated from a UMA Master Zone called the Mbuf
61 * Zone.
62 *
63 * Additionally, FreeBSD provides a Packet Zone, which it
64 * configures as a Secondary Zone to the Mbuf Master Zone,
65 * thus sharing backend Slab kegs with the Mbuf Master Zone.
66 *
67 * Thus common-case allocations and locking are simplified:
68 *
69 * m_clget() m_getcl()
70 * | |
71 * | .------------>[(Packet Cache)] m_get(), m_gethdr()
72 * | | [ Packet ] |
73 * [(Cluster Cache)] [ Secondary ] [ (Mbuf Cache) ]
74 * [ Cluster Zone ] [ Zone ] [ Mbuf Master Zone ]
75 * | \________ |
76 * [ Cluster Keg ] \ /
77 * | [ Mbuf Keg ]
78 * [ Cluster Slabs ] |
79 * | [ Mbuf Slabs ]
80 * \____________(VM)_________________/
81 */
82
83int nmbclusters;
84struct mbstat mbstat;
85
86static void
87tunable_mbinit(void *dummy)
88{
89
90 /* This has to be done before VM init. */
91 nmbclusters = 1024 + maxusers * 64;
92 TUNABLE_INT_FETCH("kern.ipc.nmbclusters", &nmbclusters);
93}
94SYSINIT(tunable_mbinit, SI_SUB_TUNABLES, SI_ORDER_ANY, tunable_mbinit, NULL);
95
96SYSCTL_DECL(_kern_ipc);
97SYSCTL_INT(_kern_ipc, OID_AUTO, nmbclusters, CTLFLAG_RW, &nmbclusters, 0,
98 "Maximum number of mbuf clusters allowed");
99SYSCTL_STRUCT(_kern_ipc, OID_AUTO, mbstat, CTLFLAG_RD, &mbstat, mbstat,
100 "Mbuf general information and statistics");
101
102/*
103 * Zones from which we allocate.
104 */
105uma_zone_t zone_mbuf;
106uma_zone_t zone_clust;
107uma_zone_t zone_pack;
108
109/*
110 * Local prototypes.
111 */
112static int mb_ctor_mbuf(void *, int, void *, int);
113static int mb_ctor_clust(void *, int, void *, int);
114static int mb_ctor_pack(void *, int, void *, int);
115static void mb_dtor_mbuf(void *, int, void *);
116static void mb_dtor_clust(void *, int, void *); /* XXX */
117static void mb_dtor_pack(void *, int, void *); /* XXX */
118static int mb_init_pack(void *, int, int);
119static void mb_fini_pack(void *, int);
120
121static void mb_reclaim(void *);
122static void mbuf_init(void *);
123
124/* Ensure that MSIZE doesn't break dtom() - it must be a power of 2 */
125CTASSERT((((MSIZE - 1) ^ MSIZE) + 1) >> 1 == MSIZE);
126
127/*
128 * Initialize FreeBSD Network buffer allocation.
129 */
130SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbuf_init, NULL)
131static void
132mbuf_init(void *dummy)
133{
134
135 /*
136 * Configure UMA zones for Mbufs, Clusters, and Packets.
137 */
138 zone_mbuf = uma_zcreate(MBUF_MEM_NAME, MSIZE, mb_ctor_mbuf,
139 mb_dtor_mbuf,
140#ifdef INVARIANTS
141 trash_init, trash_fini, MSIZE - 1, UMA_ZONE_MAXBUCKET);
142#else
143 NULL, NULL, MSIZE - 1, UMA_ZONE_MAXBUCKET);
144#endif
145 zone_clust = uma_zcreate(MBUF_CLUSTER_MEM_NAME, MCLBYTES,
146 mb_ctor_clust,
147#ifdef INVARIANTS
148 mb_dtor_clust, trash_init, trash_fini, UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
149#else
150 mb_dtor_clust, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
151#endif
152 if (nmbclusters > 0)
153 uma_zone_set_max(zone_clust, nmbclusters);
154 zone_pack = uma_zsecond_create(MBUF_PACKET_MEM_NAME, mb_ctor_pack,
155 mb_dtor_pack, mb_init_pack, mb_fini_pack, zone_mbuf);
156
157 /* uma_prealloc() goes here */
158
159 /*
160 * Hook event handler for low-memory situation, used to
161 * drain protocols and push data back to the caches (UMA
162 * later pushes it back to VM).
163 */
164 EVENTHANDLER_REGISTER(vm_lowmem, mb_reclaim, NULL,
165 EVENTHANDLER_PRI_FIRST);
166
167 /*
168 * [Re]set counters and local statistics knobs.
169 * XXX Some of these should go and be replaced, but UMA stat
170 * gathering needs to be revised.
171 */
172 mbstat.m_mbufs = 0;
173 mbstat.m_mclusts = 0;
174 mbstat.m_drain = 0;
175 mbstat.m_msize = MSIZE;
176 mbstat.m_mclbytes = MCLBYTES;
177 mbstat.m_minclsize = MINCLSIZE;
178 mbstat.m_mlen = MLEN;
179 mbstat.m_mhlen = MHLEN;
180 mbstat.m_numtypes = MT_NTYPES;
181
182 mbstat.m_mcfail = mbstat.m_mpfail = 0;
183 mbstat.sf_iocnt = 0;
184 mbstat.sf_allocwait = mbstat.sf_allocfail = 0;
185}
186
187/*
188 * Constructor for Mbuf master zone.
189 *
190 * The 'arg' pointer points to a mb_args structure which
191 * contains call-specific information required to support the
192 * mbuf allocation API.
193 */
194static int
195mb_ctor_mbuf(void *mem, int size, void *arg, int how)
196{
197 struct mbuf *m;
198 struct mb_args *args;
199#ifdef MAC
200 int error;
201#endif
202 int flags;
203 short type;
204
205#ifdef INVARIANTS
206 trash_ctor(mem, size, arg, how);
207#endif
208 m = (struct mbuf *)mem;
209 args = (struct mb_args *)arg;
210 flags = args->flags;
211 type = args->type;
212
213 m->m_type = type;
214 m->m_next = NULL;
215 m->m_nextpkt = NULL;
216 m->m_flags = flags;
217 if (flags & M_PKTHDR) {
218 m->m_data = m->m_pktdat;
219 m->m_pkthdr.rcvif = NULL;
220 m->m_pkthdr.csum_flags = 0;
221 SLIST_INIT(&m->m_pkthdr.tags);
222#ifdef MAC
223 /* If the label init fails, fail the alloc */
224 error = mac_init_mbuf(m, how);
225 if (error)
226 return (error);
227#endif
228 } else
229 m->m_data = m->m_dat;
230 return (0);
231}
232
233/*
234 * The Mbuf master zone and Packet secondary zone destructor.
235 */
236static void
237mb_dtor_mbuf(void *mem, int size, void *arg)
238{
239 struct mbuf *m;
240
241 m = (struct mbuf *)mem;
242 if ((m->m_flags & M_PKTHDR) != 0)
243 m_tag_delete_chain(m, NULL);
244#ifdef INVARIANTS
245 trash_dtor(mem, size, arg);
246#endif
247}
248
249/* XXX Only because of stats */
250static void
251mb_dtor_pack(void *mem, int size, void *arg)
252{
253 struct mbuf *m;
254
255 m = (struct mbuf *)mem;
256 if ((m->m_flags & M_PKTHDR) != 0)
257 m_tag_delete_chain(m, NULL);
258#ifdef INVARIANTS
259 trash_dtor(m->m_ext.ext_buf, MCLBYTES, arg);
260#endif
261}
262
263/*
264 * The Cluster zone constructor.
265 *
266 * Here the 'arg' pointer points to the Mbuf which we
267 * are configuring cluster storage for.
268 */
269static int
270mb_ctor_clust(void *mem, int size, void *arg, int how)
271{
272 struct mbuf *m;
273
274#ifdef INVARIANTS
275 trash_ctor(mem, size, arg, how);
276#endif
277 m = (struct mbuf *)arg;
278 m->m_ext.ext_buf = (caddr_t)mem;
279 m->m_data = m->m_ext.ext_buf;
280 m->m_flags |= M_EXT;
281 m->m_ext.ext_free = NULL;
282 m->m_ext.ext_args = NULL;
283 m->m_ext.ext_size = MCLBYTES;
284 m->m_ext.ext_type = EXT_CLUSTER;
285 m->m_ext.ref_cnt = NULL; /* Lazy counter assign. */
286 return (0);
287}
288
289/* XXX */
290static void
291mb_dtor_clust(void *mem, int size, void *arg)
292{
293#ifdef INVARIANTS
294 trash_dtor(mem, size, arg);
295#endif
296}
297
298/*
299 * The Packet secondary zone's init routine, executed on the
300 * object's transition from keg slab to zone cache.
301 */
302static int
303mb_init_pack(void *mem, int size, int how)
304{
305 struct mbuf *m;
306
307 m = (struct mbuf *)mem;
308 m->m_ext.ext_buf = NULL;
309 uma_zalloc_arg(zone_clust, m, how);
310 if (m->m_ext.ext_buf == NULL)
311 return (ENOMEM);
312#ifdef INVARIANTS
313 trash_init(m->m_ext.ext_buf, MCLBYTES, how);
314#endif
315 return (0);
316}
317
318/*
319 * The Packet secondary zone's fini routine, executed on the
320 * object's transition from zone cache to keg slab.
321 */
322static void
323mb_fini_pack(void *mem, int size)
324{
325 struct mbuf *m;
326
327 m = (struct mbuf *)mem;
328#ifdef INVARIANTS
329 trash_fini(m->m_ext.ext_buf, MCLBYTES);
330#endif
331 uma_zfree_arg(zone_clust, m->m_ext.ext_buf, NULL);
332 m->m_ext.ext_buf = NULL;
333#ifdef INVARIANTS
334 trash_dtor(mem, size, NULL);
335#endif
336}
337
338/*
339 * The "packet" keg constructor.
340 */
341static int
342mb_ctor_pack(void *mem, int size, void *arg, int how)
343{
344 struct mbuf *m;
345 struct mb_args *args;
346#ifdef MAC
347 int error;
348#endif
349 int flags;
350 short type;
351
352 m = (struct mbuf *)mem;
353 args = (struct mb_args *)arg;
354 flags = args->flags;
355 type = args->type;
356
357#ifdef INVARIANTS
358 trash_ctor(m->m_ext.ext_buf, MCLBYTES, arg, how);
359#endif
360 m->m_type = type;
361 m->m_next = NULL;
362 m->m_nextpkt = NULL;
363 m->m_data = m->m_ext.ext_buf;
364 m->m_flags = flags|M_EXT;
365 m->m_ext.ext_free = NULL;
366 m->m_ext.ext_args = NULL;
367 m->m_ext.ext_size = MCLBYTES;
368 m->m_ext.ext_type = EXT_PACKET;
369 m->m_ext.ref_cnt = NULL; /* Lazy counter assign. */
370
371 if (flags & M_PKTHDR) {
372 m->m_pkthdr.rcvif = NULL;
373 m->m_pkthdr.csum_flags = 0;
374 SLIST_INIT(&m->m_pkthdr.tags);
375#ifdef MAC
376 /* If the label init fails, fail the alloc */
377 error = mac_init_mbuf(m, how);
378 if (error)
379 return (error);
380#endif
381 }
382 return (0);
383}
384
385/*
386 * This is the protocol drain routine.
387 *
388 * No locks should be held when this is called. The drain routines have to
389 * presently acquire some locks which raises the possibility of lock order
390 * reversal.
391 */
392static void
393mb_reclaim(void *junk)
394{
395 struct domain *dp;
396 struct protosw *pr;
397
398 WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK | WARN_PANIC, NULL,
399 "mb_reclaim()");
400
401 for (dp = domains; dp != NULL; dp = dp->dom_next)
402 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
403 if (pr->pr_drain != NULL)
404 (*pr->pr_drain)();
405}