]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_malloc.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / kern / kern_malloc.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
26 /*
27 * Copyright (c) 1987, 1991, 1993
28 * The Regents of the University of California. All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
58 * @(#)kern_malloc.c 8.4 (Berkeley) 5/20/95
59 */
60
61 #include <sys/param.h>
62 #include <sys/malloc.h>
63
64 #include <sys/socket.h>
65 #include <sys/socketvar.h>
66
67 #include <net/route.h>
68
69 #include <netinet/in.h>
70 #include <netinet/in_systm.h>
71 #include <netinet/ip.h>
72 #include <netinet/in_pcb.h>
73
74 #include <sys/event.h>
75 #include <sys/eventvar.h>
76
77 #include <sys/proc.h>
78 #include <sys/mount.h>
79 #include <sys/vnode.h>
80 #include <sys/namei.h>
81 #include <sys/file.h>
82 #include <sys/filedesc.h>
83 #include <sys/tty.h>
84 #include <sys/quota.h>
85
86 #include <ufs/ufs/inode.h>
87
88 #include <hfs/hfs_cnode.h>
89 #include <isofs/cd9660/cd9660_node.h>
90
91 #include <miscfs/volfs/volfs.h>
92 #include <miscfs/specfs/specdev.h>
93
94 #include <nfs/rpcv2.h>
95 #include <nfs/nfsproto.h>
96 #include <nfs/nfsnode.h>
97 #include <nfs/nfsmount.h>
98 #include <nfs/nqnfs.h>
99
100 #include <vfs/vfs_journal.h>
101
102 #include <mach/mach_types.h>
103
104 #include <kern/zalloc.h>
105 #include <kern/kalloc.h>
106
107 struct kmemstats kmemstats[M_LAST];
108 char *memname[] = INITKMEMNAMES;
109
110 struct kmzones {
111 size_t kz_elemsize;
112 void *kz_zalloczone;
113 #define KMZ_CREATEZONE ((void *)-2)
114 #define KMZ_LOOKUPZONE ((void *)-1)
115 #define KMZ_MALLOC ((void *)0)
116 #define KMZ_SHAREZONE ((void *)1)
117 } kmzones[M_LAST] = {
118 #define SOS(sname) sizeof (struct sname)
119 #define SOX(sname) -1
120 -1, 0, /* 0 M_FREE */
121 MSIZE, KMZ_CREATEZONE, /* 1 M_MBUF */
122 0, KMZ_MALLOC, /* 2 M_DEVBUF */
123 SOS(socket), KMZ_CREATEZONE, /* 3 M_SOCKET */
124 SOS(inpcb), KMZ_LOOKUPZONE, /* 4 M_PCB */
125 M_MBUF, KMZ_SHAREZONE, /* 5 M_RTABLE */
126 M_MBUF, KMZ_SHAREZONE, /* 6 M_HTABLE */
127 M_MBUF, KMZ_SHAREZONE, /* 7 M_FTABLE */
128 SOS(rusage), KMZ_CREATEZONE, /* 8 M_ZOMBIE */
129 0, KMZ_MALLOC, /* 9 M_IFADDR */
130 M_MBUF, KMZ_SHAREZONE, /* 10 M_SOOPTS */
131 0, KMZ_MALLOC, /* 11 M_SONAME */
132 MAXPATHLEN, KMZ_CREATEZONE, /* 12 M_NAMEI */
133 0, KMZ_MALLOC, /* 13 M_GPROF */
134 0, KMZ_MALLOC, /* 14 M_IOCTLOPS */
135 0, KMZ_MALLOC, /* 15 M_MAPMEM */
136 SOS(ucred), KMZ_CREATEZONE, /* 16 M_CRED */
137 SOS(pgrp), KMZ_CREATEZONE, /* 17 M_PGRP */
138 SOS(session), KMZ_CREATEZONE, /* 18 M_SESSION */
139 SOS(iovec), KMZ_LOOKUPZONE, /* 19 M_IOV */
140 SOS(mount), KMZ_CREATEZONE, /* 20 M_MOUNT */
141 0, KMZ_MALLOC, /* 21 M_FHANDLE */
142 SOS(nfsreq), KMZ_CREATEZONE, /* 22 M_NFSREQ */
143 SOS(nfsmount), KMZ_CREATEZONE, /* 23 M_NFSMNT */
144 SOS(nfsnode), KMZ_CREATEZONE, /* 24 M_NFSNODE */
145 SOS(vnode), KMZ_CREATEZONE, /* 25 M_VNODE */
146 SOS(namecache), KMZ_CREATEZONE, /* 26 M_CACHE */
147 SOX(dquot), KMZ_LOOKUPZONE, /* 27 M_DQUOT */
148 SOX(ufsmount), KMZ_LOOKUPZONE, /* 28 M_UFSMNT */
149 0, KMZ_MALLOC, /* 29 M_CGSUM */
150 0, KMZ_MALLOC, /* 30 M_VMMAP */
151 0, KMZ_MALLOC, /* 31 M_VMMAPENT */
152 0, KMZ_MALLOC, /* 32 M_VMOBJ */
153 0, KMZ_MALLOC, /* 33 M_VMOBJHASH */
154 0, KMZ_MALLOC, /* 34 M_VMPMAP */
155 0, KMZ_MALLOC, /* 35 M_VMPVENT */
156 0, KMZ_MALLOC, /* 36 M_VMPAGER */
157 0, KMZ_MALLOC, /* 37 M_VMPGDATA */
158 SOS(file), KMZ_CREATEZONE, /* 38 M_FILE */
159 SOS(filedesc), KMZ_CREATEZONE, /* 39 M_FILEDESC */
160 SOX(lockf), KMZ_CREATEZONE, /* 40 M_LOCKF */
161 SOS(proc), KMZ_CREATEZONE, /* 41 M_PROC */
162 SOS(pcred), KMZ_CREATEZONE, /* 42 M_SUBPROC */
163 0, KMZ_MALLOC, /* 43 M_SEGMENT */
164 M_FFSNODE, KMZ_SHAREZONE, /* 44 M_LFSNODE */
165 SOS(inode), KMZ_CREATEZONE, /* 45 M_FFSNODE */
166 M_FFSNODE, KMZ_SHAREZONE, /* 46 M_MFSNODE */
167 SOS(nqlease), KMZ_CREATEZONE, /* 47 M_NQLEASE */
168 SOS(nqm), KMZ_CREATEZONE, /* 48 M_NQMHOST */
169 0, KMZ_MALLOC, /* 49 M_NETADDR */
170 SOX(nfssvc_sock),
171 KMZ_CREATEZONE, /* 50 M_NFSSVC */
172 SOS(nfsuid), KMZ_CREATEZONE, /* 51 M_NFSUID */
173 SOX(nfsrvcache),
174 KMZ_CREATEZONE, /* 52 M_NFSD */
175 SOX(ip_moptions),
176 KMZ_LOOKUPZONE, /* 53 M_IPMOPTS */
177 SOX(in_multi), KMZ_LOOKUPZONE, /* 54 M_IPMADDR */
178 SOX(ether_multi),
179 KMZ_LOOKUPZONE, /* 55 M_IFMADDR */
180 SOX(mrt), KMZ_CREATEZONE, /* 56 M_MRTABLE */
181 SOX(iso_mnt), KMZ_LOOKUPZONE, /* 57 M_ISOFSMNT */
182 SOS(iso_node), KMZ_CREATEZONE, /* 58 M_ISOFSNODE */
183 SOS(nfsrv_descript),
184 KMZ_CREATEZONE, /* 59 M_NFSRVDESC */
185 SOS(nfsdmap), KMZ_CREATEZONE, /* 60 M_NFSDIROFF */
186 SOS(fhandle), KMZ_LOOKUPZONE, /* 61 M_NFSBIGFH */
187 0, KMZ_MALLOC, /* 62 M_MSDOSFSMNT */
188 0, KMZ_MALLOC, /* 63 M_MSDOSFSFAT */
189 0, KMZ_MALLOC, /* 64 M_MSDOSFSNODE */
190 SOS(tty), KMZ_CREATEZONE, /* 65 M_TTYS */
191 0, KMZ_MALLOC, /* 66 M_EXEC */
192 0, KMZ_MALLOC, /* 67 M_MISCFSMNT */
193 0, KMZ_MALLOC, /* 68 M_MISCFSNODE */
194 0, KMZ_MALLOC, /* 69 M_ADOSFSMNT */
195 0, KMZ_MALLOC, /* 70 M_ADOSFSNODE */
196 0, KMZ_MALLOC, /* 71 M_ANODE */
197 SOX(buf), KMZ_CREATEZONE, /* 72 M_BUFHDR */
198 (NDFILE * OFILESIZE),
199 KMZ_CREATEZONE, /* 73 M_OFILETABL */
200 MCLBYTES, KMZ_CREATEZONE, /* 74 M_MCLUST */
201 SOX(hfsmount), KMZ_LOOKUPZONE, /* 75 M_HFSMNT */
202 SOS(cnode), KMZ_CREATEZONE, /* 76 M_HFSNODE */
203 SOS(filefork), KMZ_CREATEZONE, /* 77 M_HFSFORK */
204 SOX(volfs_mntdata), KMZ_LOOKUPZONE, /* 78 M_VOLFSMNT */
205 SOS(volfs_vndata), KMZ_CREATEZONE, /* 79 M_VOLFSNODE */
206 0, KMZ_MALLOC, /* 80 M_TEMP */
207 0, KMZ_MALLOC, /* 81 M_SECA */
208 0, KMZ_MALLOC, /* 82 M_DEVFS */
209 0, KMZ_MALLOC, /* 83 M_IPFW */
210 0, KMZ_MALLOC, /* 84 M_UDFNODE */
211 0, KMZ_MALLOC, /* 85 M_UDFMOUNT */
212 0, KMZ_MALLOC, /* 86 M_IP6NDP */
213 0, KMZ_MALLOC, /* 87 M_IP6OPT */
214 0, KMZ_MALLOC, /* 88 M_IP6MISC */
215 0, KMZ_MALLOC, /* 89 M_TSEGQ */
216 0, KMZ_MALLOC, /* 90 M_IGMP */
217 SOS(journal), KMZ_CREATEZONE, /* 91 M_JNL_JNL */
218 SOS(transaction), KMZ_CREATEZONE, /* 92 M_JNL_TR */
219 SOS(specinfo), KMZ_CREATEZONE, /* 93 M_SPECINFO */
220 SOS(kqueue), KMZ_CREATEZONE, /* 94 M_KQUEUE */
221 #undef SOS
222 #undef SOX
223 };
224
225 extern zone_t kalloc_zone(vm_size_t); /* XXX */
226
227 /*
228 * Initialize the kernel memory allocator
229 */
230 void
231 kmeminit(void)
232 {
233 struct kmzones *kmz;
234
235 if ((sizeof(kmzones)/sizeof(kmzones[0])) != (sizeof(memname)/sizeof(memname[0]))) {
236 panic("kmeminit: kmzones has %d elements but memname has %d\n",
237 (sizeof(kmzones)/sizeof(kmzones[0])), (sizeof(memname)/sizeof(memname[0])));
238 }
239
240 kmz = kmzones;
241 while (kmz < &kmzones[M_LAST]) {
242 /* XXX */
243 if (kmz->kz_elemsize == -1)
244 ;
245 else
246 /* XXX */
247 if (kmz->kz_zalloczone == KMZ_CREATEZONE) {
248 kmz->kz_zalloczone = zinit(kmz->kz_elemsize,
249 1024 * 1024, PAGE_SIZE,
250 memname[kmz - kmzones]);
251 }
252 else if (kmz->kz_zalloczone == KMZ_LOOKUPZONE)
253 kmz->kz_zalloczone = kalloc_zone(kmz->kz_elemsize);
254
255 kmz++;
256 }
257
258 kmz = kmzones;
259 while (kmz < &kmzones[M_LAST]) {
260 /* XXX */
261 if (kmz->kz_elemsize == -1)
262 ;
263 else
264 /* XXX */
265 if (kmz->kz_zalloczone == KMZ_SHAREZONE) {
266 kmz->kz_zalloczone =
267 kmzones[kmz->kz_elemsize].kz_zalloczone;
268 kmz->kz_elemsize =
269 kmzones[kmz->kz_elemsize].kz_elemsize;
270 }
271
272 kmz++;
273 }
274 }
275
276 #define MDECL(reqlen) \
277 union { \
278 struct _mhead hdr; \
279 char _m[(reqlen) + sizeof (struct _mhead)]; \
280 }
281
282 struct _mhead {
283 size_t mlen;
284 char dat[0];
285 };
286
287 #define ZEROSIZETOKEN (void *)0xFADEDFAD
288
289 void *_MALLOC(
290 size_t size,
291 int type,
292 int flags)
293 {
294 MDECL(size) *mem;
295 size_t memsize = sizeof (*mem);
296
297 if (type >= M_LAST)
298 panic("_malloc TYPE");
299
300 /*
301 * On zero request we do not return zero as that
302 * could be mistaken for ENOMEM.
303 */
304 if (size == 0)
305 return (ZEROSIZETOKEN);
306
307 if (flags & M_NOWAIT) {
308 mem = (void *)kalloc_noblock(memsize);
309 } else {
310 mem = (void *)kalloc(memsize);
311 }
312 if (!mem)
313 return (0);
314
315 mem->hdr.mlen = memsize;
316
317 if (flags & M_ZERO)
318 bzero(mem->hdr.dat, size);
319
320 return (mem->hdr.dat);
321 }
322
323 void _FREE(
324 void *addr,
325 int type)
326 {
327 struct _mhead *hdr;
328
329 if (type >= M_LAST)
330 panic("_free TYPE");
331
332 if (addr == (void *)ZEROSIZETOKEN)
333 return;
334 if (!addr)
335 return; /* correct (convenient bsd kernel legacy) */
336
337 hdr = addr; hdr--;
338 kfree((vm_offset_t)hdr, hdr->mlen);
339 }
340
341 void *_MALLOC_ZONE(
342 size_t size,
343 int type,
344 int flags)
345 {
346 struct kmzones *kmz;
347 void *elem;
348
349 if (type >= M_LAST)
350 panic("_malloc_zone TYPE");
351
352 kmz = &kmzones[type];
353 if (kmz->kz_zalloczone == KMZ_MALLOC)
354 panic("_malloc_zone ZONE");
355
356 /* XXX */
357 if (kmz->kz_elemsize == -1)
358 panic("_malloc_zone XXX");
359 /* XXX */
360 if (size == kmz->kz_elemsize)
361 if (flags & M_NOWAIT) {
362 elem = (void *)zalloc_noblock(kmz->kz_zalloczone);
363 } else {
364 elem = (void *)zalloc(kmz->kz_zalloczone);
365 }
366 else
367 if (flags & M_NOWAIT) {
368 elem = (void *)kalloc_noblock(size);
369 } else {
370 elem = (void *)kalloc(size);
371 }
372
373 return (elem);
374 }
375
376 void _FREE_ZONE(
377 void *elem,
378 size_t size,
379 int type)
380 {
381 struct kmzones *kmz;
382
383 if (type >= M_LAST)
384 panic("FREE_SIZE");
385
386 kmz = &kmzones[type];
387 if (kmz->kz_zalloczone == KMZ_MALLOC)
388 panic("free_zone ZONE");
389
390 /* XXX */
391 if (kmz->kz_elemsize == -1)
392 panic("FREE_SIZE XXX");
393 /* XXX */
394 if (size == kmz->kz_elemsize)
395 zfree(kmz->kz_zalloczone, (vm_offset_t)elem);
396 else
397 kfree((vm_offset_t)elem, size);
398 }