kern_malloc.c revision 1.79.2.6 1 1.79.2.6 skrll /* $NetBSD: kern_malloc.c,v 1.79.2.6 2005/04/01 14:30:56 skrll Exp $ */
2 1.9 cgd
3 1.1 cgd /*
4 1.8 cgd * Copyright (c) 1987, 1991, 1993
5 1.8 cgd * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * Redistribution and use in source and binary forms, with or without
8 1.1 cgd * modification, are permitted provided that the following conditions
9 1.1 cgd * are met:
10 1.1 cgd * 1. Redistributions of source code must retain the above copyright
11 1.1 cgd * notice, this list of conditions and the following disclaimer.
12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 cgd * notice, this list of conditions and the following disclaimer in the
14 1.1 cgd * documentation and/or other materials provided with the distribution.
15 1.79.2.1 skrll * 3. Neither the name of the University nor the names of its contributors
16 1.79.2.1 skrll * may be used to endorse or promote products derived from this software
17 1.79.2.1 skrll * without specific prior written permission.
18 1.79.2.1 skrll *
19 1.79.2.1 skrll * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 1.79.2.1 skrll * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 1.79.2.1 skrll * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 1.79.2.1 skrll * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 1.79.2.1 skrll * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 1.79.2.1 skrll * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 1.79.2.1 skrll * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 1.79.2.1 skrll * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 1.79.2.1 skrll * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 1.79.2.1 skrll * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 1.79.2.1 skrll * SUCH DAMAGE.
30 1.79.2.1 skrll *
31 1.79.2.1 skrll * @(#)kern_malloc.c 8.4 (Berkeley) 5/20/95
32 1.79.2.1 skrll */
33 1.79.2.1 skrll
34 1.79.2.1 skrll /*
35 1.79.2.1 skrll * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
36 1.79.2.1 skrll *
37 1.79.2.1 skrll * Redistribution and use in source and binary forms, with or without
38 1.79.2.1 skrll * modification, are permitted provided that the following conditions
39 1.79.2.1 skrll * are met:
40 1.79.2.1 skrll * 1. Redistributions of source code must retain the above copyright
41 1.79.2.1 skrll * notice, this list of conditions and the following disclaimer.
42 1.79.2.1 skrll * 2. Redistributions in binary form must reproduce the above copyright
43 1.79.2.1 skrll * notice, this list of conditions and the following disclaimer in the
44 1.79.2.1 skrll * documentation and/or other materials provided with the distribution.
45 1.1 cgd * 3. All advertising materials mentioning features or use of this software
46 1.1 cgd * must display the following acknowledgement:
47 1.1 cgd * This product includes software developed by the University of
48 1.1 cgd * California, Berkeley and its contributors.
49 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
50 1.1 cgd * may be used to endorse or promote products derived from this software
51 1.1 cgd * without specific prior written permission.
52 1.1 cgd *
53 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 1.1 cgd * SUCH DAMAGE.
64 1.1 cgd *
65 1.32 fvdl * @(#)kern_malloc.c 8.4 (Berkeley) 5/20/95
66 1.1 cgd */
67 1.64 lukem
68 1.64 lukem #include <sys/cdefs.h>
69 1.79.2.6 skrll __KERNEL_RCSID(0, "$NetBSD: kern_malloc.c,v 1.79.2.6 2005/04/01 14:30:56 skrll Exp $");
70 1.31 mrg
71 1.33 thorpej #include "opt_lockdebug.h"
72 1.1 cgd
73 1.7 mycroft #include <sys/param.h>
74 1.7 mycroft #include <sys/proc.h>
75 1.7 mycroft #include <sys/kernel.h>
76 1.7 mycroft #include <sys/malloc.h>
77 1.12 christos #include <sys/systm.h>
78 1.24 thorpej
79 1.28 mrg #include <uvm/uvm_extern.h>
80 1.28 mrg
81 1.79.2.4 skrll static struct vm_map_kernel kmem_map_store;
82 1.58 chs struct vm_map *kmem_map = NULL;
83 1.28 mrg
84 1.49 thorpej #include "opt_kmempages.h"
85 1.49 thorpej
86 1.49 thorpej #ifdef NKMEMCLUSTERS
87 1.52 sommerfe #error NKMEMCLUSTERS is obsolete; remove it from your kernel config file and use NKMEMPAGES instead or let the kernel auto-size
88 1.49 thorpej #endif
89 1.49 thorpej
90 1.49 thorpej /*
91 1.49 thorpej * Default number of pages in kmem_map. We attempt to calculate this
92 1.49 thorpej * at run-time, but allow it to be either patched or set in the kernel
93 1.49 thorpej * config file.
94 1.49 thorpej */
95 1.49 thorpej #ifndef NKMEMPAGES
96 1.49 thorpej #define NKMEMPAGES 0
97 1.49 thorpej #endif
98 1.49 thorpej int nkmempages = NKMEMPAGES;
99 1.49 thorpej
100 1.49 thorpej /*
101 1.49 thorpej * Defaults for lower- and upper-bounds for the kmem_map page count.
102 1.49 thorpej * Can be overridden by kernel config options.
103 1.49 thorpej */
104 1.49 thorpej #ifndef NKMEMPAGES_MIN
105 1.49 thorpej #define NKMEMPAGES_MIN NKMEMPAGES_MIN_DEFAULT
106 1.49 thorpej #endif
107 1.49 thorpej
108 1.49 thorpej #ifndef NKMEMPAGES_MAX
109 1.49 thorpej #define NKMEMPAGES_MAX NKMEMPAGES_MAX_DEFAULT
110 1.49 thorpej #endif
111 1.49 thorpej
112 1.24 thorpej #include "opt_kmemstats.h"
113 1.27 thorpej #include "opt_malloclog.h"
114 1.71 fvdl #include "opt_malloc_debug.h"
115 1.12 christos
116 1.1 cgd struct kmembuckets bucket[MINBUCKET + 16];
117 1.1 cgd struct kmemusage *kmemusage;
118 1.1 cgd char *kmembase, *kmemlimit;
119 1.77 thorpej
120 1.77 thorpej struct malloc_type *kmemstatistics;
121 1.1 cgd
122 1.27 thorpej #ifdef MALLOCLOG
123 1.27 thorpej #ifndef MALLOCLOGSIZE
124 1.27 thorpej #define MALLOCLOGSIZE 100000
125 1.27 thorpej #endif
126 1.27 thorpej
127 1.27 thorpej struct malloclog {
128 1.27 thorpej void *addr;
129 1.27 thorpej long size;
130 1.77 thorpej struct malloc_type *type;
131 1.27 thorpej int action;
132 1.27 thorpej const char *file;
133 1.27 thorpej long line;
134 1.27 thorpej } malloclog[MALLOCLOGSIZE];
135 1.27 thorpej
136 1.27 thorpej long malloclogptr;
137 1.27 thorpej
138 1.27 thorpej static void
139 1.77 thorpej domlog(void *a, long size, struct malloc_type *type, int action,
140 1.77 thorpej const char *file, long line)
141 1.27 thorpej {
142 1.27 thorpej
143 1.27 thorpej malloclog[malloclogptr].addr = a;
144 1.27 thorpej malloclog[malloclogptr].size = size;
145 1.27 thorpej malloclog[malloclogptr].type = type;
146 1.27 thorpej malloclog[malloclogptr].action = action;
147 1.27 thorpej malloclog[malloclogptr].file = file;
148 1.27 thorpej malloclog[malloclogptr].line = line;
149 1.27 thorpej malloclogptr++;
150 1.27 thorpej if (malloclogptr >= MALLOCLOGSIZE)
151 1.27 thorpej malloclogptr = 0;
152 1.27 thorpej }
153 1.27 thorpej
154 1.27 thorpej static void
155 1.69 enami hitmlog(void *a)
156 1.27 thorpej {
157 1.27 thorpej struct malloclog *lp;
158 1.27 thorpej long l;
159 1.27 thorpej
160 1.69 enami #define PRT do { \
161 1.79.2.1 skrll lp = &malloclog[l]; \
162 1.79.2.1 skrll if (lp->addr == a && lp->action) { \
163 1.27 thorpej printf("malloc log entry %ld:\n", l); \
164 1.27 thorpej printf("\taddr = %p\n", lp->addr); \
165 1.27 thorpej printf("\tsize = %ld\n", lp->size); \
166 1.77 thorpej printf("\ttype = %s\n", lp->type->ks_shortdesc); \
167 1.27 thorpej printf("\taction = %s\n", lp->action == 1 ? "alloc" : "free"); \
168 1.27 thorpej printf("\tfile = %s\n", lp->file); \
169 1.27 thorpej printf("\tline = %ld\n", lp->line); \
170 1.69 enami } \
171 1.69 enami } while (/* CONSTCOND */0)
172 1.27 thorpej
173 1.27 thorpej for (l = malloclogptr; l < MALLOCLOGSIZE; l++)
174 1.69 enami PRT;
175 1.27 thorpej
176 1.27 thorpej for (l = 0; l < malloclogptr; l++)
177 1.69 enami PRT;
178 1.79.2.1 skrll #undef PRT
179 1.27 thorpej }
180 1.27 thorpej #endif /* MALLOCLOG */
181 1.27 thorpej
182 1.8 cgd #ifdef DIAGNOSTIC
183 1.8 cgd /*
184 1.8 cgd * This structure provides a set of masks to catch unaligned frees.
185 1.8 cgd */
186 1.57 jdolecek const long addrmask[] = { 0,
187 1.8 cgd 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
188 1.8 cgd 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
189 1.8 cgd 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
190 1.8 cgd 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
191 1.8 cgd };
192 1.8 cgd
193 1.8 cgd /*
194 1.8 cgd * The WEIRD_ADDR is used as known text to copy into free objects so
195 1.8 cgd * that modifications after frees can be detected.
196 1.8 cgd */
197 1.76 thorpej #define WEIRD_ADDR ((uint32_t) 0xdeadbeef)
198 1.55 chs #ifdef DEBUG
199 1.69 enami #define MAX_COPY PAGE_SIZE
200 1.55 chs #else
201 1.69 enami #define MAX_COPY 32
202 1.55 chs #endif
203 1.8 cgd
204 1.8 cgd /*
205 1.11 cgd * Normally the freelist structure is used only to hold the list pointer
206 1.11 cgd * for free objects. However, when running with diagnostics, the first
207 1.77 thorpej * 8/16 bytes of the structure is unused except for diagnostic information,
208 1.77 thorpej * and the free list pointer is at offset 8/16 in the structure. Since the
209 1.11 cgd * first 8 bytes is the portion of the structure most often modified, this
210 1.11 cgd * helps to detect memory reuse problems and avoid free list corruption.
211 1.8 cgd */
212 1.8 cgd struct freelist {
213 1.76 thorpej uint32_t spare0;
214 1.77 thorpej #ifdef _LP64
215 1.77 thorpej uint32_t spare1; /* explicit padding */
216 1.77 thorpej #endif
217 1.77 thorpej struct malloc_type *type;
218 1.8 cgd caddr_t next;
219 1.8 cgd };
220 1.8 cgd #else /* !DIAGNOSTIC */
221 1.8 cgd struct freelist {
222 1.8 cgd caddr_t next;
223 1.8 cgd };
224 1.8 cgd #endif /* DIAGNOSTIC */
225 1.8 cgd
226 1.1 cgd /*
227 1.77 thorpej * The following are standard, build-in malloc types are are not
228 1.77 thorpej * specific to any one subsystem.
229 1.77 thorpej */
230 1.77 thorpej MALLOC_DEFINE(M_DEVBUF, "devbuf", "device driver memory");
231 1.77 thorpej MALLOC_DEFINE(M_DMAMAP, "DMA map", "bus_dma(9) structures");
232 1.77 thorpej MALLOC_DEFINE(M_FREE, "free", "should be on free list");
233 1.77 thorpej MALLOC_DEFINE(M_PCB, "pcb", "protocol control block");
234 1.77 thorpej MALLOC_DEFINE(M_SOFTINTR, "softintr", "Softinterrupt structures");
235 1.77 thorpej MALLOC_DEFINE(M_TEMP, "temp", "misc. temporary data buffers");
236 1.77 thorpej
237 1.77 thorpej /* XXX These should all be elsewhere. */
238 1.77 thorpej MALLOC_DEFINE(M_RTABLE, "routetbl", "routing tables");
239 1.77 thorpej MALLOC_DEFINE(M_FTABLE, "fragtbl", "fragment reassembly header");
240 1.77 thorpej MALLOC_DEFINE(M_UFSMNT, "UFS mount", "UFS mount structure");
241 1.77 thorpej MALLOC_DEFINE(M_NETADDR, "Export Host", "Export host address structure");
242 1.77 thorpej MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options");
243 1.77 thorpej MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address");
244 1.77 thorpej MALLOC_DEFINE(M_MRTABLE, "mrt", "multicast routing tables");
245 1.79.2.2 skrll MALLOC_DEFINE(M_BWMETER, "bwmeter", "multicast upcall bw meters");
246 1.77 thorpej MALLOC_DEFINE(M_1394DATA, "1394data", "IEEE 1394 data buffers");
247 1.77 thorpej
248 1.78 pk struct simplelock malloc_slock = SIMPLELOCK_INITIALIZER;
249 1.78 pk
250 1.77 thorpej /*
251 1.1 cgd * Allocate a block of memory
252 1.1 cgd */
253 1.27 thorpej #ifdef MALLOCLOG
254 1.27 thorpej void *
255 1.77 thorpej _malloc(unsigned long size, struct malloc_type *ksp, int flags,
256 1.77 thorpej const char *file, long line)
257 1.27 thorpej #else
258 1.1 cgd void *
259 1.77 thorpej malloc(unsigned long size, struct malloc_type *ksp, int flags)
260 1.27 thorpej #endif /* MALLOCLOG */
261 1.1 cgd {
262 1.50 augustss struct kmembuckets *kbp;
263 1.50 augustss struct kmemusage *kup;
264 1.50 augustss struct freelist *freep;
265 1.5 andrew long indx, npg, allocsize;
266 1.1 cgd int s;
267 1.1 cgd caddr_t va, cp, savedlist;
268 1.8 cgd #ifdef DIAGNOSTIC
269 1.76 thorpej uint32_t *end, *lp;
270 1.8 cgd int copysize;
271 1.8 cgd #endif
272 1.1 cgd
273 1.59 thorpej #ifdef LOCKDEBUG
274 1.59 thorpej if ((flags & M_NOWAIT) == 0)
275 1.59 thorpej simple_lock_only_held(NULL, "malloc");
276 1.59 thorpej #endif
277 1.62 thorpej #ifdef MALLOC_DEBUG
278 1.79.2.1 skrll if (debug_malloc(size, ksp, flags, (void *) &va))
279 1.62 thorpej return ((void *) va);
280 1.62 thorpej #endif
281 1.1 cgd indx = BUCKETINDX(size);
282 1.1 cgd kbp = &bucket[indx];
283 1.56 thorpej s = splvm();
284 1.78 pk simple_lock(&malloc_slock);
285 1.1 cgd #ifdef KMEMSTATS
286 1.1 cgd while (ksp->ks_memuse >= ksp->ks_limit) {
287 1.1 cgd if (flags & M_NOWAIT) {
288 1.78 pk simple_unlock(&malloc_slock);
289 1.1 cgd splx(s);
290 1.1 cgd return ((void *) NULL);
291 1.1 cgd }
292 1.1 cgd if (ksp->ks_limblocks < 65535)
293 1.1 cgd ksp->ks_limblocks++;
294 1.78 pk ltsleep((caddr_t)ksp, PSWP+2, ksp->ks_shortdesc, 0,
295 1.78 pk &malloc_slock);
296 1.1 cgd }
297 1.8 cgd ksp->ks_size |= 1 << indx;
298 1.8 cgd #endif
299 1.8 cgd #ifdef DIAGNOSTIC
300 1.8 cgd copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
301 1.1 cgd #endif
302 1.1 cgd if (kbp->kb_next == NULL) {
303 1.8 cgd kbp->kb_last = NULL;
304 1.1 cgd if (size > MAXALLOCSAVE)
305 1.66 enami allocsize = round_page(size);
306 1.1 cgd else
307 1.1 cgd allocsize = 1 << indx;
308 1.47 ragge npg = btoc(allocsize);
309 1.78 pk simple_unlock(&malloc_slock);
310 1.79.2.6 skrll va = (caddr_t) uvm_km_alloc(kmem_map,
311 1.79.2.6 skrll (vsize_t)ctob(npg), 0,
312 1.73 chs ((flags & M_NOWAIT) ? UVM_KMF_NOWAIT : 0) |
313 1.79.2.6 skrll ((flags & M_CANFAIL) ? UVM_KMF_CANFAIL : 0) |
314 1.79.2.6 skrll UVM_KMF_WIRED);
315 1.51 thorpej if (__predict_false(va == NULL)) {
316 1.17 cgd /*
317 1.17 cgd * Kmem_malloc() can return NULL, even if it can
318 1.79.2.4 skrll * wait, if there is no map space available, because
319 1.17 cgd * it can't fix that problem. Neither can we,
320 1.17 cgd * right now. (We should release pages which
321 1.17 cgd * are completely free and which are in buckets
322 1.17 cgd * with too many free elements.)
323 1.17 cgd */
324 1.68 jdolecek if ((flags & (M_NOWAIT|M_CANFAIL)) == 0)
325 1.17 cgd panic("malloc: out of space in kmem_map");
326 1.6 cgd splx(s);
327 1.73 chs return (NULL);
328 1.1 cgd }
329 1.78 pk simple_lock(&malloc_slock);
330 1.1 cgd #ifdef KMEMSTATS
331 1.1 cgd kbp->kb_total += kbp->kb_elmpercl;
332 1.1 cgd #endif
333 1.1 cgd kup = btokup(va);
334 1.1 cgd kup->ku_indx = indx;
335 1.1 cgd if (allocsize > MAXALLOCSAVE) {
336 1.1 cgd if (npg > 65535)
337 1.1 cgd panic("malloc: allocation too large");
338 1.1 cgd kup->ku_pagecnt = npg;
339 1.1 cgd #ifdef KMEMSTATS
340 1.1 cgd ksp->ks_memuse += allocsize;
341 1.1 cgd #endif
342 1.1 cgd goto out;
343 1.1 cgd }
344 1.1 cgd #ifdef KMEMSTATS
345 1.1 cgd kup->ku_freecnt = kbp->kb_elmpercl;
346 1.1 cgd kbp->kb_totalfree += kbp->kb_elmpercl;
347 1.1 cgd #endif
348 1.1 cgd /*
349 1.1 cgd * Just in case we blocked while allocating memory,
350 1.1 cgd * and someone else also allocated memory for this
351 1.1 cgd * bucket, don't assume the list is still empty.
352 1.1 cgd */
353 1.1 cgd savedlist = kbp->kb_next;
354 1.49 thorpej kbp->kb_next = cp = va + (npg << PAGE_SHIFT) - allocsize;
355 1.8 cgd for (;;) {
356 1.8 cgd freep = (struct freelist *)cp;
357 1.8 cgd #ifdef DIAGNOSTIC
358 1.8 cgd /*
359 1.8 cgd * Copy in known text to detect modification
360 1.8 cgd * after freeing.
361 1.8 cgd */
362 1.79.2.1 skrll end = (uint32_t *)&cp[copysize];
363 1.79.2.1 skrll for (lp = (uint32_t *)cp; lp < end; lp++)
364 1.8 cgd *lp = WEIRD_ADDR;
365 1.8 cgd freep->type = M_FREE;
366 1.8 cgd #endif /* DIAGNOSTIC */
367 1.8 cgd if (cp <= va)
368 1.8 cgd break;
369 1.8 cgd cp -= allocsize;
370 1.8 cgd freep->next = cp;
371 1.8 cgd }
372 1.8 cgd freep->next = savedlist;
373 1.8 cgd if (kbp->kb_last == NULL)
374 1.8 cgd kbp->kb_last = (caddr_t)freep;
375 1.1 cgd }
376 1.1 cgd va = kbp->kb_next;
377 1.8 cgd kbp->kb_next = ((struct freelist *)va)->next;
378 1.8 cgd #ifdef DIAGNOSTIC
379 1.8 cgd freep = (struct freelist *)va;
380 1.77 thorpej /* XXX potential to get garbage pointer here. */
381 1.29 chs if (kbp->kb_next) {
382 1.29 chs int rv;
383 1.35 eeh vaddr_t addr = (vaddr_t)kbp->kb_next;
384 1.29 chs
385 1.43 thorpej vm_map_lock(kmem_map);
386 1.29 chs rv = uvm_map_checkprot(kmem_map, addr,
387 1.69 enami addr + sizeof(struct freelist), VM_PROT_WRITE);
388 1.43 thorpej vm_map_unlock(kmem_map);
389 1.29 chs
390 1.51 thorpej if (__predict_false(rv == 0)) {
391 1.69 enami printf("Data modified on freelist: "
392 1.69 enami "word %ld of object %p size %ld previous type %s "
393 1.69 enami "(invalid addr %p)\n",
394 1.41 mrg (long)((int32_t *)&kbp->kb_next - (int32_t *)kbp),
395 1.79.2.1 skrll va, size, "foo", kbp->kb_next);
396 1.27 thorpej #ifdef MALLOCLOG
397 1.41 mrg hitmlog(va);
398 1.27 thorpej #endif
399 1.41 mrg kbp->kb_next = NULL;
400 1.29 chs }
401 1.8 cgd }
402 1.11 cgd
403 1.11 cgd /* Fill the fields that we've used with WEIRD_ADDR */
404 1.77 thorpej #ifdef _LP64
405 1.77 thorpej freep->type = (struct malloc_type *)
406 1.77 thorpej (WEIRD_ADDR | (((u_long) WEIRD_ADDR) << 32));
407 1.77 thorpej #else
408 1.77 thorpej freep->type = (struct malloc_type *) WEIRD_ADDR;
409 1.8 cgd #endif
410 1.79.2.1 skrll end = (uint32_t *)&freep->next +
411 1.11 cgd (sizeof(freep->next) / sizeof(int32_t));
412 1.79.2.1 skrll for (lp = (uint32_t *)&freep->next; lp < end; lp++)
413 1.11 cgd *lp = WEIRD_ADDR;
414 1.11 cgd
415 1.11 cgd /* and check that the data hasn't been modified. */
416 1.76 thorpej end = (uint32_t *)&va[copysize];
417 1.79.2.1 skrll for (lp = (uint32_t *)va; lp < end; lp++) {
418 1.51 thorpej if (__predict_true(*lp == WEIRD_ADDR))
419 1.8 cgd continue;
420 1.69 enami printf("Data modified on freelist: "
421 1.69 enami "word %ld of object %p size %ld previous type %s "
422 1.69 enami "(0x%x != 0x%x)\n",
423 1.76 thorpej (long)(lp - (uint32_t *)va), va, size,
424 1.79.2.1 skrll "bar", *lp, WEIRD_ADDR);
425 1.27 thorpej #ifdef MALLOCLOG
426 1.27 thorpej hitmlog(va);
427 1.27 thorpej #endif
428 1.8 cgd break;
429 1.8 cgd }
430 1.11 cgd
431 1.8 cgd freep->spare0 = 0;
432 1.8 cgd #endif /* DIAGNOSTIC */
433 1.1 cgd #ifdef KMEMSTATS
434 1.1 cgd kup = btokup(va);
435 1.1 cgd if (kup->ku_indx != indx)
436 1.1 cgd panic("malloc: wrong bucket");
437 1.1 cgd if (kup->ku_freecnt == 0)
438 1.1 cgd panic("malloc: lost data");
439 1.1 cgd kup->ku_freecnt--;
440 1.1 cgd kbp->kb_totalfree--;
441 1.1 cgd ksp->ks_memuse += 1 << indx;
442 1.1 cgd out:
443 1.1 cgd kbp->kb_calls++;
444 1.1 cgd ksp->ks_inuse++;
445 1.1 cgd ksp->ks_calls++;
446 1.1 cgd if (ksp->ks_memuse > ksp->ks_maxused)
447 1.1 cgd ksp->ks_maxused = ksp->ks_memuse;
448 1.1 cgd #else
449 1.1 cgd out:
450 1.1 cgd #endif
451 1.27 thorpej #ifdef MALLOCLOG
452 1.79.2.1 skrll domlog(va, size, ksp, 1, file, line);
453 1.27 thorpej #endif
454 1.78 pk simple_unlock(&malloc_slock);
455 1.1 cgd splx(s);
456 1.67 enami if ((flags & M_ZERO) != 0)
457 1.65 lukem memset(va, 0, size);
458 1.1 cgd return ((void *) va);
459 1.1 cgd }
460 1.1 cgd
461 1.1 cgd /*
462 1.1 cgd * Free a block of memory allocated by malloc.
463 1.1 cgd */
464 1.27 thorpej #ifdef MALLOCLOG
465 1.27 thorpej void
466 1.79.2.1 skrll _free(void *addr, struct malloc_type *ksp, const char *file, long line)
467 1.27 thorpej #else
468 1.1 cgd void
469 1.77 thorpej free(void *addr, struct malloc_type *ksp)
470 1.27 thorpej #endif /* MALLOCLOG */
471 1.1 cgd {
472 1.50 augustss struct kmembuckets *kbp;
473 1.50 augustss struct kmemusage *kup;
474 1.50 augustss struct freelist *freep;
475 1.8 cgd long size;
476 1.8 cgd int s;
477 1.5 andrew #ifdef DIAGNOSTIC
478 1.8 cgd caddr_t cp;
479 1.11 cgd int32_t *end, *lp;
480 1.11 cgd long alloc, copysize;
481 1.5 andrew #endif
482 1.48 thorpej
483 1.62 thorpej #ifdef MALLOC_DEBUG
484 1.77 thorpej if (debug_free(addr, ksp))
485 1.62 thorpej return;
486 1.62 thorpej #endif
487 1.62 thorpej
488 1.48 thorpej #ifdef DIAGNOSTIC
489 1.48 thorpej /*
490 1.48 thorpej * Ensure that we're free'ing something that we could
491 1.48 thorpej * have allocated in the first place. That is, check
492 1.48 thorpej * to see that the address is within kmem_map.
493 1.48 thorpej */
494 1.79.2.1 skrll if (__predict_false((vaddr_t)addr < vm_map_min(kmem_map) ||
495 1.79.2.1 skrll (vaddr_t)addr >= vm_map_max(kmem_map)))
496 1.48 thorpej panic("free: addr %p not within kmem_map", addr);
497 1.1 cgd #endif
498 1.1 cgd
499 1.1 cgd kup = btokup(addr);
500 1.1 cgd size = 1 << kup->ku_indx;
501 1.8 cgd kbp = &bucket[kup->ku_indx];
502 1.56 thorpej s = splvm();
503 1.78 pk simple_lock(&malloc_slock);
504 1.27 thorpej #ifdef MALLOCLOG
505 1.79.2.1 skrll domlog(addr, 0, ksp, 2, file, line);
506 1.27 thorpej #endif
507 1.1 cgd #ifdef DIAGNOSTIC
508 1.8 cgd /*
509 1.8 cgd * Check for returns of data that do not point to the
510 1.8 cgd * beginning of the allocation.
511 1.8 cgd */
512 1.49 thorpej if (size > PAGE_SIZE)
513 1.49 thorpej alloc = addrmask[BUCKETINDX(PAGE_SIZE)];
514 1.1 cgd else
515 1.1 cgd alloc = addrmask[kup->ku_indx];
516 1.8 cgd if (((u_long)addr & alloc) != 0)
517 1.75 provos panic("free: unaligned addr %p, size %ld, type %s, mask %ld",
518 1.77 thorpej addr, size, ksp->ks_shortdesc, alloc);
519 1.1 cgd #endif /* DIAGNOSTIC */
520 1.1 cgd if (size > MAXALLOCSAVE) {
521 1.79.2.6 skrll uvm_km_free(kmem_map, (vaddr_t)addr, ctob(kup->ku_pagecnt),
522 1.79.2.6 skrll UVM_KMF_WIRED);
523 1.1 cgd #ifdef KMEMSTATS
524 1.1 cgd size = kup->ku_pagecnt << PGSHIFT;
525 1.1 cgd ksp->ks_memuse -= size;
526 1.1 cgd kup->ku_indx = 0;
527 1.1 cgd kup->ku_pagecnt = 0;
528 1.1 cgd if (ksp->ks_memuse + size >= ksp->ks_limit &&
529 1.1 cgd ksp->ks_memuse < ksp->ks_limit)
530 1.1 cgd wakeup((caddr_t)ksp);
531 1.79 fvdl #ifdef DIAGNOSTIC
532 1.79 fvdl if (ksp->ks_inuse == 0)
533 1.79 fvdl panic("free 1: inuse 0, probable double free");
534 1.79 fvdl #endif
535 1.1 cgd ksp->ks_inuse--;
536 1.1 cgd kbp->kb_total -= 1;
537 1.1 cgd #endif
538 1.78 pk simple_unlock(&malloc_slock);
539 1.1 cgd splx(s);
540 1.1 cgd return;
541 1.1 cgd }
542 1.8 cgd freep = (struct freelist *)addr;
543 1.8 cgd #ifdef DIAGNOSTIC
544 1.8 cgd /*
545 1.8 cgd * Check for multiple frees. Use a quick check to see if
546 1.8 cgd * it looks free before laboriously searching the freelist.
547 1.8 cgd */
548 1.51 thorpej if (__predict_false(freep->spare0 == WEIRD_ADDR)) {
549 1.16 cgd for (cp = kbp->kb_next; cp;
550 1.16 cgd cp = ((struct freelist *)cp)->next) {
551 1.8 cgd if (addr != cp)
552 1.8 cgd continue;
553 1.22 christos printf("multiply freed item %p\n", addr);
554 1.27 thorpej #ifdef MALLOCLOG
555 1.27 thorpej hitmlog(addr);
556 1.27 thorpej #endif
557 1.8 cgd panic("free: duplicated free");
558 1.8 cgd }
559 1.8 cgd }
560 1.38 chs #ifdef LOCKDEBUG
561 1.38 chs /*
562 1.38 chs * Check if we're freeing a locked simple lock.
563 1.38 chs */
564 1.40 chs simple_lock_freecheck(addr, (char *)addr + size);
565 1.38 chs #endif
566 1.8 cgd /*
567 1.8 cgd * Copy in known text to detect modification after freeing
568 1.8 cgd * and to make it look free. Also, save the type being freed
569 1.8 cgd * so we can list likely culprit if modification is detected
570 1.8 cgd * when the object is reallocated.
571 1.8 cgd */
572 1.8 cgd copysize = size < MAX_COPY ? size : MAX_COPY;
573 1.11 cgd end = (int32_t *)&((caddr_t)addr)[copysize];
574 1.11 cgd for (lp = (int32_t *)addr; lp < end; lp++)
575 1.8 cgd *lp = WEIRD_ADDR;
576 1.77 thorpej freep->type = ksp;
577 1.8 cgd #endif /* DIAGNOSTIC */
578 1.1 cgd #ifdef KMEMSTATS
579 1.1 cgd kup->ku_freecnt++;
580 1.36 thorpej if (kup->ku_freecnt >= kbp->kb_elmpercl) {
581 1.1 cgd if (kup->ku_freecnt > kbp->kb_elmpercl)
582 1.1 cgd panic("free: multiple frees");
583 1.1 cgd else if (kbp->kb_totalfree > kbp->kb_highwat)
584 1.1 cgd kbp->kb_couldfree++;
585 1.36 thorpej }
586 1.1 cgd kbp->kb_totalfree++;
587 1.1 cgd ksp->ks_memuse -= size;
588 1.1 cgd if (ksp->ks_memuse + size >= ksp->ks_limit &&
589 1.1 cgd ksp->ks_memuse < ksp->ks_limit)
590 1.1 cgd wakeup((caddr_t)ksp);
591 1.79 fvdl #ifdef DIAGNOSTIC
592 1.79 fvdl if (ksp->ks_inuse == 0)
593 1.79 fvdl panic("free 2: inuse 0, probable double free");
594 1.79 fvdl #endif
595 1.1 cgd ksp->ks_inuse--;
596 1.1 cgd #endif
597 1.8 cgd if (kbp->kb_next == NULL)
598 1.8 cgd kbp->kb_next = addr;
599 1.8 cgd else
600 1.8 cgd ((struct freelist *)kbp->kb_last)->next = addr;
601 1.8 cgd freep->next = NULL;
602 1.8 cgd kbp->kb_last = addr;
603 1.78 pk simple_unlock(&malloc_slock);
604 1.1 cgd splx(s);
605 1.20 cgd }
606 1.20 cgd
607 1.20 cgd /*
608 1.20 cgd * Change the size of a block of memory.
609 1.20 cgd */
610 1.20 cgd void *
611 1.77 thorpej realloc(void *curaddr, unsigned long newsize, struct malloc_type *ksp,
612 1.77 thorpej int flags)
613 1.20 cgd {
614 1.50 augustss struct kmemusage *kup;
615 1.72 thorpej unsigned long cursize;
616 1.20 cgd void *newaddr;
617 1.20 cgd #ifdef DIAGNOSTIC
618 1.20 cgd long alloc;
619 1.20 cgd #endif
620 1.20 cgd
621 1.20 cgd /*
622 1.69 enami * realloc() with a NULL pointer is the same as malloc().
623 1.20 cgd */
624 1.20 cgd if (curaddr == NULL)
625 1.77 thorpej return (malloc(newsize, ksp, flags));
626 1.20 cgd
627 1.20 cgd /*
628 1.69 enami * realloc() with zero size is the same as free().
629 1.20 cgd */
630 1.20 cgd if (newsize == 0) {
631 1.77 thorpej free(curaddr, ksp);
632 1.20 cgd return (NULL);
633 1.20 cgd }
634 1.59 thorpej
635 1.59 thorpej #ifdef LOCKDEBUG
636 1.59 thorpej if ((flags & M_NOWAIT) == 0)
637 1.59 thorpej simple_lock_only_held(NULL, "realloc");
638 1.59 thorpej #endif
639 1.20 cgd
640 1.20 cgd /*
641 1.20 cgd * Find out how large the old allocation was (and do some
642 1.20 cgd * sanity checking).
643 1.20 cgd */
644 1.20 cgd kup = btokup(curaddr);
645 1.20 cgd cursize = 1 << kup->ku_indx;
646 1.20 cgd
647 1.20 cgd #ifdef DIAGNOSTIC
648 1.20 cgd /*
649 1.20 cgd * Check for returns of data that do not point to the
650 1.20 cgd * beginning of the allocation.
651 1.20 cgd */
652 1.49 thorpej if (cursize > PAGE_SIZE)
653 1.49 thorpej alloc = addrmask[BUCKETINDX(PAGE_SIZE)];
654 1.20 cgd else
655 1.20 cgd alloc = addrmask[kup->ku_indx];
656 1.20 cgd if (((u_long)curaddr & alloc) != 0)
657 1.69 enami panic("realloc: "
658 1.69 enami "unaligned addr %p, size %ld, type %s, mask %ld\n",
659 1.77 thorpej curaddr, cursize, ksp->ks_shortdesc, alloc);
660 1.20 cgd #endif /* DIAGNOSTIC */
661 1.20 cgd
662 1.20 cgd if (cursize > MAXALLOCSAVE)
663 1.20 cgd cursize = ctob(kup->ku_pagecnt);
664 1.20 cgd
665 1.20 cgd /*
666 1.20 cgd * If we already actually have as much as they want, we're done.
667 1.20 cgd */
668 1.20 cgd if (newsize <= cursize)
669 1.20 cgd return (curaddr);
670 1.20 cgd
671 1.20 cgd /*
672 1.20 cgd * Can't satisfy the allocation with the existing block.
673 1.20 cgd * Allocate a new one and copy the data.
674 1.20 cgd */
675 1.77 thorpej newaddr = malloc(newsize, ksp, flags);
676 1.51 thorpej if (__predict_false(newaddr == NULL)) {
677 1.20 cgd /*
678 1.69 enami * malloc() failed, because flags included M_NOWAIT.
679 1.20 cgd * Return NULL to indicate that failure. The old
680 1.20 cgd * pointer is still valid.
681 1.20 cgd */
682 1.69 enami return (NULL);
683 1.20 cgd }
684 1.34 perry memcpy(newaddr, curaddr, cursize);
685 1.20 cgd
686 1.20 cgd /*
687 1.20 cgd * We were successful: free the old allocation and return
688 1.20 cgd * the new one.
689 1.20 cgd */
690 1.77 thorpej free(curaddr, ksp);
691 1.20 cgd return (newaddr);
692 1.70 enami }
693 1.70 enami
694 1.70 enami /*
695 1.70 enami * Roundup size to the actual allocation size.
696 1.70 enami */
697 1.70 enami unsigned long
698 1.70 enami malloc_roundup(unsigned long size)
699 1.70 enami {
700 1.70 enami
701 1.70 enami if (size > MAXALLOCSAVE)
702 1.70 enami return (roundup(size, PAGE_SIZE));
703 1.70 enami else
704 1.70 enami return (1 << BUCKETINDX(size));
705 1.1 cgd }
706 1.1 cgd
707 1.1 cgd /*
708 1.77 thorpej * Add a malloc type to the system.
709 1.77 thorpej */
710 1.77 thorpej void
711 1.77 thorpej malloc_type_attach(struct malloc_type *type)
712 1.77 thorpej {
713 1.77 thorpej
714 1.77 thorpej if (nkmempages == 0)
715 1.77 thorpej panic("malloc_type_attach: nkmempages == 0");
716 1.77 thorpej
717 1.77 thorpej if (type->ks_magic != M_MAGIC)
718 1.77 thorpej panic("malloc_type_attach: bad magic");
719 1.77 thorpej
720 1.77 thorpej #ifdef DIAGNOSTIC
721 1.77 thorpej {
722 1.77 thorpej struct malloc_type *ksp;
723 1.77 thorpej for (ksp = kmemstatistics; ksp != NULL; ksp = ksp->ks_next) {
724 1.77 thorpej if (ksp == type)
725 1.77 thorpej panic("malloc_type_attach: already on list");
726 1.77 thorpej }
727 1.77 thorpej }
728 1.77 thorpej #endif
729 1.77 thorpej
730 1.77 thorpej #ifdef KMEMSTATS
731 1.77 thorpej if (type->ks_limit == 0)
732 1.77 thorpej type->ks_limit = ((u_long)nkmempages << PAGE_SHIFT) * 6U / 10U;
733 1.77 thorpej #else
734 1.77 thorpej type->ks_limit = 0;
735 1.77 thorpej #endif
736 1.77 thorpej
737 1.77 thorpej type->ks_next = kmemstatistics;
738 1.77 thorpej kmemstatistics = type;
739 1.77 thorpej }
740 1.77 thorpej
741 1.77 thorpej /*
742 1.77 thorpej * Remove a malloc type from the system..
743 1.77 thorpej */
744 1.77 thorpej void
745 1.77 thorpej malloc_type_detach(struct malloc_type *type)
746 1.77 thorpej {
747 1.77 thorpej struct malloc_type *ksp;
748 1.77 thorpej
749 1.77 thorpej #ifdef DIAGNOSTIC
750 1.77 thorpej if (type->ks_magic != M_MAGIC)
751 1.77 thorpej panic("malloc_type_detach: bad magic");
752 1.77 thorpej #endif
753 1.77 thorpej
754 1.77 thorpej if (type == kmemstatistics)
755 1.77 thorpej kmemstatistics = type->ks_next;
756 1.77 thorpej else {
757 1.77 thorpej for (ksp = kmemstatistics; ksp->ks_next != NULL;
758 1.77 thorpej ksp = ksp->ks_next) {
759 1.77 thorpej if (ksp->ks_next == type) {
760 1.77 thorpej ksp->ks_next = type->ks_next;
761 1.77 thorpej break;
762 1.77 thorpej }
763 1.77 thorpej }
764 1.77 thorpej #ifdef DIAGNOSTIC
765 1.77 thorpej if (ksp->ks_next == NULL)
766 1.77 thorpej panic("malloc_type_detach: not on list");
767 1.77 thorpej #endif
768 1.77 thorpej }
769 1.77 thorpej type->ks_next = NULL;
770 1.77 thorpej }
771 1.77 thorpej
772 1.77 thorpej /*
773 1.77 thorpej * Set the limit on a malloc type.
774 1.77 thorpej */
775 1.77 thorpej void
776 1.77 thorpej malloc_type_setlimit(struct malloc_type *type, u_long limit)
777 1.77 thorpej {
778 1.77 thorpej #ifdef KMEMSTATS
779 1.77 thorpej int s;
780 1.77 thorpej
781 1.77 thorpej s = splvm();
782 1.77 thorpej type->ks_limit = limit;
783 1.77 thorpej splx(s);
784 1.77 thorpej #endif
785 1.77 thorpej }
786 1.77 thorpej
787 1.77 thorpej /*
788 1.49 thorpej * Compute the number of pages that kmem_map will map, that is,
789 1.49 thorpej * the size of the kernel malloc arena.
790 1.49 thorpej */
791 1.49 thorpej void
792 1.69 enami kmeminit_nkmempages(void)
793 1.49 thorpej {
794 1.49 thorpej int npages;
795 1.49 thorpej
796 1.49 thorpej if (nkmempages != 0) {
797 1.49 thorpej /*
798 1.49 thorpej * It's already been set (by us being here before, or
799 1.49 thorpej * by patching or kernel config options), bail out now.
800 1.49 thorpej */
801 1.49 thorpej return;
802 1.49 thorpej }
803 1.49 thorpej
804 1.79.2.4 skrll npages = physmem;
805 1.49 thorpej
806 1.49 thorpej if (npages > NKMEMPAGES_MAX)
807 1.49 thorpej npages = NKMEMPAGES_MAX;
808 1.49 thorpej
809 1.49 thorpej if (npages < NKMEMPAGES_MIN)
810 1.49 thorpej npages = NKMEMPAGES_MIN;
811 1.49 thorpej
812 1.49 thorpej nkmempages = npages;
813 1.49 thorpej }
814 1.49 thorpej
815 1.49 thorpej /*
816 1.1 cgd * Initialize the kernel memory allocator
817 1.1 cgd */
818 1.12 christos void
819 1.69 enami kmeminit(void)
820 1.1 cgd {
821 1.77 thorpej __link_set_decl(malloc_types, struct malloc_type);
822 1.77 thorpej struct malloc_type * const *ksp;
823 1.79.2.1 skrll vaddr_t kmb, kml;
824 1.23 tls #ifdef KMEMSTATS
825 1.50 augustss long indx;
826 1.23 tls #endif
827 1.1 cgd
828 1.1 cgd #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
829 1.1 cgd ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2
830 1.1 cgd #endif
831 1.1 cgd #if (MAXALLOCSAVE > MINALLOCSIZE * 32768)
832 1.1 cgd ERROR!_kmeminit:_MAXALLOCSAVE_too_big
833 1.1 cgd #endif
834 1.47 ragge #if (MAXALLOCSAVE < NBPG)
835 1.1 cgd ERROR!_kmeminit:_MAXALLOCSAVE_too_small
836 1.1 cgd #endif
837 1.11 cgd
838 1.11 cgd if (sizeof(struct freelist) > (1 << MINBUCKET))
839 1.11 cgd panic("minbucket too small/struct freelist too big");
840 1.11 cgd
841 1.49 thorpej /*
842 1.49 thorpej * Compute the number of kmem_map pages, if we have not
843 1.49 thorpej * done so already.
844 1.49 thorpej */
845 1.49 thorpej kmeminit_nkmempages();
846 1.49 thorpej
847 1.79.2.6 skrll kmemusage = (struct kmemusage *) uvm_km_alloc(kernel_map,
848 1.79.2.6 skrll (vsize_t)(nkmempages * sizeof(struct kmemusage)), 0,
849 1.79.2.6 skrll UVM_KMF_WIRED|UVM_KMF_ZERO);
850 1.79.2.1 skrll kmb = 0;
851 1.79.2.1 skrll kmem_map = uvm_km_suballoc(kernel_map, &kmb,
852 1.79.2.5 skrll &kml, ((vsize_t)nkmempages << PAGE_SHIFT),
853 1.69 enami VM_MAP_INTRSAFE, FALSE, &kmem_map_store);
854 1.79.2.4 skrll uvm_km_vacache_init(kmem_map, "kvakmem", 0);
855 1.79.2.1 skrll kmembase = (char *)kmb;
856 1.79.2.1 skrll kmemlimit = (char *)kml;
857 1.1 cgd #ifdef KMEMSTATS
858 1.1 cgd for (indx = 0; indx < MINBUCKET + 16; indx++) {
859 1.49 thorpej if (1 << indx >= PAGE_SIZE)
860 1.1 cgd bucket[indx].kb_elmpercl = 1;
861 1.1 cgd else
862 1.49 thorpej bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
863 1.1 cgd bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
864 1.1 cgd }
865 1.62 thorpej #endif
866 1.77 thorpej
867 1.77 thorpej /* Attach all of the statically-linked malloc types. */
868 1.77 thorpej __link_set_foreach(ksp, malloc_types)
869 1.77 thorpej malloc_type_attach(*ksp);
870 1.77 thorpej
871 1.62 thorpej #ifdef MALLOC_DEBUG
872 1.62 thorpej debug_malloc_init();
873 1.1 cgd #endif
874 1.1 cgd }
875 1.39 thorpej
876 1.39 thorpej #ifdef DDB
877 1.39 thorpej #include <ddb/db_output.h>
878 1.39 thorpej
879 1.39 thorpej /*
880 1.39 thorpej * Dump kmem statistics from ddb.
881 1.39 thorpej *
882 1.39 thorpej * usage: call dump_kmemstats
883 1.39 thorpej */
884 1.69 enami void dump_kmemstats(void);
885 1.39 thorpej
886 1.39 thorpej void
887 1.69 enami dump_kmemstats(void)
888 1.39 thorpej {
889 1.39 thorpej #ifdef KMEMSTATS
890 1.77 thorpej struct malloc_type *ksp;
891 1.39 thorpej
892 1.77 thorpej for (ksp = kmemstatistics; ksp != NULL; ksp = ksp->ks_next) {
893 1.77 thorpej if (ksp->ks_memuse == 0)
894 1.77 thorpej continue;
895 1.77 thorpej db_printf("%s%.*s %ld\n", ksp->ks_shortdesc,
896 1.77 thorpej (int)(20 - strlen(ksp->ks_shortdesc)),
897 1.77 thorpej " ",
898 1.77 thorpej ksp->ks_memuse);
899 1.39 thorpej }
900 1.39 thorpej #else
901 1.39 thorpej db_printf("Kmem stats are not being collected.\n");
902 1.39 thorpej #endif /* KMEMSTATS */
903 1.39 thorpej }
904 1.39 thorpej #endif /* DDB */
905 1.79.2.1 skrll
906 1.79.2.1 skrll
907 1.79.2.1 skrll #if 0
908 1.79.2.5 skrll /*
909 1.79.2.1 skrll * Diagnostic messages about "Data modified on
910 1.79.2.1 skrll * freelist" indicate a memory corruption, but
911 1.79.2.1 skrll * they do not help tracking it down.
912 1.79.2.5 skrll * This function can be called at various places
913 1.79.2.1 skrll * to sanity check malloc's freelist and discover
914 1.79.2.1 skrll * where does the corruption take place.
915 1.79.2.1 skrll */
916 1.79.2.1 skrll int
917 1.79.2.1 skrll freelist_sanitycheck(void) {
918 1.79.2.1 skrll int i,j;
919 1.79.2.1 skrll struct kmembuckets *kbp;
920 1.79.2.1 skrll struct freelist *freep;
921 1.79.2.1 skrll int rv = 0;
922 1.79.2.5 skrll
923 1.79.2.1 skrll for (i = MINBUCKET; i <= MINBUCKET + 15; i++) {
924 1.79.2.5 skrll kbp = &bucket[i];
925 1.79.2.1 skrll freep = (struct freelist *)kbp->kb_next;
926 1.79.2.1 skrll j = 0;
927 1.79.2.1 skrll while(freep) {
928 1.79.2.1 skrll vm_map_lock(kmem_map);
929 1.79.2.1 skrll rv = uvm_map_checkprot(kmem_map, (vaddr_t)freep,
930 1.79.2.5 skrll (vaddr_t)freep + sizeof(struct freelist),
931 1.79.2.1 skrll VM_PROT_WRITE);
932 1.79.2.1 skrll vm_map_unlock(kmem_map);
933 1.79.2.1 skrll
934 1.79.2.1 skrll if ((rv == 0) || (*(int *)freep != WEIRD_ADDR)) {
935 1.79.2.1 skrll printf("bucket %i, chunck %d at %p modified\n",
936 1.79.2.1 skrll i, j, freep);
937 1.79.2.1 skrll return 1;
938 1.79.2.1 skrll }
939 1.79.2.1 skrll freep = (struct freelist *)freep->next;
940 1.79.2.1 skrll j++;
941 1.79.2.1 skrll }
942 1.79.2.1 skrll }
943 1.79.2.1 skrll
944 1.79.2.1 skrll return 0;
945 1.79.2.1 skrll }
946 1.79.2.1 skrll #endif
947