kern_malloc.c revision 1.70.4.1 1 1.70.4.1 thorpej /* $NetBSD: kern_malloc.c,v 1.70.4.1 2002/03/22 18:59:31 thorpej Exp $ */
2 1.9 cgd
3 1.1 cgd /*
4 1.37 christos * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
5 1.8 cgd * Copyright (c) 1987, 1991, 1993
6 1.8 cgd * The Regents of the University of California. All rights reserved.
7 1.1 cgd *
8 1.1 cgd * Redistribution and use in source and binary forms, with or without
9 1.1 cgd * modification, are permitted provided that the following conditions
10 1.1 cgd * are met:
11 1.1 cgd * 1. Redistributions of source code must retain the above copyright
12 1.1 cgd * notice, this list of conditions and the following disclaimer.
13 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 cgd * notice, this list of conditions and the following disclaimer in the
15 1.1 cgd * documentation and/or other materials provided with the distribution.
16 1.1 cgd * 3. All advertising materials mentioning features or use of this software
17 1.1 cgd * must display the following acknowledgement:
18 1.1 cgd * This product includes software developed by the University of
19 1.1 cgd * California, Berkeley and its contributors.
20 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
21 1.1 cgd * may be used to endorse or promote products derived from this software
22 1.1 cgd * without specific prior written permission.
23 1.1 cgd *
24 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 1.1 cgd * SUCH DAMAGE.
35 1.1 cgd *
36 1.32 fvdl * @(#)kern_malloc.c 8.4 (Berkeley) 5/20/95
37 1.1 cgd */
38 1.64 lukem
39 1.64 lukem #include <sys/cdefs.h>
40 1.70.4.1 thorpej __KERNEL_RCSID(0, "$NetBSD: kern_malloc.c,v 1.70.4.1 2002/03/22 18:59:31 thorpej Exp $");
41 1.31 mrg
42 1.33 thorpej #include "opt_lockdebug.h"
43 1.1 cgd
44 1.7 mycroft #include <sys/param.h>
45 1.7 mycroft #include <sys/proc.h>
46 1.8 cgd #include <sys/map.h>
47 1.7 mycroft #include <sys/kernel.h>
48 1.7 mycroft #include <sys/malloc.h>
49 1.12 christos #include <sys/systm.h>
50 1.24 thorpej
51 1.28 mrg #include <uvm/uvm_extern.h>
52 1.28 mrg
53 1.61 thorpej static struct vm_map kmem_map_store;
54 1.58 chs struct vm_map *kmem_map = NULL;
55 1.28 mrg
56 1.70.4.1 thorpej kmutex_t malloc_mutex;
57 1.70.4.1 thorpej
58 1.49 thorpej #include "opt_kmempages.h"
59 1.49 thorpej
60 1.49 thorpej #ifdef NKMEMCLUSTERS
61 1.52 sommerfe #error NKMEMCLUSTERS is obsolete; remove it from your kernel config file and use NKMEMPAGES instead or let the kernel auto-size
62 1.49 thorpej #endif
63 1.49 thorpej
64 1.49 thorpej /*
65 1.49 thorpej * Default number of pages in kmem_map. We attempt to calculate this
66 1.49 thorpej * at run-time, but allow it to be either patched or set in the kernel
67 1.49 thorpej * config file.
68 1.49 thorpej */
69 1.49 thorpej #ifndef NKMEMPAGES
70 1.49 thorpej #define NKMEMPAGES 0
71 1.49 thorpej #endif
72 1.49 thorpej int nkmempages = NKMEMPAGES;
73 1.49 thorpej
74 1.49 thorpej /*
75 1.49 thorpej * Defaults for lower- and upper-bounds for the kmem_map page count.
76 1.49 thorpej * Can be overridden by kernel config options.
77 1.49 thorpej */
78 1.49 thorpej #ifndef NKMEMPAGES_MIN
79 1.49 thorpej #define NKMEMPAGES_MIN NKMEMPAGES_MIN_DEFAULT
80 1.49 thorpej #endif
81 1.49 thorpej
82 1.49 thorpej #ifndef NKMEMPAGES_MAX
83 1.49 thorpej #define NKMEMPAGES_MAX NKMEMPAGES_MAX_DEFAULT
84 1.49 thorpej #endif
85 1.49 thorpej
86 1.24 thorpej #include "opt_kmemstats.h"
87 1.27 thorpej #include "opt_malloclog.h"
88 1.12 christos
89 1.1 cgd struct kmembuckets bucket[MINBUCKET + 16];
90 1.8 cgd struct kmemstats kmemstats[M_LAST];
91 1.1 cgd struct kmemusage *kmemusage;
92 1.1 cgd char *kmembase, *kmemlimit;
93 1.57 jdolecek const char * const memname[] = INITKMEMNAMES;
94 1.1 cgd
95 1.27 thorpej #ifdef MALLOCLOG
96 1.27 thorpej #ifndef MALLOCLOGSIZE
97 1.27 thorpej #define MALLOCLOGSIZE 100000
98 1.27 thorpej #endif
99 1.27 thorpej
100 1.27 thorpej struct malloclog {
101 1.27 thorpej void *addr;
102 1.27 thorpej long size;
103 1.27 thorpej int type;
104 1.27 thorpej int action;
105 1.27 thorpej const char *file;
106 1.27 thorpej long line;
107 1.27 thorpej } malloclog[MALLOCLOGSIZE];
108 1.27 thorpej
109 1.27 thorpej long malloclogptr;
110 1.27 thorpej
111 1.69 enami static void domlog(void *, long, int, int, const char *, long);
112 1.69 enami static void hitmlog(void *);
113 1.27 thorpej
114 1.27 thorpej static void
115 1.69 enami domlog(void *a, long size, int type, int action, const char *file, long line)
116 1.27 thorpej {
117 1.27 thorpej
118 1.27 thorpej malloclog[malloclogptr].addr = a;
119 1.27 thorpej malloclog[malloclogptr].size = size;
120 1.27 thorpej malloclog[malloclogptr].type = type;
121 1.27 thorpej malloclog[malloclogptr].action = action;
122 1.27 thorpej malloclog[malloclogptr].file = file;
123 1.27 thorpej malloclog[malloclogptr].line = line;
124 1.27 thorpej malloclogptr++;
125 1.27 thorpej if (malloclogptr >= MALLOCLOGSIZE)
126 1.27 thorpej malloclogptr = 0;
127 1.27 thorpej }
128 1.27 thorpej
129 1.27 thorpej static void
130 1.69 enami hitmlog(void *a)
131 1.27 thorpej {
132 1.27 thorpej struct malloclog *lp;
133 1.27 thorpej long l;
134 1.27 thorpej
135 1.69 enami #define PRT do { \
136 1.27 thorpej if (malloclog[l].addr == a && malloclog[l].action) { \
137 1.27 thorpej lp = &malloclog[l]; \
138 1.27 thorpej printf("malloc log entry %ld:\n", l); \
139 1.27 thorpej printf("\taddr = %p\n", lp->addr); \
140 1.27 thorpej printf("\tsize = %ld\n", lp->size); \
141 1.27 thorpej printf("\ttype = %s\n", memname[lp->type]); \
142 1.27 thorpej printf("\taction = %s\n", lp->action == 1 ? "alloc" : "free"); \
143 1.27 thorpej printf("\tfile = %s\n", lp->file); \
144 1.27 thorpej printf("\tline = %ld\n", lp->line); \
145 1.69 enami } \
146 1.69 enami } while (/* CONSTCOND */0)
147 1.27 thorpej
148 1.27 thorpej for (l = malloclogptr; l < MALLOCLOGSIZE; l++)
149 1.69 enami PRT;
150 1.27 thorpej
151 1.27 thorpej for (l = 0; l < malloclogptr; l++)
152 1.69 enami PRT;
153 1.27 thorpej }
154 1.27 thorpej #endif /* MALLOCLOG */
155 1.27 thorpej
156 1.8 cgd #ifdef DIAGNOSTIC
157 1.8 cgd /*
158 1.8 cgd * This structure provides a set of masks to catch unaligned frees.
159 1.8 cgd */
160 1.57 jdolecek const long addrmask[] = { 0,
161 1.8 cgd 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
162 1.8 cgd 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
163 1.8 cgd 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
164 1.8 cgd 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
165 1.8 cgd };
166 1.8 cgd
167 1.8 cgd /*
168 1.8 cgd * The WEIRD_ADDR is used as known text to copy into free objects so
169 1.8 cgd * that modifications after frees can be detected.
170 1.8 cgd */
171 1.69 enami #define WEIRD_ADDR ((unsigned) 0xdeadbeef)
172 1.55 chs #ifdef DEBUG
173 1.69 enami #define MAX_COPY PAGE_SIZE
174 1.55 chs #else
175 1.69 enami #define MAX_COPY 32
176 1.55 chs #endif
177 1.8 cgd
178 1.8 cgd /*
179 1.11 cgd * Normally the freelist structure is used only to hold the list pointer
180 1.11 cgd * for free objects. However, when running with diagnostics, the first
181 1.11 cgd * 8 bytes of the structure is unused except for diagnostic information,
182 1.11 cgd * and the free list pointer is at offst 8 in the structure. Since the
183 1.11 cgd * first 8 bytes is the portion of the structure most often modified, this
184 1.11 cgd * helps to detect memory reuse problems and avoid free list corruption.
185 1.8 cgd */
186 1.8 cgd struct freelist {
187 1.11 cgd int32_t spare0;
188 1.11 cgd int16_t type;
189 1.11 cgd int16_t spare1;
190 1.8 cgd caddr_t next;
191 1.8 cgd };
192 1.8 cgd #else /* !DIAGNOSTIC */
193 1.8 cgd struct freelist {
194 1.8 cgd caddr_t next;
195 1.8 cgd };
196 1.8 cgd #endif /* DIAGNOSTIC */
197 1.8 cgd
198 1.1 cgd /*
199 1.1 cgd * Allocate a block of memory
200 1.1 cgd */
201 1.27 thorpej #ifdef MALLOCLOG
202 1.27 thorpej void *
203 1.69 enami _malloc(unsigned long size, int type, int flags, const char *file, long line)
204 1.27 thorpej #else
205 1.1 cgd void *
206 1.69 enami malloc(unsigned long size, int type, int flags)
207 1.27 thorpej #endif /* MALLOCLOG */
208 1.1 cgd {
209 1.50 augustss struct kmembuckets *kbp;
210 1.50 augustss struct kmemusage *kup;
211 1.50 augustss struct freelist *freep;
212 1.5 andrew long indx, npg, allocsize;
213 1.1 cgd caddr_t va, cp, savedlist;
214 1.8 cgd #ifdef DIAGNOSTIC
215 1.11 cgd int32_t *end, *lp;
216 1.8 cgd int copysize;
217 1.26 mycroft const char *savedtype;
218 1.8 cgd #endif
219 1.1 cgd #ifdef KMEMSTATS
220 1.50 augustss struct kmemstats *ksp = &kmemstats[type];
221 1.1 cgd
222 1.51 thorpej if (__predict_false(((unsigned long)type) > M_LAST))
223 1.1 cgd panic("malloc - bogus type");
224 1.1 cgd #endif
225 1.59 thorpej #ifdef LOCKDEBUG
226 1.59 thorpej if ((flags & M_NOWAIT) == 0)
227 1.59 thorpej simple_lock_only_held(NULL, "malloc");
228 1.59 thorpej #endif
229 1.62 thorpej #ifdef MALLOC_DEBUG
230 1.62 thorpej if (debug_malloc(size, type, flags, (void **) &va))
231 1.62 thorpej return ((void *) va);
232 1.62 thorpej #endif
233 1.1 cgd indx = BUCKETINDX(size);
234 1.1 cgd kbp = &bucket[indx];
235 1.70.4.1 thorpej
236 1.70.4.1 thorpej mutex_enter(&malloc_mutex);
237 1.70.4.1 thorpej
238 1.1 cgd #ifdef KMEMSTATS
239 1.1 cgd while (ksp->ks_memuse >= ksp->ks_limit) {
240 1.1 cgd if (flags & M_NOWAIT) {
241 1.70.4.1 thorpej mutex_exit(&malloc_mutex);
242 1.1 cgd return ((void *) NULL);
243 1.1 cgd }
244 1.1 cgd if (ksp->ks_limblocks < 65535)
245 1.1 cgd ksp->ks_limblocks++;
246 1.1 cgd tsleep((caddr_t)ksp, PSWP+2, memname[type], 0);
247 1.1 cgd }
248 1.8 cgd ksp->ks_size |= 1 << indx;
249 1.8 cgd #endif
250 1.8 cgd #ifdef DIAGNOSTIC
251 1.8 cgd copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
252 1.1 cgd #endif
253 1.1 cgd if (kbp->kb_next == NULL) {
254 1.8 cgd kbp->kb_last = NULL;
255 1.1 cgd if (size > MAXALLOCSAVE)
256 1.66 enami allocsize = round_page(size);
257 1.1 cgd else
258 1.1 cgd allocsize = 1 << indx;
259 1.47 ragge npg = btoc(allocsize);
260 1.63 chs va = (caddr_t) uvm_km_kmemalloc(kmem_map, NULL,
261 1.69 enami (vsize_t)ctob(npg),
262 1.69 enami (flags & M_NOWAIT) ? UVM_KMF_NOWAIT : 0);
263 1.51 thorpej if (__predict_false(va == NULL)) {
264 1.17 cgd /*
265 1.17 cgd * Kmem_malloc() can return NULL, even if it can
266 1.17 cgd * wait, if there is no map space avaiable, because
267 1.17 cgd * it can't fix that problem. Neither can we,
268 1.17 cgd * right now. (We should release pages which
269 1.17 cgd * are completely free and which are in buckets
270 1.17 cgd * with too many free elements.)
271 1.17 cgd */
272 1.68 jdolecek if ((flags & (M_NOWAIT|M_CANFAIL)) == 0)
273 1.17 cgd panic("malloc: out of space in kmem_map");
274 1.70.4.1 thorpej mutex_exit(&malloc_mutex);
275 1.6 cgd return ((void *) NULL);
276 1.1 cgd }
277 1.1 cgd #ifdef KMEMSTATS
278 1.1 cgd kbp->kb_total += kbp->kb_elmpercl;
279 1.1 cgd #endif
280 1.1 cgd kup = btokup(va);
281 1.1 cgd kup->ku_indx = indx;
282 1.1 cgd if (allocsize > MAXALLOCSAVE) {
283 1.1 cgd if (npg > 65535)
284 1.1 cgd panic("malloc: allocation too large");
285 1.1 cgd kup->ku_pagecnt = npg;
286 1.1 cgd #ifdef KMEMSTATS
287 1.1 cgd ksp->ks_memuse += allocsize;
288 1.1 cgd #endif
289 1.1 cgd goto out;
290 1.1 cgd }
291 1.1 cgd #ifdef KMEMSTATS
292 1.1 cgd kup->ku_freecnt = kbp->kb_elmpercl;
293 1.1 cgd kbp->kb_totalfree += kbp->kb_elmpercl;
294 1.1 cgd #endif
295 1.1 cgd /*
296 1.1 cgd * Just in case we blocked while allocating memory,
297 1.1 cgd * and someone else also allocated memory for this
298 1.1 cgd * bucket, don't assume the list is still empty.
299 1.1 cgd */
300 1.1 cgd savedlist = kbp->kb_next;
301 1.49 thorpej kbp->kb_next = cp = va + (npg << PAGE_SHIFT) - allocsize;
302 1.8 cgd for (;;) {
303 1.8 cgd freep = (struct freelist *)cp;
304 1.8 cgd #ifdef DIAGNOSTIC
305 1.8 cgd /*
306 1.8 cgd * Copy in known text to detect modification
307 1.8 cgd * after freeing.
308 1.8 cgd */
309 1.11 cgd end = (int32_t *)&cp[copysize];
310 1.11 cgd for (lp = (int32_t *)cp; lp < end; lp++)
311 1.8 cgd *lp = WEIRD_ADDR;
312 1.8 cgd freep->type = M_FREE;
313 1.8 cgd #endif /* DIAGNOSTIC */
314 1.8 cgd if (cp <= va)
315 1.8 cgd break;
316 1.8 cgd cp -= allocsize;
317 1.8 cgd freep->next = cp;
318 1.8 cgd }
319 1.8 cgd freep->next = savedlist;
320 1.8 cgd if (kbp->kb_last == NULL)
321 1.8 cgd kbp->kb_last = (caddr_t)freep;
322 1.1 cgd }
323 1.1 cgd va = kbp->kb_next;
324 1.8 cgd kbp->kb_next = ((struct freelist *)va)->next;
325 1.8 cgd #ifdef DIAGNOSTIC
326 1.8 cgd freep = (struct freelist *)va;
327 1.8 cgd savedtype = (unsigned)freep->type < M_LAST ?
328 1.8 cgd memname[freep->type] : "???";
329 1.29 chs if (kbp->kb_next) {
330 1.29 chs int rv;
331 1.35 eeh vaddr_t addr = (vaddr_t)kbp->kb_next;
332 1.29 chs
333 1.43 thorpej vm_map_lock(kmem_map);
334 1.29 chs rv = uvm_map_checkprot(kmem_map, addr,
335 1.69 enami addr + sizeof(struct freelist), VM_PROT_WRITE);
336 1.43 thorpej vm_map_unlock(kmem_map);
337 1.29 chs
338 1.51 thorpej if (__predict_false(rv == 0)) {
339 1.69 enami printf("Data modified on freelist: "
340 1.69 enami "word %ld of object %p size %ld previous type %s "
341 1.69 enami "(invalid addr %p)\n",
342 1.41 mrg (long)((int32_t *)&kbp->kb_next - (int32_t *)kbp),
343 1.69 enami va, size, savedtype, kbp->kb_next);
344 1.27 thorpej #ifdef MALLOCLOG
345 1.41 mrg hitmlog(va);
346 1.27 thorpej #endif
347 1.41 mrg kbp->kb_next = NULL;
348 1.29 chs }
349 1.8 cgd }
350 1.11 cgd
351 1.11 cgd /* Fill the fields that we've used with WEIRD_ADDR */
352 1.8 cgd #if BYTE_ORDER == BIG_ENDIAN
353 1.8 cgd freep->type = WEIRD_ADDR >> 16;
354 1.8 cgd #endif
355 1.8 cgd #if BYTE_ORDER == LITTLE_ENDIAN
356 1.8 cgd freep->type = (short)WEIRD_ADDR;
357 1.8 cgd #endif
358 1.11 cgd end = (int32_t *)&freep->next +
359 1.11 cgd (sizeof(freep->next) / sizeof(int32_t));
360 1.11 cgd for (lp = (int32_t *)&freep->next; lp < end; lp++)
361 1.11 cgd *lp = WEIRD_ADDR;
362 1.11 cgd
363 1.11 cgd /* and check that the data hasn't been modified. */
364 1.11 cgd end = (int32_t *)&va[copysize];
365 1.11 cgd for (lp = (int32_t *)va; lp < end; lp++) {
366 1.51 thorpej if (__predict_true(*lp == WEIRD_ADDR))
367 1.8 cgd continue;
368 1.69 enami printf("Data modified on freelist: "
369 1.69 enami "word %ld of object %p size %ld previous type %s "
370 1.69 enami "(0x%x != 0x%x)\n",
371 1.69 enami (long)(lp - (int32_t *)va), va, size,
372 1.21 christos savedtype, *lp, WEIRD_ADDR);
373 1.27 thorpej #ifdef MALLOCLOG
374 1.27 thorpej hitmlog(va);
375 1.27 thorpej #endif
376 1.8 cgd break;
377 1.8 cgd }
378 1.11 cgd
379 1.8 cgd freep->spare0 = 0;
380 1.8 cgd #endif /* DIAGNOSTIC */
381 1.1 cgd #ifdef KMEMSTATS
382 1.1 cgd kup = btokup(va);
383 1.1 cgd if (kup->ku_indx != indx)
384 1.1 cgd panic("malloc: wrong bucket");
385 1.1 cgd if (kup->ku_freecnt == 0)
386 1.1 cgd panic("malloc: lost data");
387 1.1 cgd kup->ku_freecnt--;
388 1.1 cgd kbp->kb_totalfree--;
389 1.1 cgd ksp->ks_memuse += 1 << indx;
390 1.1 cgd out:
391 1.1 cgd kbp->kb_calls++;
392 1.1 cgd ksp->ks_inuse++;
393 1.1 cgd ksp->ks_calls++;
394 1.1 cgd if (ksp->ks_memuse > ksp->ks_maxused)
395 1.1 cgd ksp->ks_maxused = ksp->ks_memuse;
396 1.1 cgd #else
397 1.1 cgd out:
398 1.1 cgd #endif
399 1.27 thorpej #ifdef MALLOCLOG
400 1.27 thorpej domlog(va, size, type, 1, file, line);
401 1.27 thorpej #endif
402 1.70.4.1 thorpej mutex_exit(&malloc_mutex);
403 1.67 enami if ((flags & M_ZERO) != 0)
404 1.65 lukem memset(va, 0, size);
405 1.1 cgd return ((void *) va);
406 1.1 cgd }
407 1.1 cgd
408 1.1 cgd /*
409 1.1 cgd * Free a block of memory allocated by malloc.
410 1.1 cgd */
411 1.27 thorpej #ifdef MALLOCLOG
412 1.27 thorpej void
413 1.69 enami _free(void *addr, int type, const char *file, long line)
414 1.27 thorpej #else
415 1.1 cgd void
416 1.69 enami free(void *addr, int type)
417 1.27 thorpej #endif /* MALLOCLOG */
418 1.1 cgd {
419 1.50 augustss struct kmembuckets *kbp;
420 1.50 augustss struct kmemusage *kup;
421 1.50 augustss struct freelist *freep;
422 1.8 cgd long size;
423 1.5 andrew #ifdef DIAGNOSTIC
424 1.8 cgd caddr_t cp;
425 1.11 cgd int32_t *end, *lp;
426 1.11 cgd long alloc, copysize;
427 1.5 andrew #endif
428 1.1 cgd #ifdef KMEMSTATS
429 1.50 augustss struct kmemstats *ksp = &kmemstats[type];
430 1.48 thorpej #endif
431 1.48 thorpej
432 1.62 thorpej #ifdef MALLOC_DEBUG
433 1.62 thorpej if (debug_free(addr, type))
434 1.62 thorpej return;
435 1.62 thorpej #endif
436 1.62 thorpej
437 1.48 thorpej #ifdef DIAGNOSTIC
438 1.48 thorpej /*
439 1.48 thorpej * Ensure that we're free'ing something that we could
440 1.48 thorpej * have allocated in the first place. That is, check
441 1.48 thorpej * to see that the address is within kmem_map.
442 1.48 thorpej */
443 1.51 thorpej if (__predict_false((vaddr_t)addr < kmem_map->header.start ||
444 1.69 enami (vaddr_t)addr >= kmem_map->header.end))
445 1.48 thorpej panic("free: addr %p not within kmem_map", addr);
446 1.1 cgd #endif
447 1.1 cgd
448 1.1 cgd kup = btokup(addr);
449 1.1 cgd size = 1 << kup->ku_indx;
450 1.8 cgd kbp = &bucket[kup->ku_indx];
451 1.70.4.1 thorpej
452 1.70.4.1 thorpej mutex_enter(&malloc_mutex);
453 1.70.4.1 thorpej
454 1.27 thorpej #ifdef MALLOCLOG
455 1.27 thorpej domlog(addr, 0, type, 2, file, line);
456 1.27 thorpej #endif
457 1.1 cgd #ifdef DIAGNOSTIC
458 1.8 cgd /*
459 1.8 cgd * Check for returns of data that do not point to the
460 1.8 cgd * beginning of the allocation.
461 1.8 cgd */
462 1.49 thorpej if (size > PAGE_SIZE)
463 1.49 thorpej alloc = addrmask[BUCKETINDX(PAGE_SIZE)];
464 1.1 cgd else
465 1.1 cgd alloc = addrmask[kup->ku_indx];
466 1.8 cgd if (((u_long)addr & alloc) != 0)
467 1.15 christos panic("free: unaligned addr %p, size %ld, type %s, mask %ld\n",
468 1.69 enami addr, size, memname[type], alloc);
469 1.1 cgd #endif /* DIAGNOSTIC */
470 1.1 cgd if (size > MAXALLOCSAVE) {
471 1.35 eeh uvm_km_free(kmem_map, (vaddr_t)addr, ctob(kup->ku_pagecnt));
472 1.1 cgd #ifdef KMEMSTATS
473 1.1 cgd size = kup->ku_pagecnt << PGSHIFT;
474 1.1 cgd ksp->ks_memuse -= size;
475 1.1 cgd kup->ku_indx = 0;
476 1.1 cgd kup->ku_pagecnt = 0;
477 1.1 cgd if (ksp->ks_memuse + size >= ksp->ks_limit &&
478 1.1 cgd ksp->ks_memuse < ksp->ks_limit)
479 1.1 cgd wakeup((caddr_t)ksp);
480 1.1 cgd ksp->ks_inuse--;
481 1.1 cgd kbp->kb_total -= 1;
482 1.1 cgd #endif
483 1.70.4.1 thorpej mutex_exit(&malloc_mutex);
484 1.1 cgd return;
485 1.1 cgd }
486 1.8 cgd freep = (struct freelist *)addr;
487 1.8 cgd #ifdef DIAGNOSTIC
488 1.8 cgd /*
489 1.8 cgd * Check for multiple frees. Use a quick check to see if
490 1.8 cgd * it looks free before laboriously searching the freelist.
491 1.8 cgd */
492 1.51 thorpej if (__predict_false(freep->spare0 == WEIRD_ADDR)) {
493 1.16 cgd for (cp = kbp->kb_next; cp;
494 1.16 cgd cp = ((struct freelist *)cp)->next) {
495 1.8 cgd if (addr != cp)
496 1.8 cgd continue;
497 1.22 christos printf("multiply freed item %p\n", addr);
498 1.27 thorpej #ifdef MALLOCLOG
499 1.27 thorpej hitmlog(addr);
500 1.27 thorpej #endif
501 1.8 cgd panic("free: duplicated free");
502 1.8 cgd }
503 1.8 cgd }
504 1.38 chs #ifdef LOCKDEBUG
505 1.38 chs /*
506 1.38 chs * Check if we're freeing a locked simple lock.
507 1.38 chs */
508 1.40 chs simple_lock_freecheck(addr, (char *)addr + size);
509 1.38 chs #endif
510 1.8 cgd /*
511 1.8 cgd * Copy in known text to detect modification after freeing
512 1.8 cgd * and to make it look free. Also, save the type being freed
513 1.8 cgd * so we can list likely culprit if modification is detected
514 1.8 cgd * when the object is reallocated.
515 1.8 cgd */
516 1.8 cgd copysize = size < MAX_COPY ? size : MAX_COPY;
517 1.11 cgd end = (int32_t *)&((caddr_t)addr)[copysize];
518 1.11 cgd for (lp = (int32_t *)addr; lp < end; lp++)
519 1.8 cgd *lp = WEIRD_ADDR;
520 1.8 cgd freep->type = type;
521 1.8 cgd #endif /* DIAGNOSTIC */
522 1.1 cgd #ifdef KMEMSTATS
523 1.1 cgd kup->ku_freecnt++;
524 1.36 thorpej if (kup->ku_freecnt >= kbp->kb_elmpercl) {
525 1.1 cgd if (kup->ku_freecnt > kbp->kb_elmpercl)
526 1.1 cgd panic("free: multiple frees");
527 1.1 cgd else if (kbp->kb_totalfree > kbp->kb_highwat)
528 1.1 cgd kbp->kb_couldfree++;
529 1.36 thorpej }
530 1.1 cgd kbp->kb_totalfree++;
531 1.1 cgd ksp->ks_memuse -= size;
532 1.1 cgd if (ksp->ks_memuse + size >= ksp->ks_limit &&
533 1.1 cgd ksp->ks_memuse < ksp->ks_limit)
534 1.1 cgd wakeup((caddr_t)ksp);
535 1.1 cgd ksp->ks_inuse--;
536 1.1 cgd #endif
537 1.8 cgd if (kbp->kb_next == NULL)
538 1.8 cgd kbp->kb_next = addr;
539 1.8 cgd else
540 1.8 cgd ((struct freelist *)kbp->kb_last)->next = addr;
541 1.8 cgd freep->next = NULL;
542 1.8 cgd kbp->kb_last = addr;
543 1.70.4.1 thorpej mutex_exit(&malloc_mutex);
544 1.20 cgd }
545 1.20 cgd
546 1.20 cgd /*
547 1.20 cgd * Change the size of a block of memory.
548 1.20 cgd */
549 1.20 cgd void *
550 1.69 enami realloc(void *curaddr, unsigned long newsize, int type, int flags)
551 1.20 cgd {
552 1.50 augustss struct kmemusage *kup;
553 1.20 cgd long cursize;
554 1.20 cgd void *newaddr;
555 1.20 cgd #ifdef DIAGNOSTIC
556 1.20 cgd long alloc;
557 1.20 cgd #endif
558 1.20 cgd
559 1.20 cgd /*
560 1.69 enami * realloc() with a NULL pointer is the same as malloc().
561 1.20 cgd */
562 1.20 cgd if (curaddr == NULL)
563 1.20 cgd return (malloc(newsize, type, flags));
564 1.20 cgd
565 1.20 cgd /*
566 1.69 enami * realloc() with zero size is the same as free().
567 1.20 cgd */
568 1.20 cgd if (newsize == 0) {
569 1.20 cgd free(curaddr, type);
570 1.20 cgd return (NULL);
571 1.20 cgd }
572 1.59 thorpej
573 1.59 thorpej #ifdef LOCKDEBUG
574 1.59 thorpej if ((flags & M_NOWAIT) == 0)
575 1.59 thorpej simple_lock_only_held(NULL, "realloc");
576 1.59 thorpej #endif
577 1.20 cgd
578 1.20 cgd /*
579 1.20 cgd * Find out how large the old allocation was (and do some
580 1.20 cgd * sanity checking).
581 1.20 cgd */
582 1.20 cgd kup = btokup(curaddr);
583 1.20 cgd cursize = 1 << kup->ku_indx;
584 1.20 cgd
585 1.20 cgd #ifdef DIAGNOSTIC
586 1.20 cgd /*
587 1.20 cgd * Check for returns of data that do not point to the
588 1.20 cgd * beginning of the allocation.
589 1.20 cgd */
590 1.49 thorpej if (cursize > PAGE_SIZE)
591 1.49 thorpej alloc = addrmask[BUCKETINDX(PAGE_SIZE)];
592 1.20 cgd else
593 1.20 cgd alloc = addrmask[kup->ku_indx];
594 1.20 cgd if (((u_long)curaddr & alloc) != 0)
595 1.69 enami panic("realloc: "
596 1.69 enami "unaligned addr %p, size %ld, type %s, mask %ld\n",
597 1.69 enami curaddr, cursize, memname[type], alloc);
598 1.20 cgd #endif /* DIAGNOSTIC */
599 1.20 cgd
600 1.20 cgd if (cursize > MAXALLOCSAVE)
601 1.20 cgd cursize = ctob(kup->ku_pagecnt);
602 1.20 cgd
603 1.20 cgd /*
604 1.20 cgd * If we already actually have as much as they want, we're done.
605 1.20 cgd */
606 1.20 cgd if (newsize <= cursize)
607 1.20 cgd return (curaddr);
608 1.20 cgd
609 1.20 cgd /*
610 1.20 cgd * Can't satisfy the allocation with the existing block.
611 1.20 cgd * Allocate a new one and copy the data.
612 1.20 cgd */
613 1.20 cgd newaddr = malloc(newsize, type, flags);
614 1.51 thorpej if (__predict_false(newaddr == NULL)) {
615 1.20 cgd /*
616 1.69 enami * malloc() failed, because flags included M_NOWAIT.
617 1.20 cgd * Return NULL to indicate that failure. The old
618 1.20 cgd * pointer is still valid.
619 1.20 cgd */
620 1.69 enami return (NULL);
621 1.20 cgd }
622 1.34 perry memcpy(newaddr, curaddr, cursize);
623 1.20 cgd
624 1.20 cgd /*
625 1.20 cgd * We were successful: free the old allocation and return
626 1.20 cgd * the new one.
627 1.20 cgd */
628 1.20 cgd free(curaddr, type);
629 1.20 cgd return (newaddr);
630 1.70 enami }
631 1.70 enami
632 1.70 enami /*
633 1.70 enami * Roundup size to the actual allocation size.
634 1.70 enami */
635 1.70 enami unsigned long
636 1.70 enami malloc_roundup(unsigned long size)
637 1.70 enami {
638 1.70 enami
639 1.70 enami if (size > MAXALLOCSAVE)
640 1.70 enami return (roundup(size, PAGE_SIZE));
641 1.70 enami else
642 1.70 enami return (1 << BUCKETINDX(size));
643 1.1 cgd }
644 1.1 cgd
645 1.1 cgd /*
646 1.49 thorpej * Compute the number of pages that kmem_map will map, that is,
647 1.49 thorpej * the size of the kernel malloc arena.
648 1.49 thorpej */
649 1.49 thorpej void
650 1.69 enami kmeminit_nkmempages(void)
651 1.49 thorpej {
652 1.49 thorpej int npages;
653 1.49 thorpej
654 1.49 thorpej if (nkmempages != 0) {
655 1.49 thorpej /*
656 1.49 thorpej * It's already been set (by us being here before, or
657 1.49 thorpej * by patching or kernel config options), bail out now.
658 1.49 thorpej */
659 1.49 thorpej return;
660 1.49 thorpej }
661 1.49 thorpej
662 1.49 thorpej /*
663 1.49 thorpej * We use the following (simple) formula:
664 1.49 thorpej *
665 1.49 thorpej * - Starting point is physical memory / 4.
666 1.49 thorpej *
667 1.49 thorpej * - Clamp it down to NKMEMPAGES_MAX.
668 1.49 thorpej *
669 1.49 thorpej * - Round it up to NKMEMPAGES_MIN.
670 1.49 thorpej */
671 1.49 thorpej npages = physmem / 4;
672 1.49 thorpej
673 1.49 thorpej if (npages > NKMEMPAGES_MAX)
674 1.49 thorpej npages = NKMEMPAGES_MAX;
675 1.49 thorpej
676 1.49 thorpej if (npages < NKMEMPAGES_MIN)
677 1.49 thorpej npages = NKMEMPAGES_MIN;
678 1.49 thorpej
679 1.49 thorpej nkmempages = npages;
680 1.49 thorpej }
681 1.49 thorpej
682 1.49 thorpej /*
683 1.1 cgd * Initialize the kernel memory allocator
684 1.1 cgd */
685 1.12 christos void
686 1.69 enami kmeminit(void)
687 1.1 cgd {
688 1.23 tls #ifdef KMEMSTATS
689 1.50 augustss long indx;
690 1.23 tls #endif
691 1.1 cgd
692 1.1 cgd #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
693 1.1 cgd ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2
694 1.1 cgd #endif
695 1.1 cgd #if (MAXALLOCSAVE > MINALLOCSIZE * 32768)
696 1.1 cgd ERROR!_kmeminit:_MAXALLOCSAVE_too_big
697 1.1 cgd #endif
698 1.47 ragge #if (MAXALLOCSAVE < NBPG)
699 1.1 cgd ERROR!_kmeminit:_MAXALLOCSAVE_too_small
700 1.1 cgd #endif
701 1.11 cgd
702 1.11 cgd if (sizeof(struct freelist) > (1 << MINBUCKET))
703 1.11 cgd panic("minbucket too small/struct freelist too big");
704 1.11 cgd
705 1.49 thorpej /*
706 1.49 thorpej * Compute the number of kmem_map pages, if we have not
707 1.49 thorpej * done so already.
708 1.49 thorpej */
709 1.49 thorpej kmeminit_nkmempages();
710 1.49 thorpej
711 1.28 mrg kmemusage = (struct kmemusage *) uvm_km_zalloc(kernel_map,
712 1.69 enami (vsize_t)(nkmempages * sizeof(struct kmemusage)));
713 1.35 eeh kmem_map = uvm_km_suballoc(kernel_map, (vaddr_t *)&kmembase,
714 1.69 enami (vaddr_t *)&kmemlimit, (vsize_t)(nkmempages << PAGE_SHIFT),
715 1.69 enami VM_MAP_INTRSAFE, FALSE, &kmem_map_store);
716 1.1 cgd #ifdef KMEMSTATS
717 1.1 cgd for (indx = 0; indx < MINBUCKET + 16; indx++) {
718 1.49 thorpej if (1 << indx >= PAGE_SIZE)
719 1.1 cgd bucket[indx].kb_elmpercl = 1;
720 1.1 cgd else
721 1.49 thorpej bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
722 1.1 cgd bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
723 1.1 cgd }
724 1.8 cgd for (indx = 0; indx < M_LAST; indx++)
725 1.60 thorpej kmemstats[indx].ks_limit =
726 1.60 thorpej ((u_long)nkmempages << PAGE_SHIFT) * 6U / 10U;
727 1.62 thorpej #endif
728 1.62 thorpej #ifdef MALLOC_DEBUG
729 1.62 thorpej debug_malloc_init();
730 1.1 cgd #endif
731 1.70.4.1 thorpej
732 1.70.4.1 thorpej mutex_init(&malloc_mutex, MUTEX_SPIN, IPL_VM);
733 1.1 cgd }
734 1.39 thorpej
735 1.39 thorpej #ifdef DDB
736 1.39 thorpej #include <ddb/db_output.h>
737 1.39 thorpej
738 1.39 thorpej /*
739 1.39 thorpej * Dump kmem statistics from ddb.
740 1.39 thorpej *
741 1.39 thorpej * usage: call dump_kmemstats
742 1.39 thorpej */
743 1.69 enami void dump_kmemstats(void);
744 1.39 thorpej
745 1.39 thorpej void
746 1.69 enami dump_kmemstats(void)
747 1.39 thorpej {
748 1.39 thorpej #ifdef KMEMSTATS
749 1.39 thorpej const char *name;
750 1.39 thorpej int i;
751 1.39 thorpej
752 1.39 thorpej for (i = 0; i < M_LAST; i++) {
753 1.39 thorpej name = memname[i] ? memname[i] : "";
754 1.39 thorpej
755 1.39 thorpej db_printf("%2d %s%.*s %ld\n", i, name,
756 1.39 thorpej (int)(20 - strlen(name)), " ",
757 1.39 thorpej kmemstats[i].ks_memuse);
758 1.39 thorpej }
759 1.39 thorpej #else
760 1.39 thorpej db_printf("Kmem stats are not being collected.\n");
761 1.39 thorpej #endif /* KMEMSTATS */
762 1.39 thorpej }
763 1.39 thorpej #endif /* DDB */
764