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