kern_malloc.c revision 1.138.8.1 1 /* $NetBSD: kern_malloc.c,v 1.138.8.1 2017/08/18 14:52:43 snj 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.138.8.1 2017/08/18 14:52:43 snj 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 struct malloc_header {
94 /* Total size, include the header. */
95 size_t mh_size;
96 } __aligned(ALIGNBYTES+1);
97
98 /*
99 * Allocate a block of memory
100 */
101 #ifdef MALLOCLOG
102 void *
103 _kern_malloc(unsigned long size, struct malloc_type *ksp, int flags,
104 const char *file, long line)
105 #else
106 void *
107 kern_malloc(unsigned long size, struct malloc_type *ksp, int flags)
108 #endif /* MALLOCLOG */
109 {
110 const int kmflags = (flags & M_NOWAIT) ? KM_NOSLEEP : KM_SLEEP;
111 size_t allocsize, hdroffset;
112 struct malloc_header *mh;
113 void *p;
114
115 if (size >= PAGE_SIZE) {
116 if (size > (ULONG_MAX-PAGE_SIZE))
117 allocsize = ULONG_MAX; /* this will fail later */
118 else
119 allocsize = PAGE_SIZE + size; /* for page alignment */
120 hdroffset = PAGE_SIZE - sizeof(struct malloc_header);
121 } else {
122 allocsize = sizeof(struct malloc_header) + size;
123 hdroffset = 0;
124 }
125
126 p = kmem_intr_alloc(allocsize, kmflags);
127 if (p == NULL)
128 return NULL;
129
130 if ((flags & M_ZERO) != 0) {
131 memset(p, 0, allocsize);
132 }
133 mh = (void *)((char *)p + hdroffset);
134 mh->mh_size = allocsize - hdroffset;
135
136 return mh + 1;
137 }
138
139 /*
140 * Free a block of memory allocated by malloc.
141 */
142 #ifdef MALLOCLOG
143 void
144 _kern_free(void *addr, struct malloc_type *ksp, const char *file, long line)
145 #else
146 void
147 kern_free(void *addr, struct malloc_type *ksp)
148 #endif /* MALLOCLOG */
149 {
150 struct malloc_header *mh;
151
152 mh = addr;
153 mh--;
154
155 if (mh->mh_size >= PAGE_SIZE + sizeof(struct malloc_header))
156 kmem_intr_free((char *)addr - PAGE_SIZE,
157 mh->mh_size + PAGE_SIZE - sizeof(struct malloc_header));
158 else
159 kmem_intr_free(mh, mh->mh_size);
160 }
161
162 /*
163 * Change the size of a block of memory.
164 */
165 void *
166 kern_realloc(void *curaddr, unsigned long newsize, struct malloc_type *ksp,
167 int flags)
168 {
169 struct malloc_header *mh;
170 unsigned long cursize;
171 void *newaddr;
172
173 /*
174 * realloc() with a NULL pointer is the same as malloc().
175 */
176 if (curaddr == NULL)
177 return (malloc(newsize, ksp, flags));
178
179 /*
180 * realloc() with zero size is the same as free().
181 */
182 if (newsize == 0) {
183 free(curaddr, ksp);
184 return (NULL);
185 }
186
187 #ifdef LOCKDEBUG
188 if ((flags & M_NOWAIT) == 0) {
189 ASSERT_SLEEPABLE();
190 }
191 #endif
192
193 mh = curaddr;
194 mh--;
195
196 cursize = mh->mh_size - sizeof(struct malloc_header);
197
198 /*
199 * If we already actually have as much as they want, we're done.
200 */
201 if (newsize <= cursize)
202 return (curaddr);
203
204 /*
205 * Can't satisfy the allocation with the existing block.
206 * Allocate a new one and copy the data.
207 */
208 newaddr = malloc(newsize, ksp, flags);
209 if (__predict_false(newaddr == NULL)) {
210 /*
211 * malloc() failed, because flags included M_NOWAIT.
212 * Return NULL to indicate that failure. The old
213 * pointer is still valid.
214 */
215 return (NULL);
216 }
217 memcpy(newaddr, curaddr, cursize);
218
219 /*
220 * We were successful: free the old allocation and return
221 * the new one.
222 */
223 free(curaddr, ksp);
224 return (newaddr);
225 }
226
227 /*
228 * Add a malloc type to the system.
229 */
230 void
231 malloc_type_attach(struct malloc_type *type)
232 {
233
234 if (type->ks_magic != M_MAGIC)
235 panic("malloc_type_attach: bad magic");
236
237 #ifdef DIAGNOSTIC
238 {
239 struct malloc_type *ksp;
240 for (ksp = kmemstatistics; ksp != NULL; ksp = ksp->ks_next) {
241 if (ksp == type)
242 panic("%s: `%s' already on list", __func__,
243 type->ks_shortdesc);
244 }
245 }
246 #endif
247
248 #ifdef KMEMSTATS
249 #else
250 type->ks_limit = 0;
251 #endif
252
253 type->ks_next = kmemstatistics;
254 kmemstatistics = type;
255 }
256
257 /*
258 * Remove a malloc type from the system..
259 */
260 void
261 malloc_type_detach(struct malloc_type *type)
262 {
263 struct malloc_type *ksp;
264
265 #ifdef DIAGNOSTIC
266 if (type->ks_magic != M_MAGIC)
267 panic("malloc_type_detach: bad magic");
268 #endif
269
270 if (type == kmemstatistics)
271 kmemstatistics = type->ks_next;
272 else {
273 for (ksp = kmemstatistics; ksp->ks_next != NULL;
274 ksp = ksp->ks_next) {
275 if (ksp->ks_next == type) {
276 ksp->ks_next = type->ks_next;
277 break;
278 }
279 }
280 #ifdef DIAGNOSTIC
281 if (ksp->ks_next == NULL)
282 panic("malloc_type_detach: not on list");
283 #endif
284 }
285 type->ks_next = NULL;
286 }
287
288 /*
289 * Set the limit on a malloc type.
290 */
291 void
292 malloc_type_setlimit(struct malloc_type *type, u_long limit)
293 {
294 #ifdef KMEMSTATS
295 mutex_spin_enter(&malloc_lock);
296 type->ks_limit = limit;
297 mutex_spin_exit(&malloc_lock);
298 #endif
299 }
300
301 /*
302 * Initialize the kernel memory allocator
303 */
304 void
305 kmeminit(void)
306 {
307 __link_set_decl(malloc_types, struct malloc_type);
308 struct malloc_type * const *ksp;
309 #ifdef KMEMSTATS
310 long indx;
311 #endif
312
313 mutex_init(&malloc_lock, MUTEX_DEFAULT, IPL_VM);
314
315 #ifdef KMEMSTATS
316 for (indx = 0; indx < MINBUCKET + 16; indx++) {
317 if (1 << indx >= PAGE_SIZE)
318 kmembuckets[indx].kb_elmpercl = 1;
319 else
320 kmembuckets[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
321 kmembuckets[indx].kb_highwat =
322 5 * kmembuckets[indx].kb_elmpercl;
323 }
324 #endif
325
326 /* Attach all of the statically-linked malloc types. */
327 __link_set_foreach(ksp, malloc_types)
328 malloc_type_attach(*ksp);
329
330 #ifdef MALLOC_DEBUG
331 debug_malloc_init();
332 #endif
333 }
334
335 #ifdef DDB
336 #include <ddb/db_output.h>
337
338 /*
339 * Dump kmem statistics from ddb.
340 *
341 * usage: call dump_kmemstats
342 */
343 void dump_kmemstats(void);
344
345 void
346 dump_kmemstats(void)
347 {
348 #ifdef KMEMSTATS
349 struct malloc_type *ksp;
350
351 for (ksp = kmemstatistics; ksp != NULL; ksp = ksp->ks_next) {
352 if (ksp->ks_memuse == 0)
353 continue;
354 db_printf("%s%.*s %ld\n", ksp->ks_shortdesc,
355 (int)(20 - strlen(ksp->ks_shortdesc)),
356 " ",
357 ksp->ks_memuse);
358 }
359 #else
360 db_printf("Kmem stats are not being collected.\n");
361 #endif /* KMEMSTATS */
362 }
363 #endif /* DDB */
364
365
366 #if 0
367 /*
368 * Diagnostic messages about "Data modified on
369 * freelist" indicate a memory corruption, but
370 * they do not help tracking it down.
371 * This function can be called at various places
372 * to sanity check malloc's freelist and discover
373 * where does the corruption take place.
374 */
375 int
376 freelist_sanitycheck(void) {
377 int i,j;
378 struct kmembuckets *kbp;
379 struct freelist *freep;
380 int rv = 0;
381
382 for (i = MINBUCKET; i <= MINBUCKET + 15; i++) {
383 kbp = &kmembuckets[i];
384 freep = (struct freelist *)kbp->kb_next;
385 j = 0;
386 while(freep) {
387 vm_map_lock(kmem_map);
388 rv = uvm_map_checkprot(kmem_map, (vaddr_t)freep,
389 (vaddr_t)freep + sizeof(struct freelist),
390 VM_PROT_WRITE);
391 vm_map_unlock(kmem_map);
392
393 if ((rv == 0) || (*(int *)freep != WEIRD_ADDR)) {
394 printf("bucket %i, chunck %d at %p modified\n",
395 i, j, freep);
396 return 1;
397 }
398 freep = (struct freelist *)freep->next;
399 j++;
400 }
401 }
402
403 return 0;
404 }
405 #endif
406