kern_malloc.c revision 1.134 1 /* $NetBSD: kern_malloc.c,v 1.134 2012/01/27 19:48:40 para Exp $ */
2
3 /*
4 * Copyright (c) 1987, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following 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 University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 * @(#)kern_malloc.c 8.4 (Berkeley) 5/20/95
32 */
33
34 /*
35 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * @(#)kern_malloc.c 8.4 (Berkeley) 5/20/95
66 */
67
68 #include <sys/cdefs.h>
69 __KERNEL_RCSID(0, "$NetBSD: kern_malloc.c,v 1.134 2012/01/27 19:48:40 para Exp $");
70
71 #include <sys/param.h>
72 #include <sys/proc.h>
73 #include <sys/kernel.h>
74 #include <sys/malloc.h>
75 #include <sys/kmem.h>
76 #include <sys/systm.h>
77 #include <sys/debug.h>
78 #include <sys/mutex.h>
79 #include <sys/lockdebug.h>
80
81 #include <uvm/uvm_extern.h>
82
83 #include "opt_kmemstats.h"
84 #include "opt_malloclog.h"
85 #include "opt_malloc_debug.h"
86
87 struct kmembuckets kmembuckets[MINBUCKET + 16];
88 struct kmemusage *kmemusage;
89 struct malloc_type *kmemstatistics;
90
91 kmutex_t malloc_lock;
92
93 extern void *kmem_intr_alloc(size_t, km_flag_t);
94 extern void *kmem_intr_zalloc(size_t, km_flag_t);
95 extern void kmem_intr_free(void *, size_t);
96
97 struct malloc_header {
98 size_t mh_size;
99 };
100
101 /*
102 * Allocate a block of memory
103 */
104 #ifdef MALLOCLOG
105 void *
106 _kern_malloc(unsigned long size, struct malloc_type *ksp, int flags,
107 const char *file, long line)
108 #else
109 void *
110 kern_malloc(unsigned long size, struct malloc_type *ksp, int flags)
111 #endif /* MALLOCLOG */
112 {
113 struct malloc_header *mh;
114 int kmflags = ((flags & M_NOWAIT) != 0
115 ? KM_NOSLEEP : KM_SLEEP);
116 size_t allocsize = sizeof(struct malloc_header) + size;
117 void *p;
118
119 p = kmem_intr_alloc(allocsize, kmflags);
120 if (p == NULL)
121 return NULL;
122
123 if ((flags & M_ZERO) != 0) {
124 memset(p, 0, allocsize);
125 }
126 mh = (void *)p;
127 mh->mh_size = allocsize;
128
129 return mh + 1;
130 }
131
132 /*
133 * Free a block of memory allocated by malloc.
134 */
135 #ifdef MALLOCLOG
136 void
137 _kern_free(void *addr, struct malloc_type *ksp, const char *file, long line)
138 #else
139 void
140 kern_free(void *addr, struct malloc_type *ksp)
141 #endif /* MALLOCLOG */
142 {
143 struct malloc_header *mh;
144
145 mh = addr;
146 mh--;
147
148 kmem_intr_free(mh, mh->mh_size);
149 }
150
151 /*
152 * Change the size of a block of memory.
153 */
154 void *
155 kern_realloc(void *curaddr, unsigned long newsize, struct malloc_type *ksp,
156 int flags)
157 {
158 struct malloc_header *mh;
159 unsigned long cursize;
160 void *newaddr;
161
162 /*
163 * realloc() with a NULL pointer is the same as malloc().
164 */
165 if (curaddr == NULL)
166 return (malloc(newsize, ksp, flags));
167
168 /*
169 * realloc() with zero size is the same as free().
170 */
171 if (newsize == 0) {
172 free(curaddr, ksp);
173 return (NULL);
174 }
175
176 #ifdef LOCKDEBUG
177 if ((flags & M_NOWAIT) == 0) {
178 ASSERT_SLEEPABLE();
179 }
180 #endif
181
182 mh = curaddr;
183 mh--;
184
185 cursize = mh->mh_size;
186
187 /*
188 * If we already actually have as much as they want, we're done.
189 */
190 if (newsize <= cursize)
191 return (curaddr);
192
193 /*
194 * Can't satisfy the allocation with the existing block.
195 * Allocate a new one and copy the data.
196 */
197 newaddr = malloc(newsize, ksp, flags);
198 if (__predict_false(newaddr == NULL)) {
199 /*
200 * malloc() failed, because flags included M_NOWAIT.
201 * Return NULL to indicate that failure. The old
202 * pointer is still valid.
203 */
204 return (NULL);
205 }
206 memcpy(newaddr, curaddr, cursize);
207
208 /*
209 * We were successful: free the old allocation and return
210 * the new one.
211 */
212 free(curaddr, ksp);
213 return (newaddr);
214 }
215
216 /*
217 * Add a malloc type to the system.
218 */
219 void
220 malloc_type_attach(struct malloc_type *type)
221 {
222
223 if (type->ks_magic != M_MAGIC)
224 panic("malloc_type_attach: bad magic");
225
226 #ifdef DIAGNOSTIC
227 {
228 struct malloc_type *ksp;
229 for (ksp = kmemstatistics; ksp != NULL; ksp = ksp->ks_next) {
230 if (ksp == type)
231 panic("%s: `%s' already on list", __func__,
232 type->ks_shortdesc);
233 }
234 }
235 #endif
236
237 #ifdef KMEMSTATS
238 #else
239 type->ks_limit = 0;
240 #endif
241
242 type->ks_next = kmemstatistics;
243 kmemstatistics = type;
244 }
245
246 /*
247 * Remove a malloc type from the system..
248 */
249 void
250 malloc_type_detach(struct malloc_type *type)
251 {
252 struct malloc_type *ksp;
253
254 #ifdef DIAGNOSTIC
255 if (type->ks_magic != M_MAGIC)
256 panic("malloc_type_detach: bad magic");
257 #endif
258
259 if (type == kmemstatistics)
260 kmemstatistics = type->ks_next;
261 else {
262 for (ksp = kmemstatistics; ksp->ks_next != NULL;
263 ksp = ksp->ks_next) {
264 if (ksp->ks_next == type) {
265 ksp->ks_next = type->ks_next;
266 break;
267 }
268 }
269 #ifdef DIAGNOSTIC
270 if (ksp->ks_next == NULL)
271 panic("malloc_type_detach: not on list");
272 #endif
273 }
274 type->ks_next = NULL;
275 }
276
277 /*
278 * Set the limit on a malloc type.
279 */
280 void
281 malloc_type_setlimit(struct malloc_type *type, u_long limit)
282 {
283 #ifdef KMEMSTATS
284 mutex_spin_enter(&malloc_lock);
285 type->ks_limit = limit;
286 mutex_spin_exit(&malloc_lock);
287 #endif
288 }
289
290 /*
291 * Initialize the kernel memory allocator
292 */
293 void
294 kmeminit(void)
295 {
296 __link_set_decl(malloc_types, struct malloc_type);
297 struct malloc_type * const *ksp;
298 #ifdef KMEMSTATS
299 long indx;
300 #endif
301
302 mutex_init(&malloc_lock, MUTEX_DEFAULT, IPL_VM);
303
304 #ifdef KMEMSTATS
305 for (indx = 0; indx < MINBUCKET + 16; indx++) {
306 if (1 << indx >= PAGE_SIZE)
307 kmembuckets[indx].kb_elmpercl = 1;
308 else
309 kmembuckets[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
310 kmembuckets[indx].kb_highwat =
311 5 * kmembuckets[indx].kb_elmpercl;
312 }
313 #endif
314
315 /* Attach all of the statically-linked malloc types. */
316 __link_set_foreach(ksp, malloc_types)
317 malloc_type_attach(*ksp);
318
319 #ifdef MALLOC_DEBUG
320 debug_malloc_init();
321 #endif
322 }
323
324 #ifdef DDB
325 #include <ddb/db_output.h>
326
327 /*
328 * Dump kmem statistics from ddb.
329 *
330 * usage: call dump_kmemstats
331 */
332 void dump_kmemstats(void);
333
334 void
335 dump_kmemstats(void)
336 {
337 #ifdef KMEMSTATS
338 struct malloc_type *ksp;
339
340 for (ksp = kmemstatistics; ksp != NULL; ksp = ksp->ks_next) {
341 if (ksp->ks_memuse == 0)
342 continue;
343 db_printf("%s%.*s %ld\n", ksp->ks_shortdesc,
344 (int)(20 - strlen(ksp->ks_shortdesc)),
345 " ",
346 ksp->ks_memuse);
347 }
348 #else
349 db_printf("Kmem stats are not being collected.\n");
350 #endif /* KMEMSTATS */
351 }
352 #endif /* DDB */
353
354
355 #if 0
356 /*
357 * Diagnostic messages about "Data modified on
358 * freelist" indicate a memory corruption, but
359 * they do not help tracking it down.
360 * This function can be called at various places
361 * to sanity check malloc's freelist and discover
362 * where does the corruption take place.
363 */
364 int
365 freelist_sanitycheck(void) {
366 int i,j;
367 struct kmembuckets *kbp;
368 struct freelist *freep;
369 int rv = 0;
370
371 for (i = MINBUCKET; i <= MINBUCKET + 15; i++) {
372 kbp = &kmembuckets[i];
373 freep = (struct freelist *)kbp->kb_next;
374 j = 0;
375 while(freep) {
376 vm_map_lock(kmem_map);
377 rv = uvm_map_checkprot(kmem_map, (vaddr_t)freep,
378 (vaddr_t)freep + sizeof(struct freelist),
379 VM_PROT_WRITE);
380 vm_map_unlock(kmem_map);
381
382 if ((rv == 0) || (*(int *)freep != WEIRD_ADDR)) {
383 printf("bucket %i, chunck %d at %p modified\n",
384 i, j, freep);
385 return 1;
386 }
387 freep = (struct freelist *)freep->next;
388 j++;
389 }
390 }
391
392 return 0;
393 }
394 #endif
395