xref: /freebsd/sys/kern/kern_malloc.c (revision e20a199fd56de5996c0a3f101b0569c0722816b0)
19454b2d8SWarner Losh /*-
2df8bae1dSRodney W. Grimes  * Copyright (c) 1987, 1991, 1993
363a7e0a3SRobert Watson  *	The Regents of the University of California.
424076d13SRobert Watson  * Copyright (c) 2005-2006 Robert N. M. Watson
563a7e0a3SRobert Watson  * All rights reserved.
6df8bae1dSRodney W. Grimes  *
7df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
8df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
9df8bae1dSRodney W. Grimes  * are met:
10df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
12df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
13df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
14df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
16df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
17df8bae1dSRodney W. Grimes  *    without specific prior written permission.
18df8bae1dSRodney W. Grimes  *
19df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
30df8bae1dSRodney W. Grimes  *
31df8bae1dSRodney W. Grimes  *	@(#)kern_malloc.c	8.3 (Berkeley) 1/4/94
32df8bae1dSRodney W. Grimes  */
33df8bae1dSRodney W. Grimes 
340ce3f16dSRobert Watson /*
350ce3f16dSRobert Watson  * Kernel malloc(9) implementation -- general purpose kernel memory allocator
360ce3f16dSRobert Watson  * based on memory types.  Back end is implemented using the UMA(9) zone
370ce3f16dSRobert Watson  * allocator.  A set of fixed-size buckets are used for smaller allocations,
380ce3f16dSRobert Watson  * and a special UMA allocation interface is used for larger allocations.
390ce3f16dSRobert Watson  * Callers declare memory types, and statistics are maintained independently
400ce3f16dSRobert Watson  * for each memory type.  Statistics are maintained per-CPU for performance
410ce3f16dSRobert Watson  * reasons.  See malloc(9) and comments in malloc.h for a detailed
420ce3f16dSRobert Watson  * description.
430ce3f16dSRobert Watson  */
440ce3f16dSRobert Watson 
45677b542eSDavid E. O'Brien #include <sys/cdefs.h>
46677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
47677b542eSDavid E. O'Brien 
48909ed16cSRobert Watson #include "opt_ddb.h"
4991dd776cSJohn Birrell #include "opt_kdtrace.h"
508a58a9f6SJohn Dyson #include "opt_vm.h"
518a58a9f6SJohn Dyson 
52df8bae1dSRodney W. Grimes #include <sys/param.h>
5326f9a767SRodney W. Grimes #include <sys/systm.h>
542d50560aSMarcel Moolenaar #include <sys/kdb.h>
55df8bae1dSRodney W. Grimes #include <sys/kernel.h>
56fb919e4dSMark Murray #include <sys/lock.h>
57df8bae1dSRodney W. Grimes #include <sys/malloc.h>
5854e7152cSDavid Greenman #include <sys/mbuf.h>
59eec258d2SJohn Baldwin #include <sys/mutex.h>
60efeaf95aSDavid Greenman #include <sys/vmmeter.h>
61a448b62aSJake Burkholder #include <sys/proc.h>
6263a7e0a3SRobert Watson #include <sys/sbuf.h>
636f267175SJeff Roberson #include <sys/sysctl.h>
641fb14a47SPoul-Henning Kamp #include <sys/time.h>
659a02e8c6SJason Evans 
66df8bae1dSRodney W. Grimes #include <vm/vm.h>
6799571dc3SJeff Roberson #include <vm/pmap.h>
68efeaf95aSDavid Greenman #include <vm/vm_param.h>
69df8bae1dSRodney W. Grimes #include <vm/vm_kern.h>
70efeaf95aSDavid Greenman #include <vm/vm_extern.h>
713075778bSJohn Dyson #include <vm/vm_map.h>
7299571dc3SJeff Roberson #include <vm/vm_page.h>
738355f576SJeff Roberson #include <vm/uma.h>
748355f576SJeff Roberson #include <vm/uma_int.h>
758efc4effSJeff Roberson #include <vm/uma_dbg.h>
76df8bae1dSRodney W. Grimes 
77e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
78e4eb384bSBosko Milekic #include <vm/memguard.h>
79e4eb384bSBosko Milekic #endif
80847a2a17SPawel Jakub Dawidek #ifdef DEBUG_REDZONE
81847a2a17SPawel Jakub Dawidek #include <vm/redzone.h>
82847a2a17SPawel Jakub Dawidek #endif
83e4eb384bSBosko Milekic 
84984982d6SPoul-Henning Kamp #if defined(INVARIANTS) && defined(__i386__)
85984982d6SPoul-Henning Kamp #include <machine/cpu.h>
86984982d6SPoul-Henning Kamp #endif
87984982d6SPoul-Henning Kamp 
88909ed16cSRobert Watson #include <ddb/ddb.h>
89909ed16cSRobert Watson 
9091dd776cSJohn Birrell #ifdef KDTRACE_HOOKS
9191dd776cSJohn Birrell #include <sys/dtrace_bsd.h>
9291dd776cSJohn Birrell 
9391dd776cSJohn Birrell dtrace_malloc_probe_func_t	dtrace_malloc_probe;
9491dd776cSJohn Birrell #endif
9591dd776cSJohn Birrell 
9644a8ff31SArchie Cobbs /*
9744a8ff31SArchie Cobbs  * When realloc() is called, if the new size is sufficiently smaller than
9844a8ff31SArchie Cobbs  * the old size, realloc() will allocate a new, smaller block to avoid
9944a8ff31SArchie Cobbs  * wasting memory. 'Sufficiently smaller' is defined as: newsize <=
10044a8ff31SArchie Cobbs  * oldsize / 2^n, where REALLOC_FRACTION defines the value of 'n'.
10144a8ff31SArchie Cobbs  */
10244a8ff31SArchie Cobbs #ifndef REALLOC_FRACTION
10344a8ff31SArchie Cobbs #define	REALLOC_FRACTION	1	/* new block if <= half the size */
10444a8ff31SArchie Cobbs #endif
10544a8ff31SArchie Cobbs 
1060ce3f16dSRobert Watson /*
1070ce3f16dSRobert Watson  * Centrally define some common malloc types.
1080ce3f16dSRobert Watson  */
1093b6fb885SPoul-Henning Kamp MALLOC_DEFINE(M_CACHE, "cache", "Various Dynamically allocated caches");
1109ef246c6SBruce Evans MALLOC_DEFINE(M_DEVBUF, "devbuf", "device driver memory");
1119ef246c6SBruce Evans MALLOC_DEFINE(M_TEMP, "temp", "misc temporary data buffers");
1129ef246c6SBruce Evans 
11382cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6OPT, "ip6opt", "IPv6 options");
11482cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6NDP, "ip6ndp", "IPv6 Neighbor Discovery");
11582cd038dSYoshinobu Inoue 
1164d77a549SAlfred Perlstein static void kmeminit(void *);
117237fdd78SRobert Watson SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL);
1182b14f991SJulian Elischer 
119a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FREE, "free", "should be on free list");
120a1c995b6SPoul-Henning Kamp 
121db669378SPeter Wemm static struct malloc_type *kmemstatistics;
122dc2e1e3fSRobert Watson static vm_offset_t kmembase;
123dc2e1e3fSRobert Watson static vm_offset_t kmemlimit;
124cd814b26SRobert Watson static int kmemcount;
1251f6889a1SMatthew Dillon 
1268355f576SJeff Roberson #define KMEM_ZSHIFT	4
1278355f576SJeff Roberson #define KMEM_ZBASE	16
1288355f576SJeff Roberson #define KMEM_ZMASK	(KMEM_ZBASE - 1)
1298355f576SJeff Roberson 
1309fb535deSJeff Roberson #define KMEM_ZMAX	PAGE_SIZE
1318355f576SJeff Roberson #define KMEM_ZSIZE	(KMEM_ZMAX >> KMEM_ZSHIFT)
1326f267175SJeff Roberson static u_int8_t kmemsize[KMEM_ZSIZE + 1];
1336f267175SJeff Roberson 
1340ce3f16dSRobert Watson /*
1350ce3f16dSRobert Watson  * Small malloc(9) memory allocations are allocated from a set of UMA buckets
1360ce3f16dSRobert Watson  * of various sizes.
1370ce3f16dSRobert Watson  *
1380ce3f16dSRobert Watson  * XXX: The comment here used to read "These won't be powers of two for
1390ce3f16dSRobert Watson  * long."  It's possible that a significant amount of wasted memory could be
1400ce3f16dSRobert Watson  * recovered by tuning the sizes of these buckets.
1410ce3f16dSRobert Watson  */
1428355f576SJeff Roberson struct {
1436f267175SJeff Roberson 	int kz_size;
1446f267175SJeff Roberson 	char *kz_name;
1456f267175SJeff Roberson 	uma_zone_t kz_zone;
1466f267175SJeff Roberson } kmemzones[] = {
1476f267175SJeff Roberson 	{16, "16", NULL},
1486f267175SJeff Roberson 	{32, "32", NULL},
1496f267175SJeff Roberson 	{64, "64", NULL},
1506f267175SJeff Roberson 	{128, "128", NULL},
1516f267175SJeff Roberson 	{256, "256", NULL},
1526f267175SJeff Roberson 	{512, "512", NULL},
1536f267175SJeff Roberson 	{1024, "1024", NULL},
1546f267175SJeff Roberson 	{2048, "2048", NULL},
1556f267175SJeff Roberson 	{4096, "4096", NULL},
1569fb535deSJeff Roberson #if PAGE_SIZE > 4096
1576f267175SJeff Roberson 	{8192, "8192", NULL},
1589fb535deSJeff Roberson #if PAGE_SIZE > 8192
15943a7c4e9SRobert Watson 	{16384, "16384", NULL},
1609fb535deSJeff Roberson #if PAGE_SIZE > 16384
161bd796eb2SRobert Watson 	{32768, "32768", NULL},
1629fb535deSJeff Roberson #if PAGE_SIZE > 32768
163bd796eb2SRobert Watson 	{65536, "65536", NULL},
1649fb535deSJeff Roberson #if PAGE_SIZE > 65536
1659fb535deSJeff Roberson #error	"Unsupported PAGE_SIZE"
1669fb535deSJeff Roberson #endif	/* 65536 */
1679fb535deSJeff Roberson #endif	/* 32768 */
1689fb535deSJeff Roberson #endif	/* 16384 */
1699fb535deSJeff Roberson #endif	/* 8192 */
1709fb535deSJeff Roberson #endif	/* 4096 */
1718355f576SJeff Roberson 	{0, NULL},
1728355f576SJeff Roberson };
1738355f576SJeff Roberson 
1740ce3f16dSRobert Watson /*
1750ce3f16dSRobert Watson  * Zone to allocate malloc type descriptions from.  For ABI reasons, memory
1760ce3f16dSRobert Watson  * types are described by a data structure passed by the declaring code, but
1770ce3f16dSRobert Watson  * the malloc(9) implementation has its own data structure describing the
1780ce3f16dSRobert Watson  * type and statistics.  This permits the malloc(9)-internal data structures
1790ce3f16dSRobert Watson  * to be modified without breaking binary-compiled kernel modules that
1800ce3f16dSRobert Watson  * declare malloc types.
1810ce3f16dSRobert Watson  */
18263a7e0a3SRobert Watson static uma_zone_t mt_zone;
18363a7e0a3SRobert Watson 
184b89eaf4eSAlan Cox u_long vm_kmem_size;
185b89eaf4eSAlan Cox SYSCTL_ULONG(_vm, OID_AUTO, kmem_size, CTLFLAG_RD, &vm_kmem_size, 0,
18684344f9fSDag-Erling Smørgrav     "Size of kernel memory");
1875a34a9f0SJeff Roberson 
188b89eaf4eSAlan Cox static u_long vm_kmem_size_min;
189b89eaf4eSAlan Cox SYSCTL_ULONG(_vm, OID_AUTO, kmem_size_min, CTLFLAG_RD, &vm_kmem_size_min, 0,
1900e5179e4SStephane E. Potvin     "Minimum size of kernel memory");
1910e5179e4SStephane E. Potvin 
192b89eaf4eSAlan Cox static u_long vm_kmem_size_max;
193b89eaf4eSAlan Cox SYSCTL_ULONG(_vm, OID_AUTO, kmem_size_max, CTLFLAG_RD, &vm_kmem_size_max, 0,
194479439b4SDag-Erling Smørgrav     "Maximum size of kernel memory");
195479439b4SDag-Erling Smørgrav 
196b89eaf4eSAlan Cox static u_int vm_kmem_size_scale;
197479439b4SDag-Erling Smørgrav SYSCTL_UINT(_vm, OID_AUTO, kmem_size_scale, CTLFLAG_RD, &vm_kmem_size_scale, 0,
198479439b4SDag-Erling Smørgrav     "Scale factor for kernel memory size");
199479439b4SDag-Erling Smørgrav 
2005a34a9f0SJeff Roberson /*
20199571dc3SJeff Roberson  * The malloc_mtx protects the kmemstatistics linked list.
2025a34a9f0SJeff Roberson  */
2035a34a9f0SJeff Roberson struct mtx malloc_mtx;
20469ef67f9SJason Evans 
2055e914b96SJeff Roberson #ifdef MALLOC_PROFILE
2065e914b96SJeff Roberson uint64_t krequests[KMEM_ZSIZE + 1];
2076f267175SJeff Roberson 
2085e914b96SJeff Roberson static int sysctl_kern_mprof(SYSCTL_HANDLER_ARGS);
2095e914b96SJeff Roberson #endif
2105e914b96SJeff Roberson 
211cd814b26SRobert Watson static int sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS);
212df8bae1dSRodney W. Grimes 
2130ce3f16dSRobert Watson /*
2140ce3f16dSRobert Watson  * time_uptime of the last malloc(9) failure (induced or real).
2150ce3f16dSRobert Watson  */
2161fb14a47SPoul-Henning Kamp static time_t t_malloc_fail;
2171fb14a47SPoul-Henning Kamp 
218eae870cdSRobert Watson /*
2190ce3f16dSRobert Watson  * malloc(9) fault injection -- cause malloc failures every (n) mallocs when
2200ce3f16dSRobert Watson  * the caller specifies M_NOWAIT.  If set to 0, no failures are caused.
221eae870cdSRobert Watson  */
2220ce3f16dSRobert Watson #ifdef MALLOC_MAKE_FAILURES
223eae870cdSRobert Watson SYSCTL_NODE(_debug, OID_AUTO, malloc, CTLFLAG_RD, 0,
224eae870cdSRobert Watson     "Kernel malloc debugging options");
225eae870cdSRobert Watson 
226eae870cdSRobert Watson static int malloc_failure_rate;
227eae870cdSRobert Watson static int malloc_nowait_count;
228eae870cdSRobert Watson static int malloc_failure_count;
229eae870cdSRobert Watson SYSCTL_INT(_debug_malloc, OID_AUTO, failure_rate, CTLFLAG_RW,
230eae870cdSRobert Watson     &malloc_failure_rate, 0, "Every (n) mallocs with M_NOWAIT will fail");
231f2538508SRobert Watson TUNABLE_INT("debug.malloc.failure_rate", &malloc_failure_rate);
232eae870cdSRobert Watson SYSCTL_INT(_debug_malloc, OID_AUTO, failure_count, CTLFLAG_RD,
233eae870cdSRobert Watson     &malloc_failure_count, 0, "Number of imposed M_NOWAIT malloc failures");
234eae870cdSRobert Watson #endif
235eae870cdSRobert Watson 
2361fb14a47SPoul-Henning Kamp int
2371fb14a47SPoul-Henning Kamp malloc_last_fail(void)
2381fb14a47SPoul-Henning Kamp {
2391fb14a47SPoul-Henning Kamp 
2401fb14a47SPoul-Henning Kamp 	return (time_uptime - t_malloc_fail);
2411fb14a47SPoul-Henning Kamp }
2421fb14a47SPoul-Henning Kamp 
243df8bae1dSRodney W. Grimes /*
2440ce3f16dSRobert Watson  * An allocation has succeeded -- update malloc type statistics for the
2450ce3f16dSRobert Watson  * amount of bucket size.  Occurs within a critical section so that the
2460ce3f16dSRobert Watson  * thread isn't preempted and doesn't migrate while updating per-PCU
2470ce3f16dSRobert Watson  * statistics.
2484362fadaSBrian Feldman  */
2494362fadaSBrian Feldman static void
25063a7e0a3SRobert Watson malloc_type_zone_allocated(struct malloc_type *mtp, unsigned long size,
2514362fadaSBrian Feldman     int zindx)
2524362fadaSBrian Feldman {
25363a7e0a3SRobert Watson 	struct malloc_type_internal *mtip;
25463a7e0a3SRobert Watson 	struct malloc_type_stats *mtsp;
25563a7e0a3SRobert Watson 
25663a7e0a3SRobert Watson 	critical_enter();
25763a7e0a3SRobert Watson 	mtip = mtp->ks_handle;
25863a7e0a3SRobert Watson 	mtsp = &mtip->mti_stats[curcpu];
25973864adbSPawel Jakub Dawidek 	if (size > 0) {
26063a7e0a3SRobert Watson 		mtsp->mts_memalloced += size;
26163a7e0a3SRobert Watson 		mtsp->mts_numallocs++;
26273864adbSPawel Jakub Dawidek 	}
2634362fadaSBrian Feldman 	if (zindx != -1)
26463a7e0a3SRobert Watson 		mtsp->mts_size |= 1 << zindx;
26591dd776cSJohn Birrell 
26691dd776cSJohn Birrell #ifdef KDTRACE_HOOKS
26791dd776cSJohn Birrell 	if (dtrace_malloc_probe != NULL) {
26891dd776cSJohn Birrell 		uint32_t probe_id = mtip->mti_probes[DTMALLOC_PROBE_MALLOC];
26991dd776cSJohn Birrell 		if (probe_id != 0)
27091dd776cSJohn Birrell 			(dtrace_malloc_probe)(probe_id,
27191dd776cSJohn Birrell 			    (uintptr_t) mtp, (uintptr_t) mtip,
27291dd776cSJohn Birrell 			    (uintptr_t) mtsp, size, zindx);
27391dd776cSJohn Birrell 	}
27491dd776cSJohn Birrell #endif
27591dd776cSJohn Birrell 
27663a7e0a3SRobert Watson 	critical_exit();
2774362fadaSBrian Feldman }
2784362fadaSBrian Feldman 
2794362fadaSBrian Feldman void
28063a7e0a3SRobert Watson malloc_type_allocated(struct malloc_type *mtp, unsigned long size)
2814362fadaSBrian Feldman {
28263a7e0a3SRobert Watson 
28373864adbSPawel Jakub Dawidek 	if (size > 0)
28463a7e0a3SRobert Watson 		malloc_type_zone_allocated(mtp, size, -1);
2854362fadaSBrian Feldman }
2864362fadaSBrian Feldman 
2874362fadaSBrian Feldman /*
2883805385eSRobert Watson  * A free operation has occurred -- update malloc type statistics for the
2890ce3f16dSRobert Watson  * amount of the bucket size.  Occurs within a critical section so that the
2900ce3f16dSRobert Watson  * thread isn't preempted and doesn't migrate while updating per-CPU
2910ce3f16dSRobert Watson  * statistics.
2924362fadaSBrian Feldman  */
2934362fadaSBrian Feldman void
29463a7e0a3SRobert Watson malloc_type_freed(struct malloc_type *mtp, unsigned long size)
2954362fadaSBrian Feldman {
29663a7e0a3SRobert Watson 	struct malloc_type_internal *mtip;
29763a7e0a3SRobert Watson 	struct malloc_type_stats *mtsp;
29863a7e0a3SRobert Watson 
29963a7e0a3SRobert Watson 	critical_enter();
30063a7e0a3SRobert Watson 	mtip = mtp->ks_handle;
30163a7e0a3SRobert Watson 	mtsp = &mtip->mti_stats[curcpu];
30263a7e0a3SRobert Watson 	mtsp->mts_memfreed += size;
30363a7e0a3SRobert Watson 	mtsp->mts_numfrees++;
30491dd776cSJohn Birrell 
30591dd776cSJohn Birrell #ifdef KDTRACE_HOOKS
30691dd776cSJohn Birrell 	if (dtrace_malloc_probe != NULL) {
30791dd776cSJohn Birrell 		uint32_t probe_id = mtip->mti_probes[DTMALLOC_PROBE_FREE];
30891dd776cSJohn Birrell 		if (probe_id != 0)
30991dd776cSJohn Birrell 			(dtrace_malloc_probe)(probe_id,
31091dd776cSJohn Birrell 			    (uintptr_t) mtp, (uintptr_t) mtip,
31191dd776cSJohn Birrell 			    (uintptr_t) mtsp, size, 0);
31291dd776cSJohn Birrell 	}
31391dd776cSJohn Birrell #endif
31491dd776cSJohn Birrell 
31563a7e0a3SRobert Watson 	critical_exit();
3164362fadaSBrian Feldman }
3174362fadaSBrian Feldman 
3184362fadaSBrian Feldman /*
3191c7c3c6aSMatthew Dillon  *	malloc:
3201c7c3c6aSMatthew Dillon  *
3211c7c3c6aSMatthew Dillon  *	Allocate a block of memory.
3221c7c3c6aSMatthew Dillon  *
3231c7c3c6aSMatthew Dillon  *	If M_NOWAIT is set, this routine will not block and return NULL if
3241c7c3c6aSMatthew Dillon  *	the allocation fails.
325df8bae1dSRodney W. Grimes  */
326df8bae1dSRodney W. Grimes void *
32763a7e0a3SRobert Watson malloc(unsigned long size, struct malloc_type *mtp, int flags)
328df8bae1dSRodney W. Grimes {
3296f267175SJeff Roberson 	int indx;
3308355f576SJeff Roberson 	caddr_t va;
3318355f576SJeff Roberson 	uma_zone_t zone;
332847a2a17SPawel Jakub Dawidek #if defined(DIAGNOSTIC) || defined(DEBUG_REDZONE)
3334db4f5c8SPoul-Henning Kamp 	unsigned long osize = size;
3344db4f5c8SPoul-Henning Kamp #endif
335df8bae1dSRodney W. Grimes 
336194a0abfSPoul-Henning Kamp #ifdef INVARIANTS
337d3c11994SPoul-Henning Kamp 	/*
33823198357SRuslan Ermilov 	 * Check that exactly one of M_WAITOK or M_NOWAIT is specified.
339d3c11994SPoul-Henning Kamp 	 */
34023198357SRuslan Ermilov 	indx = flags & (M_WAITOK | M_NOWAIT);
341d3c11994SPoul-Henning Kamp 	if (indx != M_NOWAIT && indx != M_WAITOK) {
342d3c11994SPoul-Henning Kamp 		static	struct timeval lasterr;
343d3c11994SPoul-Henning Kamp 		static	int curerr, once;
344d3c11994SPoul-Henning Kamp 		if (once == 0 && ppsratecheck(&lasterr, &curerr, 1)) {
345d3c11994SPoul-Henning Kamp 			printf("Bad malloc flags: %x\n", indx);
3462d50560aSMarcel Moolenaar 			kdb_backtrace();
347d3c11994SPoul-Henning Kamp 			flags |= M_WAITOK;
348d3c11994SPoul-Henning Kamp 			once++;
349d3c11994SPoul-Henning Kamp 		}
350d3c11994SPoul-Henning Kamp 	}
351194a0abfSPoul-Henning Kamp #endif
352eae870cdSRobert Watson #ifdef MALLOC_MAKE_FAILURES
353eae870cdSRobert Watson 	if ((flags & M_NOWAIT) && (malloc_failure_rate != 0)) {
354eae870cdSRobert Watson 		atomic_add_int(&malloc_nowait_count, 1);
355eae870cdSRobert Watson 		if ((malloc_nowait_count % malloc_failure_rate) == 0) {
356eae870cdSRobert Watson 			atomic_add_int(&malloc_failure_count, 1);
3573f6ee876SPoul-Henning Kamp 			t_malloc_fail = time_uptime;
358eae870cdSRobert Watson 			return (NULL);
359eae870cdSRobert Watson 		}
360eae870cdSRobert Watson 	}
361eae870cdSRobert Watson #endif
362d3c11994SPoul-Henning Kamp 	if (flags & M_WAITOK)
363b40ce416SJulian Elischer 		KASSERT(curthread->td_intr_nesting_level == 0,
364a163d034SWarner Losh 		   ("malloc(M_WAITOK) in interrupt context"));
365e4eb384bSBosko Milekic 
366e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
367d362c40dSPawel Jakub Dawidek 	if (memguard_cmp(mtp))
368e4eb384bSBosko Milekic 		return memguard_alloc(size, flags);
369e4eb384bSBosko Milekic #endif
370e4eb384bSBosko Milekic 
371847a2a17SPawel Jakub Dawidek #ifdef DEBUG_REDZONE
372847a2a17SPawel Jakub Dawidek 	size = redzone_size_ntor(size);
373847a2a17SPawel Jakub Dawidek #endif
374847a2a17SPawel Jakub Dawidek 
3758355f576SJeff Roberson 	if (size <= KMEM_ZMAX) {
3766f267175SJeff Roberson 		if (size & KMEM_ZMASK)
3776f267175SJeff Roberson 			size = (size & ~KMEM_ZMASK) + KMEM_ZBASE;
3786f267175SJeff Roberson 		indx = kmemsize[size >> KMEM_ZSHIFT];
3796f267175SJeff Roberson 		zone = kmemzones[indx].kz_zone;
3806f267175SJeff Roberson #ifdef MALLOC_PROFILE
3816f267175SJeff Roberson 		krequests[size >> KMEM_ZSHIFT]++;
3826f267175SJeff Roberson #endif
3838355f576SJeff Roberson 		va = uma_zalloc(zone, flags);
3844362fadaSBrian Feldman 		if (va != NULL)
385e20a199fSJeff Roberson 			size = zone->uz_size;
38663a7e0a3SRobert Watson 		malloc_type_zone_allocated(mtp, va == NULL ? 0 : size, indx);
3878355f576SJeff Roberson 	} else {
3886f267175SJeff Roberson 		size = roundup(size, PAGE_SIZE);
3898355f576SJeff Roberson 		zone = NULL;
3908355f576SJeff Roberson 		va = uma_large_malloc(size, flags);
39163a7e0a3SRobert Watson 		malloc_type_allocated(mtp, va == NULL ? 0 : size);
392df8bae1dSRodney W. Grimes 	}
3931282e9acSPoul-Henning Kamp 	if (flags & M_WAITOK)
394a163d034SWarner Losh 		KASSERT(va != NULL, ("malloc(M_WAITOK) returned NULL"));
3951282e9acSPoul-Henning Kamp 	else if (va == NULL)
3961fb14a47SPoul-Henning Kamp 		t_malloc_fail = time_uptime;
3974db4f5c8SPoul-Henning Kamp #ifdef DIAGNOSTIC
3981282e9acSPoul-Henning Kamp 	if (va != NULL && !(flags & M_ZERO)) {
3994db4f5c8SPoul-Henning Kamp 		memset(va, 0x70, osize);
4004db4f5c8SPoul-Henning Kamp 	}
4014db4f5c8SPoul-Henning Kamp #endif
402847a2a17SPawel Jakub Dawidek #ifdef DEBUG_REDZONE
403847a2a17SPawel Jakub Dawidek 	if (va != NULL)
404847a2a17SPawel Jakub Dawidek 		va = redzone_setup(va, osize);
405847a2a17SPawel Jakub Dawidek #endif
406df8bae1dSRodney W. Grimes 	return ((void *) va);
407df8bae1dSRodney W. Grimes }
408df8bae1dSRodney W. Grimes 
409df8bae1dSRodney W. Grimes /*
4101c7c3c6aSMatthew Dillon  *	free:
4111c7c3c6aSMatthew Dillon  *
412df8bae1dSRodney W. Grimes  *	Free a block of memory allocated by malloc.
4131c7c3c6aSMatthew Dillon  *
4141c7c3c6aSMatthew Dillon  *	This routine may not block.
415df8bae1dSRodney W. Grimes  */
416df8bae1dSRodney W. Grimes void
41763a7e0a3SRobert Watson free(void *addr, struct malloc_type *mtp)
418df8bae1dSRodney W. Grimes {
41999571dc3SJeff Roberson 	uma_slab_t slab;
42099571dc3SJeff Roberson 	u_long size;
421254c6cb3SPoul-Henning Kamp 
42244a8ff31SArchie Cobbs 	/* free(NULL, ...) does nothing */
42344a8ff31SArchie Cobbs 	if (addr == NULL)
42444a8ff31SArchie Cobbs 		return;
42544a8ff31SArchie Cobbs 
426e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
427d362c40dSPawel Jakub Dawidek 	if (memguard_cmp(mtp)) {
428e4eb384bSBosko Milekic 		memguard_free(addr);
429e4eb384bSBosko Milekic 		return;
430e4eb384bSBosko Milekic 	}
431e4eb384bSBosko Milekic #endif
432e4eb384bSBosko Milekic 
433847a2a17SPawel Jakub Dawidek #ifdef DEBUG_REDZONE
434847a2a17SPawel Jakub Dawidek 	redzone_check(addr);
435847a2a17SPawel Jakub Dawidek 	addr = redzone_addr_ntor(addr);
436847a2a17SPawel Jakub Dawidek #endif
437847a2a17SPawel Jakub Dawidek 
4388355f576SJeff Roberson 	size = 0;
43969ef67f9SJason Evans 
44099571dc3SJeff Roberson 	slab = vtoslab((vm_offset_t)addr & (~UMA_SLAB_MASK));
4418355f576SJeff Roberson 
4428355f576SJeff Roberson 	if (slab == NULL)
4436f267175SJeff Roberson 		panic("free: address %p(%p) has not been allocated.\n",
44499571dc3SJeff Roberson 		    addr, (void *)((u_long)addr & (~UMA_SLAB_MASK)));
44599571dc3SJeff Roberson 
4468355f576SJeff Roberson 
4478355f576SJeff Roberson 	if (!(slab->us_flags & UMA_SLAB_MALLOC)) {
4488f70816cSJeff Roberson #ifdef INVARIANTS
44963a7e0a3SRobert Watson 		struct malloc_type **mtpp = addr;
4508f70816cSJeff Roberson #endif
451099a0e58SBosko Milekic 		size = slab->us_keg->uk_size;
4528f70816cSJeff Roberson #ifdef INVARIANTS
4538f70816cSJeff Roberson 		/*
4548f70816cSJeff Roberson 		 * Cache a pointer to the malloc_type that most recently freed
4558f70816cSJeff Roberson 		 * this memory here.  This way we know who is most likely to
4568f70816cSJeff Roberson 		 * have stepped on it later.
4578f70816cSJeff Roberson 		 *
4588f70816cSJeff Roberson 		 * This code assumes that size is a multiple of 8 bytes for
4598f70816cSJeff Roberson 		 * 64 bit machines
4608f70816cSJeff Roberson 		 */
46163a7e0a3SRobert Watson 		mtpp = (struct malloc_type **)
46263a7e0a3SRobert Watson 		    ((unsigned long)mtpp & ~UMA_ALIGN_PTR);
46363a7e0a3SRobert Watson 		mtpp += (size - sizeof(struct malloc_type *)) /
4648f70816cSJeff Roberson 		    sizeof(struct malloc_type *);
46563a7e0a3SRobert Watson 		*mtpp = mtp;
4668f70816cSJeff Roberson #endif
467099a0e58SBosko Milekic 		uma_zfree_arg(LIST_FIRST(&slab->us_keg->uk_zones), addr, slab);
46814bf02f8SJohn Dyson 	} else {
4698355f576SJeff Roberson 		size = slab->us_size;
4708355f576SJeff Roberson 		uma_large_free(slab);
47114bf02f8SJohn Dyson 	}
47263a7e0a3SRobert Watson 	malloc_type_freed(mtp, size);
473df8bae1dSRodney W. Grimes }
474df8bae1dSRodney W. Grimes 
475df8bae1dSRodney W. Grimes /*
47644a8ff31SArchie Cobbs  *	realloc: change the size of a memory block
47744a8ff31SArchie Cobbs  */
47844a8ff31SArchie Cobbs void *
47963a7e0a3SRobert Watson realloc(void *addr, unsigned long size, struct malloc_type *mtp, int flags)
48044a8ff31SArchie Cobbs {
4818355f576SJeff Roberson 	uma_slab_t slab;
48244a8ff31SArchie Cobbs 	unsigned long alloc;
48344a8ff31SArchie Cobbs 	void *newaddr;
48444a8ff31SArchie Cobbs 
48544a8ff31SArchie Cobbs 	/* realloc(NULL, ...) is equivalent to malloc(...) */
48644a8ff31SArchie Cobbs 	if (addr == NULL)
48763a7e0a3SRobert Watson 		return (malloc(size, mtp, flags));
48863a7e0a3SRobert Watson 
48963a7e0a3SRobert Watson 	/*
49063a7e0a3SRobert Watson 	 * XXX: Should report free of old memory and alloc of new memory to
49163a7e0a3SRobert Watson 	 * per-CPU stats.
49263a7e0a3SRobert Watson 	 */
49344a8ff31SArchie Cobbs 
494e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
495d362c40dSPawel Jakub Dawidek if (memguard_cmp(mtp)) {
496e4eb384bSBosko Milekic 	slab = NULL;
497e4eb384bSBosko Milekic 	alloc = size;
498e4eb384bSBosko Milekic } else {
499e4eb384bSBosko Milekic #endif
500e4eb384bSBosko Milekic 
501847a2a17SPawel Jakub Dawidek #ifdef DEBUG_REDZONE
502847a2a17SPawel Jakub Dawidek 	slab = NULL;
503847a2a17SPawel Jakub Dawidek 	alloc = redzone_get_size(addr);
504847a2a17SPawel Jakub Dawidek #else
50599571dc3SJeff Roberson 	slab = vtoslab((vm_offset_t)addr & ~(UMA_SLAB_MASK));
5068355f576SJeff Roberson 
50744a8ff31SArchie Cobbs 	/* Sanity check */
5088355f576SJeff Roberson 	KASSERT(slab != NULL,
50944a8ff31SArchie Cobbs 	    ("realloc: address %p out of range", (void *)addr));
51044a8ff31SArchie Cobbs 
51144a8ff31SArchie Cobbs 	/* Get the size of the original block */
512619f2841SPawel Jakub Dawidek 	if (!(slab->us_flags & UMA_SLAB_MALLOC))
513099a0e58SBosko Milekic 		alloc = slab->us_keg->uk_size;
5148355f576SJeff Roberson 	else
5158355f576SJeff Roberson 		alloc = slab->us_size;
51644a8ff31SArchie Cobbs 
51744a8ff31SArchie Cobbs 	/* Reuse the original block if appropriate */
51844a8ff31SArchie Cobbs 	if (size <= alloc
51944a8ff31SArchie Cobbs 	    && (size > (alloc >> REALLOC_FRACTION) || alloc == MINALLOCSIZE))
52044a8ff31SArchie Cobbs 		return (addr);
521847a2a17SPawel Jakub Dawidek #endif /* !DEBUG_REDZONE */
52244a8ff31SArchie Cobbs 
523e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
524e4eb384bSBosko Milekic }
525e4eb384bSBosko Milekic #endif
526e4eb384bSBosko Milekic 
52744a8ff31SArchie Cobbs 	/* Allocate a new, bigger (or smaller) block */
52863a7e0a3SRobert Watson 	if ((newaddr = malloc(size, mtp, flags)) == NULL)
52944a8ff31SArchie Cobbs 		return (NULL);
53044a8ff31SArchie Cobbs 
53144a8ff31SArchie Cobbs 	/* Copy over original contents */
53244a8ff31SArchie Cobbs 	bcopy(addr, newaddr, min(size, alloc));
53363a7e0a3SRobert Watson 	free(addr, mtp);
53444a8ff31SArchie Cobbs 	return (newaddr);
53544a8ff31SArchie Cobbs }
53644a8ff31SArchie Cobbs 
53744a8ff31SArchie Cobbs /*
53844a8ff31SArchie Cobbs  *	reallocf: same as realloc() but free memory on failure.
53944a8ff31SArchie Cobbs  */
54044a8ff31SArchie Cobbs void *
54163a7e0a3SRobert Watson reallocf(void *addr, unsigned long size, struct malloc_type *mtp, int flags)
54244a8ff31SArchie Cobbs {
54344a8ff31SArchie Cobbs 	void *mem;
54444a8ff31SArchie Cobbs 
54563a7e0a3SRobert Watson 	if ((mem = realloc(addr, size, mtp, flags)) == NULL)
54663a7e0a3SRobert Watson 		free(addr, mtp);
54744a8ff31SArchie Cobbs 	return (mem);
54844a8ff31SArchie Cobbs }
54944a8ff31SArchie Cobbs 
55044a8ff31SArchie Cobbs /*
551df8bae1dSRodney W. Grimes  * Initialize the kernel memory allocator
552df8bae1dSRodney W. Grimes  */
5532b14f991SJulian Elischer /* ARGSUSED*/
5542b14f991SJulian Elischer static void
55587efd4d5SRobert Watson kmeminit(void *dummy)
556df8bae1dSRodney W. Grimes {
5576f267175SJeff Roberson 	u_int8_t indx;
55827b8623fSDavid Greenman 	u_long mem_size;
5598355f576SJeff Roberson 	int i;
5608a58a9f6SJohn Dyson 
5616008862bSJohn Baldwin 	mtx_init(&malloc_mtx, "malloc", NULL, MTX_DEF);
56269ef67f9SJason Evans 
5638a58a9f6SJohn Dyson 	/*
5648a58a9f6SJohn Dyson 	 * Try to auto-tune the kernel memory size, so that it is
5658a58a9f6SJohn Dyson 	 * more applicable for a wider range of machine sizes.
5668a58a9f6SJohn Dyson 	 * On an X86, a VM_KMEM_SIZE_SCALE value of 4 is good, while
5678a58a9f6SJohn Dyson 	 * a VM_KMEM_SIZE of 12MB is a fair compromise.  The
5688a58a9f6SJohn Dyson 	 * VM_KMEM_SIZE_MAX is dependent on the maximum KVA space
5698a58a9f6SJohn Dyson 	 * available, and on an X86 with a total KVA space of 256MB,
5708a58a9f6SJohn Dyson 	 * try to keep VM_KMEM_SIZE_MAX at 80MB or below.
5718a58a9f6SJohn Dyson 	 *
5728a58a9f6SJohn Dyson 	 * Note that the kmem_map is also used by the zone allocator,
5738a58a9f6SJohn Dyson 	 * so make sure that there is enough space.
5748a58a9f6SJohn Dyson 	 */
575099a0e58SBosko Milekic 	vm_kmem_size = VM_KMEM_SIZE + nmbclusters * PAGE_SIZE;
5762feb50bfSAttilio Rao 	mem_size = cnt.v_page_count;
5778a58a9f6SJohn Dyson 
5788a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_SCALE)
579479439b4SDag-Erling Smørgrav 	vm_kmem_size_scale = VM_KMEM_SIZE_SCALE;
5808a58a9f6SJohn Dyson #endif
581479439b4SDag-Erling Smørgrav 	TUNABLE_INT_FETCH("vm.kmem_size_scale", &vm_kmem_size_scale);
582479439b4SDag-Erling Smørgrav 	if (vm_kmem_size_scale > 0 &&
583479439b4SDag-Erling Smørgrav 	    (mem_size / vm_kmem_size_scale) > (vm_kmem_size / PAGE_SIZE))
584479439b4SDag-Erling Smørgrav 		vm_kmem_size = (mem_size / vm_kmem_size_scale) * PAGE_SIZE;
5858a58a9f6SJohn Dyson 
5860e5179e4SStephane E. Potvin #if defined(VM_KMEM_SIZE_MIN)
5870e5179e4SStephane E. Potvin 	vm_kmem_size_min = VM_KMEM_SIZE_MIN;
5880e5179e4SStephane E. Potvin #endif
589b89eaf4eSAlan Cox 	TUNABLE_ULONG_FETCH("vm.kmem_size_min", &vm_kmem_size_min);
5900e5179e4SStephane E. Potvin 	if (vm_kmem_size_min > 0 && vm_kmem_size < vm_kmem_size_min) {
5910e5179e4SStephane E. Potvin 		vm_kmem_size = vm_kmem_size_min;
5920e5179e4SStephane E. Potvin 	}
5930e5179e4SStephane E. Potvin 
5948a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_MAX)
595479439b4SDag-Erling Smørgrav 	vm_kmem_size_max = VM_KMEM_SIZE_MAX;
5968a58a9f6SJohn Dyson #endif
597b89eaf4eSAlan Cox 	TUNABLE_ULONG_FETCH("vm.kmem_size_max", &vm_kmem_size_max);
598479439b4SDag-Erling Smørgrav 	if (vm_kmem_size_max > 0 && vm_kmem_size >= vm_kmem_size_max)
599479439b4SDag-Erling Smørgrav 		vm_kmem_size = vm_kmem_size_max;
6008a58a9f6SJohn Dyson 
6018de6e8e1SMike Smith 	/* Allow final override from the kernel environment */
60284344f9fSDag-Erling Smørgrav #ifndef BURN_BRIDGES
603b89eaf4eSAlan Cox 	if (TUNABLE_ULONG_FETCH("kern.vm.kmem.size", &vm_kmem_size) != 0)
60484344f9fSDag-Erling Smørgrav 		printf("kern.vm.kmem.size is now called vm.kmem_size!\n");
60584344f9fSDag-Erling Smørgrav #endif
606b89eaf4eSAlan Cox 	TUNABLE_ULONG_FETCH("vm.kmem_size", &vm_kmem_size);
6078de6e8e1SMike Smith 
60827b8623fSDavid Greenman 	/*
60927b8623fSDavid Greenman 	 * Limit kmem virtual size to twice the physical memory.
61027b8623fSDavid Greenman 	 * This allows for kmem map sparseness, but limits the size
61127b8623fSDavid Greenman 	 * to something sane. Be careful to not overflow the 32bit
61227b8623fSDavid Greenman 	 * ints while doing the check.
61327b8623fSDavid Greenman 	 */
6142feb50bfSAttilio Rao 	if (((vm_kmem_size / 2) / PAGE_SIZE) > cnt.v_page_count)
6152feb50bfSAttilio Rao 		vm_kmem_size = 2 * cnt.v_page_count * PAGE_SIZE;
6168a58a9f6SJohn Dyson 
61708442f8aSBosko Milekic 	/*
6186819e13eSAlan Cox 	 * Tune settings based on the kmem map's size at this time.
619347194c1SMike Silbersack 	 */
620347194c1SMike Silbersack 	init_param3(vm_kmem_size / PAGE_SIZE);
621347194c1SMike Silbersack 
622dc2e1e3fSRobert Watson 	kmem_map = kmem_suballoc(kernel_map, &kmembase, &kmemlimit,
6233202ed75SAlan Cox 	    vm_kmem_size, TRUE);
6243075778bSJohn Dyson 	kmem_map->system_map = 1;
6258355f576SJeff Roberson 
626e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
627e4eb384bSBosko Milekic 	/*
628e4eb384bSBosko Milekic 	 * Initialize MemGuard if support compiled in.  MemGuard is a
629e4eb384bSBosko Milekic 	 * replacement allocator used for detecting tamper-after-free
630e4eb384bSBosko Milekic 	 * scenarios as they occur.  It is only used for debugging.
631e4eb384bSBosko Milekic 	 */
632e4eb384bSBosko Milekic 	vm_memguard_divisor = 10;
633d362c40dSPawel Jakub Dawidek 	TUNABLE_INT_FETCH("vm.memguard.divisor", &vm_memguard_divisor);
634e4eb384bSBosko Milekic 
635e4eb384bSBosko Milekic 	/* Pick a conservative value if provided value sucks. */
636e4eb384bSBosko Milekic 	if ((vm_memguard_divisor <= 0) ||
637e4eb384bSBosko Milekic 	    ((vm_kmem_size / vm_memguard_divisor) == 0))
638e4eb384bSBosko Milekic 		vm_memguard_divisor = 10;
639e4eb384bSBosko Milekic 	memguard_init(kmem_map, vm_kmem_size / vm_memguard_divisor);
640e4eb384bSBosko Milekic #endif
641e4eb384bSBosko Milekic 
64299571dc3SJeff Roberson 	uma_startup2();
6438355f576SJeff Roberson 
64463a7e0a3SRobert Watson 	mt_zone = uma_zcreate("mt_zone", sizeof(struct malloc_type_internal),
64563a7e0a3SRobert Watson #ifdef INVARIANTS
64663a7e0a3SRobert Watson 	    mtrash_ctor, mtrash_dtor, mtrash_init, mtrash_fini,
64763a7e0a3SRobert Watson #else
64863a7e0a3SRobert Watson 	    NULL, NULL, NULL, NULL,
64963a7e0a3SRobert Watson #endif
65063a7e0a3SRobert Watson 	    UMA_ALIGN_PTR, UMA_ZONE_MALLOC);
6516f267175SJeff Roberson 	for (i = 0, indx = 0; kmemzones[indx].kz_size != 0; indx++) {
6526f267175SJeff Roberson 		int size = kmemzones[indx].kz_size;
6536f267175SJeff Roberson 		char *name = kmemzones[indx].kz_name;
6548355f576SJeff Roberson 
6558efc4effSJeff Roberson 		kmemzones[indx].kz_zone = uma_zcreate(name, size,
6568efc4effSJeff Roberson #ifdef INVARIANTS
6578f70816cSJeff Roberson 		    mtrash_ctor, mtrash_dtor, mtrash_init, mtrash_fini,
6588efc4effSJeff Roberson #else
6598efc4effSJeff Roberson 		    NULL, NULL, NULL, NULL,
6608efc4effSJeff Roberson #endif
6618efc4effSJeff Roberson 		    UMA_ALIGN_PTR, UMA_ZONE_MALLOC);
6626f267175SJeff Roberson 
6638355f576SJeff Roberson 		for (;i <= size; i+= KMEM_ZBASE)
6646f267175SJeff Roberson 			kmemsize[i >> KMEM_ZSHIFT] = indx;
6658355f576SJeff Roberson 
666df8bae1dSRodney W. Grimes 	}
667254c6cb3SPoul-Henning Kamp }
668254c6cb3SPoul-Henning Kamp 
669db669378SPeter Wemm void
67087efd4d5SRobert Watson malloc_init(void *data)
671254c6cb3SPoul-Henning Kamp {
67263a7e0a3SRobert Watson 	struct malloc_type_internal *mtip;
67363a7e0a3SRobert Watson 	struct malloc_type *mtp;
67463a7e0a3SRobert Watson 
6752feb50bfSAttilio Rao 	KASSERT(cnt.v_page_count != 0, ("malloc_register before vm_init"));
67663a7e0a3SRobert Watson 
67763a7e0a3SRobert Watson 	mtp = data;
67863a7e0a3SRobert Watson 	mtip = uma_zalloc(mt_zone, M_WAITOK | M_ZERO);
67963a7e0a3SRobert Watson 	mtp->ks_handle = mtip;
680254c6cb3SPoul-Henning Kamp 
6816f267175SJeff Roberson 	mtx_lock(&malloc_mtx);
68263a7e0a3SRobert Watson 	mtp->ks_next = kmemstatistics;
68363a7e0a3SRobert Watson 	kmemstatistics = mtp;
684cd814b26SRobert Watson 	kmemcount++;
6856f267175SJeff Roberson 	mtx_unlock(&malloc_mtx);
686df8bae1dSRodney W. Grimes }
687db669378SPeter Wemm 
688db669378SPeter Wemm void
68987efd4d5SRobert Watson malloc_uninit(void *data)
690db669378SPeter Wemm {
69163a7e0a3SRobert Watson 	struct malloc_type_internal *mtip;
6922a143d5bSPawel Jakub Dawidek 	struct malloc_type_stats *mtsp;
69363a7e0a3SRobert Watson 	struct malloc_type *mtp, *temp;
69445d48bdaSPaul Saab 	uma_slab_t slab;
6952a143d5bSPawel Jakub Dawidek 	long temp_allocs, temp_bytes;
6962a143d5bSPawel Jakub Dawidek 	int i;
697db669378SPeter Wemm 
69863a7e0a3SRobert Watson 	mtp = data;
69963a7e0a3SRobert Watson 	KASSERT(mtp->ks_handle != NULL, ("malloc_deregister: cookie NULL"));
7006f267175SJeff Roberson 	mtx_lock(&malloc_mtx);
70163a7e0a3SRobert Watson 	mtip = mtp->ks_handle;
70263a7e0a3SRobert Watson 	mtp->ks_handle = NULL;
70363a7e0a3SRobert Watson 	if (mtp != kmemstatistics) {
70463a7e0a3SRobert Watson 		for (temp = kmemstatistics; temp != NULL;
70563a7e0a3SRobert Watson 		    temp = temp->ks_next) {
70663a7e0a3SRobert Watson 			if (temp->ks_next == mtp)
70763a7e0a3SRobert Watson 				temp->ks_next = mtp->ks_next;
708db669378SPeter Wemm 		}
70963a7e0a3SRobert Watson 	} else
71063a7e0a3SRobert Watson 		kmemstatistics = mtp->ks_next;
711cd814b26SRobert Watson 	kmemcount--;
7126f267175SJeff Roberson 	mtx_unlock(&malloc_mtx);
7132a143d5bSPawel Jakub Dawidek 
7142a143d5bSPawel Jakub Dawidek 	/*
7152a143d5bSPawel Jakub Dawidek 	 * Look for memory leaks.
7162a143d5bSPawel Jakub Dawidek 	 */
7172a143d5bSPawel Jakub Dawidek 	temp_allocs = temp_bytes = 0;
7182a143d5bSPawel Jakub Dawidek 	for (i = 0; i < MAXCPU; i++) {
7192a143d5bSPawel Jakub Dawidek 		mtsp = &mtip->mti_stats[i];
7202a143d5bSPawel Jakub Dawidek 		temp_allocs += mtsp->mts_numallocs;
7212a143d5bSPawel Jakub Dawidek 		temp_allocs -= mtsp->mts_numfrees;
7222a143d5bSPawel Jakub Dawidek 		temp_bytes += mtsp->mts_memalloced;
7232a143d5bSPawel Jakub Dawidek 		temp_bytes -= mtsp->mts_memfreed;
7242a143d5bSPawel Jakub Dawidek 	}
7252a143d5bSPawel Jakub Dawidek 	if (temp_allocs > 0 || temp_bytes > 0) {
7262a143d5bSPawel Jakub Dawidek 		printf("Warning: memory type %s leaked memory on destroy "
7272a143d5bSPawel Jakub Dawidek 		    "(%ld allocations, %ld bytes leaked).\n", mtp->ks_shortdesc,
7282a143d5bSPawel Jakub Dawidek 		    temp_allocs, temp_bytes);
7292a143d5bSPawel Jakub Dawidek 	}
7302a143d5bSPawel Jakub Dawidek 
73145d48bdaSPaul Saab 	slab = vtoslab((vm_offset_t) mtip & (~UMA_SLAB_MASK));
73245d48bdaSPaul Saab 	uma_zfree_arg(mt_zone, mtip, slab);
733db669378SPeter Wemm }
7346f267175SJeff Roberson 
735d362c40dSPawel Jakub Dawidek struct malloc_type *
736d362c40dSPawel Jakub Dawidek malloc_desc2type(const char *desc)
737d362c40dSPawel Jakub Dawidek {
738d362c40dSPawel Jakub Dawidek 	struct malloc_type *mtp;
739d362c40dSPawel Jakub Dawidek 
740d362c40dSPawel Jakub Dawidek 	mtx_assert(&malloc_mtx, MA_OWNED);
741d362c40dSPawel Jakub Dawidek 	for (mtp = kmemstatistics; mtp != NULL; mtp = mtp->ks_next) {
742d362c40dSPawel Jakub Dawidek 		if (strcmp(mtp->ks_shortdesc, desc) == 0)
743d362c40dSPawel Jakub Dawidek 			return (mtp);
744d362c40dSPawel Jakub Dawidek 	}
745d362c40dSPawel Jakub Dawidek 	return (NULL);
746d362c40dSPawel Jakub Dawidek }
747d362c40dSPawel Jakub Dawidek 
7486f267175SJeff Roberson static int
749cd814b26SRobert Watson sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS)
750cd814b26SRobert Watson {
751cd814b26SRobert Watson 	struct malloc_type_stream_header mtsh;
752cd814b26SRobert Watson 	struct malloc_type_internal *mtip;
753cd814b26SRobert Watson 	struct malloc_type_header mth;
754cd814b26SRobert Watson 	struct malloc_type *mtp;
755cd814b26SRobert Watson 	int buflen, count, error, i;
756cd814b26SRobert Watson 	struct sbuf sbuf;
757cd814b26SRobert Watson 	char *buffer;
758cd814b26SRobert Watson 
759cd814b26SRobert Watson 	mtx_lock(&malloc_mtx);
760cd814b26SRobert Watson restart:
761cd814b26SRobert Watson 	mtx_assert(&malloc_mtx, MA_OWNED);
762cd814b26SRobert Watson 	count = kmemcount;
763cd814b26SRobert Watson 	mtx_unlock(&malloc_mtx);
764cd814b26SRobert Watson 	buflen = sizeof(mtsh) + count * (sizeof(mth) +
765cd814b26SRobert Watson 	    sizeof(struct malloc_type_stats) * MAXCPU) + 1;
766cd814b26SRobert Watson 	buffer = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
767cd814b26SRobert Watson 	mtx_lock(&malloc_mtx);
768cd814b26SRobert Watson 	if (count < kmemcount) {
769cd814b26SRobert Watson 		free(buffer, M_TEMP);
770cd814b26SRobert Watson 		goto restart;
771cd814b26SRobert Watson 	}
772cd814b26SRobert Watson 
773cd814b26SRobert Watson 	sbuf_new(&sbuf, buffer, buflen, SBUF_FIXEDLEN);
774cd814b26SRobert Watson 
775cd814b26SRobert Watson 	/*
776cd814b26SRobert Watson 	 * Insert stream header.
777cd814b26SRobert Watson 	 */
778cd814b26SRobert Watson 	bzero(&mtsh, sizeof(mtsh));
779cd814b26SRobert Watson 	mtsh.mtsh_version = MALLOC_TYPE_STREAM_VERSION;
780cd814b26SRobert Watson 	mtsh.mtsh_maxcpus = MAXCPU;
781cd814b26SRobert Watson 	mtsh.mtsh_count = kmemcount;
782cd814b26SRobert Watson 	if (sbuf_bcat(&sbuf, &mtsh, sizeof(mtsh)) < 0) {
783cd814b26SRobert Watson 		mtx_unlock(&malloc_mtx);
784cd814b26SRobert Watson 		error = ENOMEM;
785cd814b26SRobert Watson 		goto out;
786cd814b26SRobert Watson 	}
787cd814b26SRobert Watson 
788cd814b26SRobert Watson 	/*
789cd814b26SRobert Watson 	 * Insert alternating sequence of type headers and type statistics.
790cd814b26SRobert Watson 	 */
791cd814b26SRobert Watson 	for (mtp = kmemstatistics; mtp != NULL; mtp = mtp->ks_next) {
792cd814b26SRobert Watson 		mtip = (struct malloc_type_internal *)mtp->ks_handle;
793cd814b26SRobert Watson 
794cd814b26SRobert Watson 		/*
795cd814b26SRobert Watson 		 * Insert type header.
796cd814b26SRobert Watson 		 */
797cd814b26SRobert Watson 		bzero(&mth, sizeof(mth));
798cd814b26SRobert Watson 		strlcpy(mth.mth_name, mtp->ks_shortdesc, MALLOC_MAX_NAME);
799cd814b26SRobert Watson 		if (sbuf_bcat(&sbuf, &mth, sizeof(mth)) < 0) {
800cd814b26SRobert Watson 			mtx_unlock(&malloc_mtx);
801cd814b26SRobert Watson 			error = ENOMEM;
802cd814b26SRobert Watson 			goto out;
803cd814b26SRobert Watson 		}
804cd814b26SRobert Watson 
805cd814b26SRobert Watson 		/*
806cd814b26SRobert Watson 		 * Insert type statistics for each CPU.
807cd814b26SRobert Watson 		 */
808cd814b26SRobert Watson 		for (i = 0; i < MAXCPU; i++) {
809cd814b26SRobert Watson 			if (sbuf_bcat(&sbuf, &mtip->mti_stats[i],
810cd814b26SRobert Watson 			    sizeof(mtip->mti_stats[i])) < 0) {
811cd814b26SRobert Watson 				mtx_unlock(&malloc_mtx);
812cd814b26SRobert Watson 				error = ENOMEM;
813cd814b26SRobert Watson 				goto out;
814cd814b26SRobert Watson 			}
815cd814b26SRobert Watson 		}
816cd814b26SRobert Watson 	}
817cd814b26SRobert Watson 	mtx_unlock(&malloc_mtx);
818cd814b26SRobert Watson 	sbuf_finish(&sbuf);
819cd814b26SRobert Watson 	error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf));
820cd814b26SRobert Watson out:
821cd814b26SRobert Watson 	sbuf_delete(&sbuf);
822cd814b26SRobert Watson 	free(buffer, M_TEMP);
823cd814b26SRobert Watson 	return (error);
824cd814b26SRobert Watson }
825cd814b26SRobert Watson 
826cd814b26SRobert Watson SYSCTL_PROC(_kern, OID_AUTO, malloc_stats, CTLFLAG_RD|CTLTYPE_STRUCT,
827cd814b26SRobert Watson     0, 0, sysctl_kern_malloc_stats, "s,malloc_type_ustats",
828cd814b26SRobert Watson     "Return malloc types");
829cd814b26SRobert Watson 
830cd814b26SRobert Watson SYSCTL_INT(_kern, OID_AUTO, malloc_count, CTLFLAG_RD, &kmemcount, 0,
831cd814b26SRobert Watson     "Count of kernel malloc types");
832cd814b26SRobert Watson 
83391dd776cSJohn Birrell void
83491dd776cSJohn Birrell malloc_type_list(malloc_type_list_func_t *func, void *arg)
83591dd776cSJohn Birrell {
83691dd776cSJohn Birrell 	struct malloc_type *mtp, **bufmtp;
83791dd776cSJohn Birrell 	int count, i;
83891dd776cSJohn Birrell 	size_t buflen;
83991dd776cSJohn Birrell 
84091dd776cSJohn Birrell 	mtx_lock(&malloc_mtx);
84191dd776cSJohn Birrell restart:
84291dd776cSJohn Birrell 	mtx_assert(&malloc_mtx, MA_OWNED);
84391dd776cSJohn Birrell 	count = kmemcount;
84491dd776cSJohn Birrell 	mtx_unlock(&malloc_mtx);
84591dd776cSJohn Birrell 
84691dd776cSJohn Birrell 	buflen = sizeof(struct malloc_type *) * count;
84791dd776cSJohn Birrell 	bufmtp = malloc(buflen, M_TEMP, M_WAITOK);
84891dd776cSJohn Birrell 
84991dd776cSJohn Birrell 	mtx_lock(&malloc_mtx);
85091dd776cSJohn Birrell 
85191dd776cSJohn Birrell 	if (count < kmemcount) {
85291dd776cSJohn Birrell 		free(bufmtp, M_TEMP);
85391dd776cSJohn Birrell 		goto restart;
85491dd776cSJohn Birrell 	}
85591dd776cSJohn Birrell 
85691dd776cSJohn Birrell 	for (mtp = kmemstatistics, i = 0; mtp != NULL; mtp = mtp->ks_next, i++)
85791dd776cSJohn Birrell 		bufmtp[i] = mtp;
85891dd776cSJohn Birrell 
85991dd776cSJohn Birrell 	mtx_unlock(&malloc_mtx);
86091dd776cSJohn Birrell 
86191dd776cSJohn Birrell 	for (i = 0; i < count; i++)
86291dd776cSJohn Birrell 		(func)(bufmtp[i], arg);
86391dd776cSJohn Birrell 
86491dd776cSJohn Birrell 	free(bufmtp, M_TEMP);
86591dd776cSJohn Birrell }
86691dd776cSJohn Birrell 
867909ed16cSRobert Watson #ifdef DDB
868909ed16cSRobert Watson DB_SHOW_COMMAND(malloc, db_show_malloc)
869909ed16cSRobert Watson {
870909ed16cSRobert Watson 	struct malloc_type_internal *mtip;
871909ed16cSRobert Watson 	struct malloc_type *mtp;
872909ed16cSRobert Watson 	u_int64_t allocs, frees;
87324076d13SRobert Watson 	u_int64_t alloced, freed;
874909ed16cSRobert Watson 	int i;
875909ed16cSRobert Watson 
87624076d13SRobert Watson 	db_printf("%18s %12s  %12s %12s\n", "Type", "InUse", "MemUse",
87724076d13SRobert Watson 	    "Requests");
878909ed16cSRobert Watson 	for (mtp = kmemstatistics; mtp != NULL; mtp = mtp->ks_next) {
879909ed16cSRobert Watson 		mtip = (struct malloc_type_internal *)mtp->ks_handle;
880909ed16cSRobert Watson 		allocs = 0;
881909ed16cSRobert Watson 		frees = 0;
88224076d13SRobert Watson 		alloced = 0;
88324076d13SRobert Watson 		freed = 0;
884909ed16cSRobert Watson 		for (i = 0; i < MAXCPU; i++) {
885909ed16cSRobert Watson 			allocs += mtip->mti_stats[i].mts_numallocs;
886909ed16cSRobert Watson 			frees += mtip->mti_stats[i].mts_numfrees;
88724076d13SRobert Watson 			alloced += mtip->mti_stats[i].mts_memalloced;
88824076d13SRobert Watson 			freed += mtip->mti_stats[i].mts_memfreed;
889909ed16cSRobert Watson 		}
89024076d13SRobert Watson 		db_printf("%18s %12ju %12juK %12ju\n",
89124076d13SRobert Watson 		    mtp->ks_shortdesc, allocs - frees,
89224076d13SRobert Watson 		    (alloced - freed + 1023) / 1024, allocs);
893909ed16cSRobert Watson 	}
894909ed16cSRobert Watson }
895909ed16cSRobert Watson #endif
896909ed16cSRobert Watson 
8975e914b96SJeff Roberson #ifdef MALLOC_PROFILE
8985e914b96SJeff Roberson 
8995e914b96SJeff Roberson static int
9005e914b96SJeff Roberson sysctl_kern_mprof(SYSCTL_HANDLER_ARGS)
9015e914b96SJeff Roberson {
9025e914b96SJeff Roberson 	int linesize = 64;
90363a7e0a3SRobert Watson 	struct sbuf sbuf;
9045e914b96SJeff Roberson 	uint64_t count;
9055e914b96SJeff Roberson 	uint64_t waste;
9065e914b96SJeff Roberson 	uint64_t mem;
9075e914b96SJeff Roberson 	int bufsize;
9085e914b96SJeff Roberson 	int error;
9095e914b96SJeff Roberson 	char *buf;
9105e914b96SJeff Roberson 	int rsize;
9115e914b96SJeff Roberson 	int size;
9125e914b96SJeff Roberson 	int i;
9135e914b96SJeff Roberson 
9145e914b96SJeff Roberson 	bufsize = linesize * (KMEM_ZSIZE + 1);
9155e914b96SJeff Roberson 	bufsize += 128; 	/* For the stats line */
9165e914b96SJeff Roberson 	bufsize += 128; 	/* For the banner line */
9175e914b96SJeff Roberson 	waste = 0;
9185e914b96SJeff Roberson 	mem = 0;
9195e914b96SJeff Roberson 
92063a7e0a3SRobert Watson 	buf = malloc(bufsize, M_TEMP, M_WAITOK|M_ZERO);
92163a7e0a3SRobert Watson 	sbuf_new(&sbuf, buf, bufsize, SBUF_FIXEDLEN);
92263a7e0a3SRobert Watson 	sbuf_printf(&sbuf,
9235e914b96SJeff Roberson 	    "\n  Size                    Requests  Real Size\n");
9245e914b96SJeff Roberson 	for (i = 0; i < KMEM_ZSIZE; i++) {
9255e914b96SJeff Roberson 		size = i << KMEM_ZSHIFT;
9265e914b96SJeff Roberson 		rsize = kmemzones[kmemsize[i]].kz_size;
9275e914b96SJeff Roberson 		count = (long long unsigned)krequests[i];
9285e914b96SJeff Roberson 
92963a7e0a3SRobert Watson 		sbuf_printf(&sbuf, "%6d%28llu%11d\n", size,
93063a7e0a3SRobert Watson 		    (unsigned long long)count, rsize);
9315e914b96SJeff Roberson 
9325e914b96SJeff Roberson 		if ((rsize * count) > (size * count))
9335e914b96SJeff Roberson 			waste += (rsize * count) - (size * count);
9345e914b96SJeff Roberson 		mem += (rsize * count);
9355e914b96SJeff Roberson 	}
93663a7e0a3SRobert Watson 	sbuf_printf(&sbuf,
9375e914b96SJeff Roberson 	    "\nTotal memory used:\t%30llu\nTotal Memory wasted:\t%30llu\n",
9385e914b96SJeff Roberson 	    (unsigned long long)mem, (unsigned long long)waste);
93963a7e0a3SRobert Watson 	sbuf_finish(&sbuf);
9405e914b96SJeff Roberson 
94163a7e0a3SRobert Watson 	error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf));
9425e914b96SJeff Roberson 
94363a7e0a3SRobert Watson 	sbuf_delete(&sbuf);
9445e914b96SJeff Roberson 	free(buf, M_TEMP);
9455e914b96SJeff Roberson 	return (error);
9465e914b96SJeff Roberson }
9475e914b96SJeff Roberson 
9485e914b96SJeff Roberson SYSCTL_OID(_kern, OID_AUTO, mprof, CTLTYPE_STRING|CTLFLAG_RD,
9495e914b96SJeff Roberson     NULL, 0, sysctl_kern_mprof, "A", "Malloc Profiling");
9505e914b96SJeff Roberson #endif /* MALLOC_PROFILE */
951