xref: /freebsd/sys/kern/kern_malloc.c (revision 3805385e3d2f8bef16d412d8bcbfda4f2f88cc5a)
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"
498a58a9f6SJohn Dyson #include "opt_vm.h"
508a58a9f6SJohn Dyson 
51df8bae1dSRodney W. Grimes #include <sys/param.h>
5226f9a767SRodney W. Grimes #include <sys/systm.h>
532d50560aSMarcel Moolenaar #include <sys/kdb.h>
54df8bae1dSRodney W. Grimes #include <sys/kernel.h>
55fb919e4dSMark Murray #include <sys/lock.h>
56df8bae1dSRodney W. Grimes #include <sys/malloc.h>
5754e7152cSDavid Greenman #include <sys/mbuf.h>
58eec258d2SJohn Baldwin #include <sys/mutex.h>
59efeaf95aSDavid Greenman #include <sys/vmmeter.h>
60a448b62aSJake Burkholder #include <sys/proc.h>
6163a7e0a3SRobert Watson #include <sys/sbuf.h>
626f267175SJeff Roberson #include <sys/sysctl.h>
631fb14a47SPoul-Henning Kamp #include <sys/time.h>
649a02e8c6SJason Evans 
65df8bae1dSRodney W. Grimes #include <vm/vm.h>
6699571dc3SJeff Roberson #include <vm/pmap.h>
67efeaf95aSDavid Greenman #include <vm/vm_param.h>
68df8bae1dSRodney W. Grimes #include <vm/vm_kern.h>
69efeaf95aSDavid Greenman #include <vm/vm_extern.h>
703075778bSJohn Dyson #include <vm/vm_map.h>
7199571dc3SJeff Roberson #include <vm/vm_page.h>
728355f576SJeff Roberson #include <vm/uma.h>
738355f576SJeff Roberson #include <vm/uma_int.h>
748efc4effSJeff Roberson #include <vm/uma_dbg.h>
75df8bae1dSRodney W. Grimes 
76e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
77e4eb384bSBosko Milekic #include <vm/memguard.h>
78e4eb384bSBosko Milekic #endif
79847a2a17SPawel Jakub Dawidek #ifdef DEBUG_REDZONE
80847a2a17SPawel Jakub Dawidek #include <vm/redzone.h>
81847a2a17SPawel Jakub Dawidek #endif
82e4eb384bSBosko Milekic 
83984982d6SPoul-Henning Kamp #if defined(INVARIANTS) && defined(__i386__)
84984982d6SPoul-Henning Kamp #include <machine/cpu.h>
85984982d6SPoul-Henning Kamp #endif
86984982d6SPoul-Henning Kamp 
87909ed16cSRobert Watson #include <ddb/ddb.h>
88909ed16cSRobert Watson 
8944a8ff31SArchie Cobbs /*
9044a8ff31SArchie Cobbs  * When realloc() is called, if the new size is sufficiently smaller than
9144a8ff31SArchie Cobbs  * the old size, realloc() will allocate a new, smaller block to avoid
9244a8ff31SArchie Cobbs  * wasting memory. 'Sufficiently smaller' is defined as: newsize <=
9344a8ff31SArchie Cobbs  * oldsize / 2^n, where REALLOC_FRACTION defines the value of 'n'.
9444a8ff31SArchie Cobbs  */
9544a8ff31SArchie Cobbs #ifndef REALLOC_FRACTION
9644a8ff31SArchie Cobbs #define	REALLOC_FRACTION	1	/* new block if <= half the size */
9744a8ff31SArchie Cobbs #endif
9844a8ff31SArchie Cobbs 
990ce3f16dSRobert Watson /*
1000ce3f16dSRobert Watson  * Centrally define some common malloc types.
1010ce3f16dSRobert Watson  */
1023b6fb885SPoul-Henning Kamp MALLOC_DEFINE(M_CACHE, "cache", "Various Dynamically allocated caches");
1039ef246c6SBruce Evans MALLOC_DEFINE(M_DEVBUF, "devbuf", "device driver memory");
1049ef246c6SBruce Evans MALLOC_DEFINE(M_TEMP, "temp", "misc temporary data buffers");
1059ef246c6SBruce Evans 
10682cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6OPT, "ip6opt", "IPv6 options");
10782cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6NDP, "ip6ndp", "IPv6 Neighbor Discovery");
10882cd038dSYoshinobu Inoue 
1094d77a549SAlfred Perlstein static void kmeminit(void *);
1102b14f991SJulian Elischer SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL)
1112b14f991SJulian Elischer 
112a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FREE, "free", "should be on free list");
113a1c995b6SPoul-Henning Kamp 
114db669378SPeter Wemm static struct malloc_type *kmemstatistics;
115254c6cb3SPoul-Henning Kamp static char *kmembase;
116043a2f3bSBruce Evans static char *kmemlimit;
117cd814b26SRobert Watson static int kmemcount;
1181f6889a1SMatthew Dillon 
1198355f576SJeff Roberson #define KMEM_ZSHIFT	4
1208355f576SJeff Roberson #define KMEM_ZBASE	16
1218355f576SJeff Roberson #define KMEM_ZMASK	(KMEM_ZBASE - 1)
1228355f576SJeff Roberson 
1239fb535deSJeff Roberson #define KMEM_ZMAX	PAGE_SIZE
1248355f576SJeff Roberson #define KMEM_ZSIZE	(KMEM_ZMAX >> KMEM_ZSHIFT)
1256f267175SJeff Roberson static u_int8_t kmemsize[KMEM_ZSIZE + 1];
1266f267175SJeff Roberson 
1270ce3f16dSRobert Watson /*
1280ce3f16dSRobert Watson  * Small malloc(9) memory allocations are allocated from a set of UMA buckets
1290ce3f16dSRobert Watson  * of various sizes.
1300ce3f16dSRobert Watson  *
1310ce3f16dSRobert Watson  * XXX: The comment here used to read "These won't be powers of two for
1320ce3f16dSRobert Watson  * long."  It's possible that a significant amount of wasted memory could be
1330ce3f16dSRobert Watson  * recovered by tuning the sizes of these buckets.
1340ce3f16dSRobert Watson  */
1358355f576SJeff Roberson struct {
1366f267175SJeff Roberson 	int kz_size;
1376f267175SJeff Roberson 	char *kz_name;
1386f267175SJeff Roberson 	uma_zone_t kz_zone;
1396f267175SJeff Roberson } kmemzones[] = {
1406f267175SJeff Roberson 	{16, "16", NULL},
1416f267175SJeff Roberson 	{32, "32", NULL},
1426f267175SJeff Roberson 	{64, "64", NULL},
1436f267175SJeff Roberson 	{128, "128", NULL},
1446f267175SJeff Roberson 	{256, "256", NULL},
1456f267175SJeff Roberson 	{512, "512", NULL},
1466f267175SJeff Roberson 	{1024, "1024", NULL},
1476f267175SJeff Roberson 	{2048, "2048", NULL},
1486f267175SJeff Roberson 	{4096, "4096", NULL},
1499fb535deSJeff Roberson #if PAGE_SIZE > 4096
1506f267175SJeff Roberson 	{8192, "8192", NULL},
1519fb535deSJeff Roberson #if PAGE_SIZE > 8192
15243a7c4e9SRobert Watson 	{16384, "16384", NULL},
1539fb535deSJeff Roberson #if PAGE_SIZE > 16384
154bd796eb2SRobert Watson 	{32768, "32768", NULL},
1559fb535deSJeff Roberson #if PAGE_SIZE > 32768
156bd796eb2SRobert Watson 	{65536, "65536", NULL},
1579fb535deSJeff Roberson #if PAGE_SIZE > 65536
1589fb535deSJeff Roberson #error	"Unsupported PAGE_SIZE"
1599fb535deSJeff Roberson #endif	/* 65536 */
1609fb535deSJeff Roberson #endif	/* 32768 */
1619fb535deSJeff Roberson #endif	/* 16384 */
1629fb535deSJeff Roberson #endif	/* 8192 */
1639fb535deSJeff Roberson #endif	/* 4096 */
1648355f576SJeff Roberson 	{0, NULL},
1658355f576SJeff Roberson };
1668355f576SJeff Roberson 
1670ce3f16dSRobert Watson /*
1680ce3f16dSRobert Watson  * Zone to allocate malloc type descriptions from.  For ABI reasons, memory
1690ce3f16dSRobert Watson  * types are described by a data structure passed by the declaring code, but
1700ce3f16dSRobert Watson  * the malloc(9) implementation has its own data structure describing the
1710ce3f16dSRobert Watson  * type and statistics.  This permits the malloc(9)-internal data structures
1720ce3f16dSRobert Watson  * to be modified without breaking binary-compiled kernel modules that
1730ce3f16dSRobert Watson  * declare malloc types.
1740ce3f16dSRobert Watson  */
17563a7e0a3SRobert Watson static uma_zone_t mt_zone;
17663a7e0a3SRobert Watson 
1776f267175SJeff Roberson u_int vm_kmem_size;
17884344f9fSDag-Erling Smørgrav SYSCTL_UINT(_vm, OID_AUTO, kmem_size, CTLFLAG_RD, &vm_kmem_size, 0,
17984344f9fSDag-Erling Smørgrav     "Size of kernel memory");
1805a34a9f0SJeff Roberson 
1810e5179e4SStephane E. Potvin u_int vm_kmem_size_min;
1820e5179e4SStephane E. Potvin SYSCTL_UINT(_vm, OID_AUTO, kmem_size_min, CTLFLAG_RD, &vm_kmem_size_min, 0,
1830e5179e4SStephane E. Potvin     "Minimum size of kernel memory");
1840e5179e4SStephane E. Potvin 
185479439b4SDag-Erling Smørgrav u_int vm_kmem_size_max;
186479439b4SDag-Erling Smørgrav SYSCTL_UINT(_vm, OID_AUTO, kmem_size_max, CTLFLAG_RD, &vm_kmem_size_max, 0,
187479439b4SDag-Erling Smørgrav     "Maximum size of kernel memory");
188479439b4SDag-Erling Smørgrav 
189479439b4SDag-Erling Smørgrav u_int vm_kmem_size_scale;
190479439b4SDag-Erling Smørgrav SYSCTL_UINT(_vm, OID_AUTO, kmem_size_scale, CTLFLAG_RD, &vm_kmem_size_scale, 0,
191479439b4SDag-Erling Smørgrav     "Scale factor for kernel memory size");
192479439b4SDag-Erling Smørgrav 
1935a34a9f0SJeff Roberson /*
19499571dc3SJeff Roberson  * The malloc_mtx protects the kmemstatistics linked list.
1955a34a9f0SJeff Roberson  */
1965a34a9f0SJeff Roberson struct mtx malloc_mtx;
19769ef67f9SJason Evans 
1985e914b96SJeff Roberson #ifdef MALLOC_PROFILE
1995e914b96SJeff Roberson uint64_t krequests[KMEM_ZSIZE + 1];
2006f267175SJeff Roberson 
2015e914b96SJeff Roberson static int sysctl_kern_mprof(SYSCTL_HANDLER_ARGS);
2025e914b96SJeff Roberson #endif
2035e914b96SJeff Roberson 
204cd814b26SRobert Watson static int sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS);
205df8bae1dSRodney W. Grimes 
2060ce3f16dSRobert Watson /*
2070ce3f16dSRobert Watson  * time_uptime of the last malloc(9) failure (induced or real).
2080ce3f16dSRobert Watson  */
2091fb14a47SPoul-Henning Kamp static time_t t_malloc_fail;
2101fb14a47SPoul-Henning Kamp 
211eae870cdSRobert Watson /*
2120ce3f16dSRobert Watson  * malloc(9) fault injection -- cause malloc failures every (n) mallocs when
2130ce3f16dSRobert Watson  * the caller specifies M_NOWAIT.  If set to 0, no failures are caused.
214eae870cdSRobert Watson  */
2150ce3f16dSRobert Watson #ifdef MALLOC_MAKE_FAILURES
216eae870cdSRobert Watson SYSCTL_NODE(_debug, OID_AUTO, malloc, CTLFLAG_RD, 0,
217eae870cdSRobert Watson     "Kernel malloc debugging options");
218eae870cdSRobert Watson 
219eae870cdSRobert Watson static int malloc_failure_rate;
220eae870cdSRobert Watson static int malloc_nowait_count;
221eae870cdSRobert Watson static int malloc_failure_count;
222eae870cdSRobert Watson SYSCTL_INT(_debug_malloc, OID_AUTO, failure_rate, CTLFLAG_RW,
223eae870cdSRobert Watson     &malloc_failure_rate, 0, "Every (n) mallocs with M_NOWAIT will fail");
224f2538508SRobert Watson TUNABLE_INT("debug.malloc.failure_rate", &malloc_failure_rate);
225eae870cdSRobert Watson SYSCTL_INT(_debug_malloc, OID_AUTO, failure_count, CTLFLAG_RD,
226eae870cdSRobert Watson     &malloc_failure_count, 0, "Number of imposed M_NOWAIT malloc failures");
227eae870cdSRobert Watson #endif
228eae870cdSRobert Watson 
2291fb14a47SPoul-Henning Kamp int
2301fb14a47SPoul-Henning Kamp malloc_last_fail(void)
2311fb14a47SPoul-Henning Kamp {
2321fb14a47SPoul-Henning Kamp 
2331fb14a47SPoul-Henning Kamp 	return (time_uptime - t_malloc_fail);
2341fb14a47SPoul-Henning Kamp }
2351fb14a47SPoul-Henning Kamp 
236df8bae1dSRodney W. Grimes /*
2370ce3f16dSRobert Watson  * An allocation has succeeded -- update malloc type statistics for the
2380ce3f16dSRobert Watson  * amount of bucket size.  Occurs within a critical section so that the
2390ce3f16dSRobert Watson  * thread isn't preempted and doesn't migrate while updating per-PCU
2400ce3f16dSRobert Watson  * statistics.
2414362fadaSBrian Feldman  */
2424362fadaSBrian Feldman static void
24363a7e0a3SRobert Watson malloc_type_zone_allocated(struct malloc_type *mtp, unsigned long size,
2444362fadaSBrian Feldman     int zindx)
2454362fadaSBrian Feldman {
24663a7e0a3SRobert Watson 	struct malloc_type_internal *mtip;
24763a7e0a3SRobert Watson 	struct malloc_type_stats *mtsp;
24863a7e0a3SRobert Watson 
24963a7e0a3SRobert Watson 	critical_enter();
25063a7e0a3SRobert Watson 	mtip = mtp->ks_handle;
25163a7e0a3SRobert Watson 	mtsp = &mtip->mti_stats[curcpu];
25273864adbSPawel Jakub Dawidek 	if (size > 0) {
25363a7e0a3SRobert Watson 		mtsp->mts_memalloced += size;
25463a7e0a3SRobert Watson 		mtsp->mts_numallocs++;
25573864adbSPawel Jakub Dawidek 	}
2564362fadaSBrian Feldman 	if (zindx != -1)
25763a7e0a3SRobert Watson 		mtsp->mts_size |= 1 << zindx;
25863a7e0a3SRobert Watson 	critical_exit();
2594362fadaSBrian Feldman }
2604362fadaSBrian Feldman 
2614362fadaSBrian Feldman void
26263a7e0a3SRobert Watson malloc_type_allocated(struct malloc_type *mtp, unsigned long size)
2634362fadaSBrian Feldman {
26463a7e0a3SRobert Watson 
26573864adbSPawel Jakub Dawidek 	if (size > 0)
26663a7e0a3SRobert Watson 		malloc_type_zone_allocated(mtp, size, -1);
2674362fadaSBrian Feldman }
2684362fadaSBrian Feldman 
2694362fadaSBrian Feldman /*
2703805385eSRobert Watson  * A free operation has occurred -- update malloc type statistics for the
2710ce3f16dSRobert Watson  * amount of the bucket size.  Occurs within a critical section so that the
2720ce3f16dSRobert Watson  * thread isn't preempted and doesn't migrate while updating per-CPU
2730ce3f16dSRobert Watson  * statistics.
2744362fadaSBrian Feldman  */
2754362fadaSBrian Feldman void
27663a7e0a3SRobert Watson malloc_type_freed(struct malloc_type *mtp, unsigned long size)
2774362fadaSBrian Feldman {
27863a7e0a3SRobert Watson 	struct malloc_type_internal *mtip;
27963a7e0a3SRobert Watson 	struct malloc_type_stats *mtsp;
28063a7e0a3SRobert Watson 
28163a7e0a3SRobert Watson 	critical_enter();
28263a7e0a3SRobert Watson 	mtip = mtp->ks_handle;
28363a7e0a3SRobert Watson 	mtsp = &mtip->mti_stats[curcpu];
28463a7e0a3SRobert Watson 	mtsp->mts_memfreed += size;
28563a7e0a3SRobert Watson 	mtsp->mts_numfrees++;
28663a7e0a3SRobert Watson 	critical_exit();
2874362fadaSBrian Feldman }
2884362fadaSBrian Feldman 
2894362fadaSBrian Feldman /*
2901c7c3c6aSMatthew Dillon  *	malloc:
2911c7c3c6aSMatthew Dillon  *
2921c7c3c6aSMatthew Dillon  *	Allocate a block of memory.
2931c7c3c6aSMatthew Dillon  *
2941c7c3c6aSMatthew Dillon  *	If M_NOWAIT is set, this routine will not block and return NULL if
2951c7c3c6aSMatthew Dillon  *	the allocation fails.
296df8bae1dSRodney W. Grimes  */
297df8bae1dSRodney W. Grimes void *
29863a7e0a3SRobert Watson malloc(unsigned long size, struct malloc_type *mtp, int flags)
299df8bae1dSRodney W. Grimes {
3006f267175SJeff Roberson 	int indx;
3018355f576SJeff Roberson 	caddr_t va;
3028355f576SJeff Roberson 	uma_zone_t zone;
303099a0e58SBosko Milekic 	uma_keg_t keg;
304847a2a17SPawel Jakub Dawidek #if defined(DIAGNOSTIC) || defined(DEBUG_REDZONE)
3054db4f5c8SPoul-Henning Kamp 	unsigned long osize = size;
3064db4f5c8SPoul-Henning Kamp #endif
307df8bae1dSRodney W. Grimes 
308194a0abfSPoul-Henning Kamp #ifdef INVARIANTS
309d3c11994SPoul-Henning Kamp 	/*
31023198357SRuslan Ermilov 	 * Check that exactly one of M_WAITOK or M_NOWAIT is specified.
311d3c11994SPoul-Henning Kamp 	 */
31223198357SRuslan Ermilov 	indx = flags & (M_WAITOK | M_NOWAIT);
313d3c11994SPoul-Henning Kamp 	if (indx != M_NOWAIT && indx != M_WAITOK) {
314d3c11994SPoul-Henning Kamp 		static	struct timeval lasterr;
315d3c11994SPoul-Henning Kamp 		static	int curerr, once;
316d3c11994SPoul-Henning Kamp 		if (once == 0 && ppsratecheck(&lasterr, &curerr, 1)) {
317d3c11994SPoul-Henning Kamp 			printf("Bad malloc flags: %x\n", indx);
3182d50560aSMarcel Moolenaar 			kdb_backtrace();
319d3c11994SPoul-Henning Kamp 			flags |= M_WAITOK;
320d3c11994SPoul-Henning Kamp 			once++;
321d3c11994SPoul-Henning Kamp 		}
322d3c11994SPoul-Henning Kamp 	}
323194a0abfSPoul-Henning Kamp #endif
324eae870cdSRobert Watson #ifdef MALLOC_MAKE_FAILURES
325eae870cdSRobert Watson 	if ((flags & M_NOWAIT) && (malloc_failure_rate != 0)) {
326eae870cdSRobert Watson 		atomic_add_int(&malloc_nowait_count, 1);
327eae870cdSRobert Watson 		if ((malloc_nowait_count % malloc_failure_rate) == 0) {
328eae870cdSRobert Watson 			atomic_add_int(&malloc_failure_count, 1);
3293f6ee876SPoul-Henning Kamp 			t_malloc_fail = time_uptime;
330eae870cdSRobert Watson 			return (NULL);
331eae870cdSRobert Watson 		}
332eae870cdSRobert Watson 	}
333eae870cdSRobert Watson #endif
334d3c11994SPoul-Henning Kamp 	if (flags & M_WAITOK)
335b40ce416SJulian Elischer 		KASSERT(curthread->td_intr_nesting_level == 0,
336a163d034SWarner Losh 		   ("malloc(M_WAITOK) in interrupt context"));
337e4eb384bSBosko Milekic 
338e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
339d362c40dSPawel Jakub Dawidek 	if (memguard_cmp(mtp))
340e4eb384bSBosko Milekic 		return memguard_alloc(size, flags);
341e4eb384bSBosko Milekic #endif
342e4eb384bSBosko Milekic 
343847a2a17SPawel Jakub Dawidek #ifdef DEBUG_REDZONE
344847a2a17SPawel Jakub Dawidek 	size = redzone_size_ntor(size);
345847a2a17SPawel Jakub Dawidek #endif
346847a2a17SPawel Jakub Dawidek 
3478355f576SJeff Roberson 	if (size <= KMEM_ZMAX) {
3486f267175SJeff Roberson 		if (size & KMEM_ZMASK)
3496f267175SJeff Roberson 			size = (size & ~KMEM_ZMASK) + KMEM_ZBASE;
3506f267175SJeff Roberson 		indx = kmemsize[size >> KMEM_ZSHIFT];
3516f267175SJeff Roberson 		zone = kmemzones[indx].kz_zone;
352099a0e58SBosko Milekic 		keg = zone->uz_keg;
3536f267175SJeff Roberson #ifdef MALLOC_PROFILE
3546f267175SJeff Roberson 		krequests[size >> KMEM_ZSHIFT]++;
3556f267175SJeff Roberson #endif
3568355f576SJeff Roberson 		va = uma_zalloc(zone, flags);
3574362fadaSBrian Feldman 		if (va != NULL)
358099a0e58SBosko Milekic 			size = keg->uk_size;
35963a7e0a3SRobert Watson 		malloc_type_zone_allocated(mtp, va == NULL ? 0 : size, indx);
3608355f576SJeff Roberson 	} else {
3616f267175SJeff Roberson 		size = roundup(size, PAGE_SIZE);
3628355f576SJeff Roberson 		zone = NULL;
363099a0e58SBosko Milekic 		keg = NULL;
3648355f576SJeff Roberson 		va = uma_large_malloc(size, flags);
36563a7e0a3SRobert Watson 		malloc_type_allocated(mtp, va == NULL ? 0 : size);
366df8bae1dSRodney W. Grimes 	}
3671282e9acSPoul-Henning Kamp 	if (flags & M_WAITOK)
368a163d034SWarner Losh 		KASSERT(va != NULL, ("malloc(M_WAITOK) returned NULL"));
3691282e9acSPoul-Henning Kamp 	else if (va == NULL)
3701fb14a47SPoul-Henning Kamp 		t_malloc_fail = time_uptime;
3714db4f5c8SPoul-Henning Kamp #ifdef DIAGNOSTIC
3721282e9acSPoul-Henning Kamp 	if (va != NULL && !(flags & M_ZERO)) {
3734db4f5c8SPoul-Henning Kamp 		memset(va, 0x70, osize);
3744db4f5c8SPoul-Henning Kamp 	}
3754db4f5c8SPoul-Henning Kamp #endif
376847a2a17SPawel Jakub Dawidek #ifdef DEBUG_REDZONE
377847a2a17SPawel Jakub Dawidek 	if (va != NULL)
378847a2a17SPawel Jakub Dawidek 		va = redzone_setup(va, osize);
379847a2a17SPawel Jakub Dawidek #endif
380df8bae1dSRodney W. Grimes 	return ((void *) va);
381df8bae1dSRodney W. Grimes }
382df8bae1dSRodney W. Grimes 
383df8bae1dSRodney W. Grimes /*
3841c7c3c6aSMatthew Dillon  *	free:
3851c7c3c6aSMatthew Dillon  *
386df8bae1dSRodney W. Grimes  *	Free a block of memory allocated by malloc.
3871c7c3c6aSMatthew Dillon  *
3881c7c3c6aSMatthew Dillon  *	This routine may not block.
389df8bae1dSRodney W. Grimes  */
390df8bae1dSRodney W. Grimes void
39163a7e0a3SRobert Watson free(void *addr, struct malloc_type *mtp)
392df8bae1dSRodney W. Grimes {
39399571dc3SJeff Roberson 	uma_slab_t slab;
39499571dc3SJeff Roberson 	u_long size;
395254c6cb3SPoul-Henning Kamp 
39644a8ff31SArchie Cobbs 	/* free(NULL, ...) does nothing */
39744a8ff31SArchie Cobbs 	if (addr == NULL)
39844a8ff31SArchie Cobbs 		return;
39944a8ff31SArchie Cobbs 
400e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
401d362c40dSPawel Jakub Dawidek 	if (memguard_cmp(mtp)) {
402e4eb384bSBosko Milekic 		memguard_free(addr);
403e4eb384bSBosko Milekic 		return;
404e4eb384bSBosko Milekic 	}
405e4eb384bSBosko Milekic #endif
406e4eb384bSBosko Milekic 
407847a2a17SPawel Jakub Dawidek #ifdef DEBUG_REDZONE
408847a2a17SPawel Jakub Dawidek 	redzone_check(addr);
409847a2a17SPawel Jakub Dawidek 	addr = redzone_addr_ntor(addr);
410847a2a17SPawel Jakub Dawidek #endif
411847a2a17SPawel Jakub Dawidek 
4128355f576SJeff Roberson 	size = 0;
41369ef67f9SJason Evans 
41499571dc3SJeff Roberson 	slab = vtoslab((vm_offset_t)addr & (~UMA_SLAB_MASK));
4158355f576SJeff Roberson 
4168355f576SJeff Roberson 	if (slab == NULL)
4176f267175SJeff Roberson 		panic("free: address %p(%p) has not been allocated.\n",
41899571dc3SJeff Roberson 		    addr, (void *)((u_long)addr & (~UMA_SLAB_MASK)));
41999571dc3SJeff Roberson 
4208355f576SJeff Roberson 
4218355f576SJeff Roberson 	if (!(slab->us_flags & UMA_SLAB_MALLOC)) {
4228f70816cSJeff Roberson #ifdef INVARIANTS
42363a7e0a3SRobert Watson 		struct malloc_type **mtpp = addr;
4248f70816cSJeff Roberson #endif
425099a0e58SBosko Milekic 		size = slab->us_keg->uk_size;
4268f70816cSJeff Roberson #ifdef INVARIANTS
4278f70816cSJeff Roberson 		/*
4288f70816cSJeff Roberson 		 * Cache a pointer to the malloc_type that most recently freed
4298f70816cSJeff Roberson 		 * this memory here.  This way we know who is most likely to
4308f70816cSJeff Roberson 		 * have stepped on it later.
4318f70816cSJeff Roberson 		 *
4328f70816cSJeff Roberson 		 * This code assumes that size is a multiple of 8 bytes for
4338f70816cSJeff Roberson 		 * 64 bit machines
4348f70816cSJeff Roberson 		 */
43563a7e0a3SRobert Watson 		mtpp = (struct malloc_type **)
43663a7e0a3SRobert Watson 		    ((unsigned long)mtpp & ~UMA_ALIGN_PTR);
43763a7e0a3SRobert Watson 		mtpp += (size - sizeof(struct malloc_type *)) /
4388f70816cSJeff Roberson 		    sizeof(struct malloc_type *);
43963a7e0a3SRobert Watson 		*mtpp = mtp;
4408f70816cSJeff Roberson #endif
441099a0e58SBosko Milekic 		uma_zfree_arg(LIST_FIRST(&slab->us_keg->uk_zones), addr, slab);
44214bf02f8SJohn Dyson 	} else {
4438355f576SJeff Roberson 		size = slab->us_size;
4448355f576SJeff Roberson 		uma_large_free(slab);
44514bf02f8SJohn Dyson 	}
44663a7e0a3SRobert Watson 	malloc_type_freed(mtp, size);
447df8bae1dSRodney W. Grimes }
448df8bae1dSRodney W. Grimes 
449df8bae1dSRodney W. Grimes /*
45044a8ff31SArchie Cobbs  *	realloc: change the size of a memory block
45144a8ff31SArchie Cobbs  */
45244a8ff31SArchie Cobbs void *
45363a7e0a3SRobert Watson realloc(void *addr, unsigned long size, struct malloc_type *mtp, int flags)
45444a8ff31SArchie Cobbs {
4558355f576SJeff Roberson 	uma_slab_t slab;
45644a8ff31SArchie Cobbs 	unsigned long alloc;
45744a8ff31SArchie Cobbs 	void *newaddr;
45844a8ff31SArchie Cobbs 
45944a8ff31SArchie Cobbs 	/* realloc(NULL, ...) is equivalent to malloc(...) */
46044a8ff31SArchie Cobbs 	if (addr == NULL)
46163a7e0a3SRobert Watson 		return (malloc(size, mtp, flags));
46263a7e0a3SRobert Watson 
46363a7e0a3SRobert Watson 	/*
46463a7e0a3SRobert Watson 	 * XXX: Should report free of old memory and alloc of new memory to
46563a7e0a3SRobert Watson 	 * per-CPU stats.
46663a7e0a3SRobert Watson 	 */
46744a8ff31SArchie Cobbs 
468e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
469d362c40dSPawel Jakub Dawidek if (memguard_cmp(mtp)) {
470e4eb384bSBosko Milekic 	slab = NULL;
471e4eb384bSBosko Milekic 	alloc = size;
472e4eb384bSBosko Milekic } else {
473e4eb384bSBosko Milekic #endif
474e4eb384bSBosko Milekic 
475847a2a17SPawel Jakub Dawidek #ifdef DEBUG_REDZONE
476847a2a17SPawel Jakub Dawidek 	slab = NULL;
477847a2a17SPawel Jakub Dawidek 	alloc = redzone_get_size(addr);
478847a2a17SPawel Jakub Dawidek #else
47999571dc3SJeff Roberson 	slab = vtoslab((vm_offset_t)addr & ~(UMA_SLAB_MASK));
4808355f576SJeff Roberson 
48144a8ff31SArchie Cobbs 	/* Sanity check */
4828355f576SJeff Roberson 	KASSERT(slab != NULL,
48344a8ff31SArchie Cobbs 	    ("realloc: address %p out of range", (void *)addr));
48444a8ff31SArchie Cobbs 
48544a8ff31SArchie Cobbs 	/* Get the size of the original block */
486619f2841SPawel Jakub Dawidek 	if (!(slab->us_flags & UMA_SLAB_MALLOC))
487099a0e58SBosko Milekic 		alloc = slab->us_keg->uk_size;
4888355f576SJeff Roberson 	else
4898355f576SJeff Roberson 		alloc = slab->us_size;
49044a8ff31SArchie Cobbs 
49144a8ff31SArchie Cobbs 	/* Reuse the original block if appropriate */
49244a8ff31SArchie Cobbs 	if (size <= alloc
49344a8ff31SArchie Cobbs 	    && (size > (alloc >> REALLOC_FRACTION) || alloc == MINALLOCSIZE))
49444a8ff31SArchie Cobbs 		return (addr);
495847a2a17SPawel Jakub Dawidek #endif /* !DEBUG_REDZONE */
49644a8ff31SArchie Cobbs 
497e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
498e4eb384bSBosko Milekic }
499e4eb384bSBosko Milekic #endif
500e4eb384bSBosko Milekic 
50144a8ff31SArchie Cobbs 	/* Allocate a new, bigger (or smaller) block */
50263a7e0a3SRobert Watson 	if ((newaddr = malloc(size, mtp, flags)) == NULL)
50344a8ff31SArchie Cobbs 		return (NULL);
50444a8ff31SArchie Cobbs 
50544a8ff31SArchie Cobbs 	/* Copy over original contents */
50644a8ff31SArchie Cobbs 	bcopy(addr, newaddr, min(size, alloc));
50763a7e0a3SRobert Watson 	free(addr, mtp);
50844a8ff31SArchie Cobbs 	return (newaddr);
50944a8ff31SArchie Cobbs }
51044a8ff31SArchie Cobbs 
51144a8ff31SArchie Cobbs /*
51244a8ff31SArchie Cobbs  *	reallocf: same as realloc() but free memory on failure.
51344a8ff31SArchie Cobbs  */
51444a8ff31SArchie Cobbs void *
51563a7e0a3SRobert Watson reallocf(void *addr, unsigned long size, struct malloc_type *mtp, int flags)
51644a8ff31SArchie Cobbs {
51744a8ff31SArchie Cobbs 	void *mem;
51844a8ff31SArchie Cobbs 
51963a7e0a3SRobert Watson 	if ((mem = realloc(addr, size, mtp, flags)) == NULL)
52063a7e0a3SRobert Watson 		free(addr, mtp);
52144a8ff31SArchie Cobbs 	return (mem);
52244a8ff31SArchie Cobbs }
52344a8ff31SArchie Cobbs 
52444a8ff31SArchie Cobbs /*
525df8bae1dSRodney W. Grimes  * Initialize the kernel memory allocator
526df8bae1dSRodney W. Grimes  */
5272b14f991SJulian Elischer /* ARGSUSED*/
5282b14f991SJulian Elischer static void
52987efd4d5SRobert Watson kmeminit(void *dummy)
530df8bae1dSRodney W. Grimes {
5316f267175SJeff Roberson 	u_int8_t indx;
53227b8623fSDavid Greenman 	u_long mem_size;
5338355f576SJeff Roberson 	int i;
5348a58a9f6SJohn Dyson 
5356008862bSJohn Baldwin 	mtx_init(&malloc_mtx, "malloc", NULL, MTX_DEF);
53669ef67f9SJason Evans 
5378a58a9f6SJohn Dyson 	/*
5388a58a9f6SJohn Dyson 	 * Try to auto-tune the kernel memory size, so that it is
5398a58a9f6SJohn Dyson 	 * more applicable for a wider range of machine sizes.
5408a58a9f6SJohn Dyson 	 * On an X86, a VM_KMEM_SIZE_SCALE value of 4 is good, while
5418a58a9f6SJohn Dyson 	 * a VM_KMEM_SIZE of 12MB is a fair compromise.  The
5428a58a9f6SJohn Dyson 	 * VM_KMEM_SIZE_MAX is dependent on the maximum KVA space
5438a58a9f6SJohn Dyson 	 * available, and on an X86 with a total KVA space of 256MB,
5448a58a9f6SJohn Dyson 	 * try to keep VM_KMEM_SIZE_MAX at 80MB or below.
5458a58a9f6SJohn Dyson 	 *
5468a58a9f6SJohn Dyson 	 * Note that the kmem_map is also used by the zone allocator,
5478a58a9f6SJohn Dyson 	 * so make sure that there is enough space.
5488a58a9f6SJohn Dyson 	 */
549099a0e58SBosko Milekic 	vm_kmem_size = VM_KMEM_SIZE + nmbclusters * PAGE_SIZE;
5502feb50bfSAttilio Rao 	mem_size = cnt.v_page_count;
5518a58a9f6SJohn Dyson 
5528a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_SCALE)
553479439b4SDag-Erling Smørgrav 	vm_kmem_size_scale = VM_KMEM_SIZE_SCALE;
5548a58a9f6SJohn Dyson #endif
555479439b4SDag-Erling Smørgrav 	TUNABLE_INT_FETCH("vm.kmem_size_scale", &vm_kmem_size_scale);
556479439b4SDag-Erling Smørgrav 	if (vm_kmem_size_scale > 0 &&
557479439b4SDag-Erling Smørgrav 	    (mem_size / vm_kmem_size_scale) > (vm_kmem_size / PAGE_SIZE))
558479439b4SDag-Erling Smørgrav 		vm_kmem_size = (mem_size / vm_kmem_size_scale) * PAGE_SIZE;
5598a58a9f6SJohn Dyson 
5600e5179e4SStephane E. Potvin #if defined(VM_KMEM_SIZE_MIN)
5610e5179e4SStephane E. Potvin 	vm_kmem_size_min = VM_KMEM_SIZE_MIN;
5620e5179e4SStephane E. Potvin #endif
5630e5179e4SStephane E. Potvin 	TUNABLE_INT_FETCH("vm.kmem_size_min", &vm_kmem_size_min);
5640e5179e4SStephane E. Potvin 	if (vm_kmem_size_min > 0 && vm_kmem_size < vm_kmem_size_min) {
5650e5179e4SStephane E. Potvin 		vm_kmem_size = vm_kmem_size_min;
5660e5179e4SStephane E. Potvin 	}
5670e5179e4SStephane E. Potvin 
5688a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_MAX)
569479439b4SDag-Erling Smørgrav 	vm_kmem_size_max = VM_KMEM_SIZE_MAX;
5708a58a9f6SJohn Dyson #endif
571479439b4SDag-Erling Smørgrav 	TUNABLE_INT_FETCH("vm.kmem_size_max", &vm_kmem_size_max);
572479439b4SDag-Erling Smørgrav 	if (vm_kmem_size_max > 0 && vm_kmem_size >= vm_kmem_size_max)
573479439b4SDag-Erling Smørgrav 		vm_kmem_size = vm_kmem_size_max;
5748a58a9f6SJohn Dyson 
5758de6e8e1SMike Smith 	/* Allow final override from the kernel environment */
57684344f9fSDag-Erling Smørgrav #ifndef BURN_BRIDGES
57784344f9fSDag-Erling Smørgrav 	if (TUNABLE_INT_FETCH("kern.vm.kmem.size", &vm_kmem_size) != 0)
57884344f9fSDag-Erling Smørgrav 		printf("kern.vm.kmem.size is now called vm.kmem_size!\n");
57984344f9fSDag-Erling Smørgrav #endif
58084344f9fSDag-Erling Smørgrav 	TUNABLE_INT_FETCH("vm.kmem_size", &vm_kmem_size);
5818de6e8e1SMike Smith 
58227b8623fSDavid Greenman 	/*
58327b8623fSDavid Greenman 	 * Limit kmem virtual size to twice the physical memory.
58427b8623fSDavid Greenman 	 * This allows for kmem map sparseness, but limits the size
58527b8623fSDavid Greenman 	 * to something sane. Be careful to not overflow the 32bit
58627b8623fSDavid Greenman 	 * ints while doing the check.
58727b8623fSDavid Greenman 	 */
5882feb50bfSAttilio Rao 	if (((vm_kmem_size / 2) / PAGE_SIZE) > cnt.v_page_count)
5892feb50bfSAttilio Rao 		vm_kmem_size = 2 * cnt.v_page_count * PAGE_SIZE;
5908a58a9f6SJohn Dyson 
59108442f8aSBosko Milekic 	/*
592347194c1SMike Silbersack 	 * Tune settings based on the kernel map's size at this time.
593347194c1SMike Silbersack 	 */
594347194c1SMike Silbersack 	init_param3(vm_kmem_size / PAGE_SIZE);
595347194c1SMike Silbersack 
596df8bae1dSRodney W. Grimes 	kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase,
597099a0e58SBosko Milekic 		(vm_offset_t *)&kmemlimit, vm_kmem_size);
5983075778bSJohn Dyson 	kmem_map->system_map = 1;
5998355f576SJeff Roberson 
600e4eb384bSBosko Milekic #ifdef DEBUG_MEMGUARD
601e4eb384bSBosko Milekic 	/*
602e4eb384bSBosko Milekic 	 * Initialize MemGuard if support compiled in.  MemGuard is a
603e4eb384bSBosko Milekic 	 * replacement allocator used for detecting tamper-after-free
604e4eb384bSBosko Milekic 	 * scenarios as they occur.  It is only used for debugging.
605e4eb384bSBosko Milekic 	 */
606e4eb384bSBosko Milekic 	vm_memguard_divisor = 10;
607d362c40dSPawel Jakub Dawidek 	TUNABLE_INT_FETCH("vm.memguard.divisor", &vm_memguard_divisor);
608e4eb384bSBosko Milekic 
609e4eb384bSBosko Milekic 	/* Pick a conservative value if provided value sucks. */
610e4eb384bSBosko Milekic 	if ((vm_memguard_divisor <= 0) ||
611e4eb384bSBosko Milekic 	    ((vm_kmem_size / vm_memguard_divisor) == 0))
612e4eb384bSBosko Milekic 		vm_memguard_divisor = 10;
613e4eb384bSBosko Milekic 	memguard_init(kmem_map, vm_kmem_size / vm_memguard_divisor);
614e4eb384bSBosko Milekic #endif
615e4eb384bSBosko Milekic 
61699571dc3SJeff Roberson 	uma_startup2();
6178355f576SJeff Roberson 
61863a7e0a3SRobert Watson 	mt_zone = uma_zcreate("mt_zone", sizeof(struct malloc_type_internal),
61963a7e0a3SRobert Watson #ifdef INVARIANTS
62063a7e0a3SRobert Watson 	    mtrash_ctor, mtrash_dtor, mtrash_init, mtrash_fini,
62163a7e0a3SRobert Watson #else
62263a7e0a3SRobert Watson 	    NULL, NULL, NULL, NULL,
62363a7e0a3SRobert Watson #endif
62463a7e0a3SRobert Watson 	    UMA_ALIGN_PTR, UMA_ZONE_MALLOC);
6256f267175SJeff Roberson 	for (i = 0, indx = 0; kmemzones[indx].kz_size != 0; indx++) {
6266f267175SJeff Roberson 		int size = kmemzones[indx].kz_size;
6276f267175SJeff Roberson 		char *name = kmemzones[indx].kz_name;
6288355f576SJeff Roberson 
6298efc4effSJeff Roberson 		kmemzones[indx].kz_zone = uma_zcreate(name, size,
6308efc4effSJeff Roberson #ifdef INVARIANTS
6318f70816cSJeff Roberson 		    mtrash_ctor, mtrash_dtor, mtrash_init, mtrash_fini,
6328efc4effSJeff Roberson #else
6338efc4effSJeff Roberson 		    NULL, NULL, NULL, NULL,
6348efc4effSJeff Roberson #endif
6358efc4effSJeff Roberson 		    UMA_ALIGN_PTR, UMA_ZONE_MALLOC);
6366f267175SJeff Roberson 
6378355f576SJeff Roberson 		for (;i <= size; i+= KMEM_ZBASE)
6386f267175SJeff Roberson 			kmemsize[i >> KMEM_ZSHIFT] = indx;
6398355f576SJeff Roberson 
640df8bae1dSRodney W. Grimes 	}
641254c6cb3SPoul-Henning Kamp }
642254c6cb3SPoul-Henning Kamp 
643db669378SPeter Wemm void
64487efd4d5SRobert Watson malloc_init(void *data)
645254c6cb3SPoul-Henning Kamp {
64663a7e0a3SRobert Watson 	struct malloc_type_internal *mtip;
64763a7e0a3SRobert Watson 	struct malloc_type *mtp;
64863a7e0a3SRobert Watson 
6492feb50bfSAttilio Rao 	KASSERT(cnt.v_page_count != 0, ("malloc_register before vm_init"));
65063a7e0a3SRobert Watson 
65163a7e0a3SRobert Watson 	mtp = data;
65263a7e0a3SRobert Watson 	mtip = uma_zalloc(mt_zone, M_WAITOK | M_ZERO);
65363a7e0a3SRobert Watson 	mtp->ks_handle = mtip;
654254c6cb3SPoul-Henning Kamp 
6556f267175SJeff Roberson 	mtx_lock(&malloc_mtx);
65663a7e0a3SRobert Watson 	mtp->ks_next = kmemstatistics;
65763a7e0a3SRobert Watson 	kmemstatistics = mtp;
658cd814b26SRobert Watson 	kmemcount++;
6596f267175SJeff Roberson 	mtx_unlock(&malloc_mtx);
660df8bae1dSRodney W. Grimes }
661db669378SPeter Wemm 
662db669378SPeter Wemm void
66387efd4d5SRobert Watson malloc_uninit(void *data)
664db669378SPeter Wemm {
66563a7e0a3SRobert Watson 	struct malloc_type_internal *mtip;
6662a143d5bSPawel Jakub Dawidek 	struct malloc_type_stats *mtsp;
66763a7e0a3SRobert Watson 	struct malloc_type *mtp, *temp;
66845d48bdaSPaul Saab 	uma_slab_t slab;
6692a143d5bSPawel Jakub Dawidek 	long temp_allocs, temp_bytes;
6702a143d5bSPawel Jakub Dawidek 	int i;
671db669378SPeter Wemm 
67263a7e0a3SRobert Watson 	mtp = data;
67363a7e0a3SRobert Watson 	KASSERT(mtp->ks_handle != NULL, ("malloc_deregister: cookie NULL"));
6746f267175SJeff Roberson 	mtx_lock(&malloc_mtx);
67563a7e0a3SRobert Watson 	mtip = mtp->ks_handle;
67663a7e0a3SRobert Watson 	mtp->ks_handle = NULL;
67763a7e0a3SRobert Watson 	if (mtp != kmemstatistics) {
67863a7e0a3SRobert Watson 		for (temp = kmemstatistics; temp != NULL;
67963a7e0a3SRobert Watson 		    temp = temp->ks_next) {
68063a7e0a3SRobert Watson 			if (temp->ks_next == mtp)
68163a7e0a3SRobert Watson 				temp->ks_next = mtp->ks_next;
682db669378SPeter Wemm 		}
68363a7e0a3SRobert Watson 	} else
68463a7e0a3SRobert Watson 		kmemstatistics = mtp->ks_next;
685cd814b26SRobert Watson 	kmemcount--;
6866f267175SJeff Roberson 	mtx_unlock(&malloc_mtx);
6872a143d5bSPawel Jakub Dawidek 
6882a143d5bSPawel Jakub Dawidek 	/*
6892a143d5bSPawel Jakub Dawidek 	 * Look for memory leaks.
6902a143d5bSPawel Jakub Dawidek 	 */
6912a143d5bSPawel Jakub Dawidek 	temp_allocs = temp_bytes = 0;
6922a143d5bSPawel Jakub Dawidek 	for (i = 0; i < MAXCPU; i++) {
6932a143d5bSPawel Jakub Dawidek 		mtsp = &mtip->mti_stats[i];
6942a143d5bSPawel Jakub Dawidek 		temp_allocs += mtsp->mts_numallocs;
6952a143d5bSPawel Jakub Dawidek 		temp_allocs -= mtsp->mts_numfrees;
6962a143d5bSPawel Jakub Dawidek 		temp_bytes += mtsp->mts_memalloced;
6972a143d5bSPawel Jakub Dawidek 		temp_bytes -= mtsp->mts_memfreed;
6982a143d5bSPawel Jakub Dawidek 	}
6992a143d5bSPawel Jakub Dawidek 	if (temp_allocs > 0 || temp_bytes > 0) {
7002a143d5bSPawel Jakub Dawidek 		printf("Warning: memory type %s leaked memory on destroy "
7012a143d5bSPawel Jakub Dawidek 		    "(%ld allocations, %ld bytes leaked).\n", mtp->ks_shortdesc,
7022a143d5bSPawel Jakub Dawidek 		    temp_allocs, temp_bytes);
7032a143d5bSPawel Jakub Dawidek 	}
7042a143d5bSPawel Jakub Dawidek 
70545d48bdaSPaul Saab 	slab = vtoslab((vm_offset_t) mtip & (~UMA_SLAB_MASK));
70645d48bdaSPaul Saab 	uma_zfree_arg(mt_zone, mtip, slab);
707db669378SPeter Wemm }
7086f267175SJeff Roberson 
709d362c40dSPawel Jakub Dawidek struct malloc_type *
710d362c40dSPawel Jakub Dawidek malloc_desc2type(const char *desc)
711d362c40dSPawel Jakub Dawidek {
712d362c40dSPawel Jakub Dawidek 	struct malloc_type *mtp;
713d362c40dSPawel Jakub Dawidek 
714d362c40dSPawel Jakub Dawidek 	mtx_assert(&malloc_mtx, MA_OWNED);
715d362c40dSPawel Jakub Dawidek 	for (mtp = kmemstatistics; mtp != NULL; mtp = mtp->ks_next) {
716d362c40dSPawel Jakub Dawidek 		if (strcmp(mtp->ks_shortdesc, desc) == 0)
717d362c40dSPawel Jakub Dawidek 			return (mtp);
718d362c40dSPawel Jakub Dawidek 	}
719d362c40dSPawel Jakub Dawidek 	return (NULL);
720d362c40dSPawel Jakub Dawidek }
721d362c40dSPawel Jakub Dawidek 
7226f267175SJeff Roberson static int
723cd814b26SRobert Watson sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS)
724cd814b26SRobert Watson {
725cd814b26SRobert Watson 	struct malloc_type_stream_header mtsh;
726cd814b26SRobert Watson 	struct malloc_type_internal *mtip;
727cd814b26SRobert Watson 	struct malloc_type_header mth;
728cd814b26SRobert Watson 	struct malloc_type *mtp;
729cd814b26SRobert Watson 	int buflen, count, error, i;
730cd814b26SRobert Watson 	struct sbuf sbuf;
731cd814b26SRobert Watson 	char *buffer;
732cd814b26SRobert Watson 
733cd814b26SRobert Watson 	mtx_lock(&malloc_mtx);
734cd814b26SRobert Watson restart:
735cd814b26SRobert Watson 	mtx_assert(&malloc_mtx, MA_OWNED);
736cd814b26SRobert Watson 	count = kmemcount;
737cd814b26SRobert Watson 	mtx_unlock(&malloc_mtx);
738cd814b26SRobert Watson 	buflen = sizeof(mtsh) + count * (sizeof(mth) +
739cd814b26SRobert Watson 	    sizeof(struct malloc_type_stats) * MAXCPU) + 1;
740cd814b26SRobert Watson 	buffer = malloc(buflen, M_TEMP, M_WAITOK | M_ZERO);
741cd814b26SRobert Watson 	mtx_lock(&malloc_mtx);
742cd814b26SRobert Watson 	if (count < kmemcount) {
743cd814b26SRobert Watson 		free(buffer, M_TEMP);
744cd814b26SRobert Watson 		goto restart;
745cd814b26SRobert Watson 	}
746cd814b26SRobert Watson 
747cd814b26SRobert Watson 	sbuf_new(&sbuf, buffer, buflen, SBUF_FIXEDLEN);
748cd814b26SRobert Watson 
749cd814b26SRobert Watson 	/*
750cd814b26SRobert Watson 	 * Insert stream header.
751cd814b26SRobert Watson 	 */
752cd814b26SRobert Watson 	bzero(&mtsh, sizeof(mtsh));
753cd814b26SRobert Watson 	mtsh.mtsh_version = MALLOC_TYPE_STREAM_VERSION;
754cd814b26SRobert Watson 	mtsh.mtsh_maxcpus = MAXCPU;
755cd814b26SRobert Watson 	mtsh.mtsh_count = kmemcount;
756cd814b26SRobert Watson 	if (sbuf_bcat(&sbuf, &mtsh, sizeof(mtsh)) < 0) {
757cd814b26SRobert Watson 		mtx_unlock(&malloc_mtx);
758cd814b26SRobert Watson 		error = ENOMEM;
759cd814b26SRobert Watson 		goto out;
760cd814b26SRobert Watson 	}
761cd814b26SRobert Watson 
762cd814b26SRobert Watson 	/*
763cd814b26SRobert Watson 	 * Insert alternating sequence of type headers and type statistics.
764cd814b26SRobert Watson 	 */
765cd814b26SRobert Watson 	for (mtp = kmemstatistics; mtp != NULL; mtp = mtp->ks_next) {
766cd814b26SRobert Watson 		mtip = (struct malloc_type_internal *)mtp->ks_handle;
767cd814b26SRobert Watson 
768cd814b26SRobert Watson 		/*
769cd814b26SRobert Watson 		 * Insert type header.
770cd814b26SRobert Watson 		 */
771cd814b26SRobert Watson 		bzero(&mth, sizeof(mth));
772cd814b26SRobert Watson 		strlcpy(mth.mth_name, mtp->ks_shortdesc, MALLOC_MAX_NAME);
773cd814b26SRobert Watson 		if (sbuf_bcat(&sbuf, &mth, sizeof(mth)) < 0) {
774cd814b26SRobert Watson 			mtx_unlock(&malloc_mtx);
775cd814b26SRobert Watson 			error = ENOMEM;
776cd814b26SRobert Watson 			goto out;
777cd814b26SRobert Watson 		}
778cd814b26SRobert Watson 
779cd814b26SRobert Watson 		/*
780cd814b26SRobert Watson 		 * Insert type statistics for each CPU.
781cd814b26SRobert Watson 		 */
782cd814b26SRobert Watson 		for (i = 0; i < MAXCPU; i++) {
783cd814b26SRobert Watson 			if (sbuf_bcat(&sbuf, &mtip->mti_stats[i],
784cd814b26SRobert Watson 			    sizeof(mtip->mti_stats[i])) < 0) {
785cd814b26SRobert Watson 				mtx_unlock(&malloc_mtx);
786cd814b26SRobert Watson 				error = ENOMEM;
787cd814b26SRobert Watson 				goto out;
788cd814b26SRobert Watson 			}
789cd814b26SRobert Watson 		}
790cd814b26SRobert Watson 	}
791cd814b26SRobert Watson 	mtx_unlock(&malloc_mtx);
792cd814b26SRobert Watson 	sbuf_finish(&sbuf);
793cd814b26SRobert Watson 	error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf));
794cd814b26SRobert Watson out:
795cd814b26SRobert Watson 	sbuf_delete(&sbuf);
796cd814b26SRobert Watson 	free(buffer, M_TEMP);
797cd814b26SRobert Watson 	return (error);
798cd814b26SRobert Watson }
799cd814b26SRobert Watson 
800cd814b26SRobert Watson SYSCTL_PROC(_kern, OID_AUTO, malloc_stats, CTLFLAG_RD|CTLTYPE_STRUCT,
801cd814b26SRobert Watson     0, 0, sysctl_kern_malloc_stats, "s,malloc_type_ustats",
802cd814b26SRobert Watson     "Return malloc types");
803cd814b26SRobert Watson 
804cd814b26SRobert Watson SYSCTL_INT(_kern, OID_AUTO, malloc_count, CTLFLAG_RD, &kmemcount, 0,
805cd814b26SRobert Watson     "Count of kernel malloc types");
806cd814b26SRobert Watson 
807909ed16cSRobert Watson #ifdef DDB
808909ed16cSRobert Watson DB_SHOW_COMMAND(malloc, db_show_malloc)
809909ed16cSRobert Watson {
810909ed16cSRobert Watson 	struct malloc_type_internal *mtip;
811909ed16cSRobert Watson 	struct malloc_type *mtp;
812909ed16cSRobert Watson 	u_int64_t allocs, frees;
81324076d13SRobert Watson 	u_int64_t alloced, freed;
814909ed16cSRobert Watson 	int i;
815909ed16cSRobert Watson 
81624076d13SRobert Watson 	db_printf("%18s %12s  %12s %12s\n", "Type", "InUse", "MemUse",
81724076d13SRobert Watson 	    "Requests");
818909ed16cSRobert Watson 	for (mtp = kmemstatistics; mtp != NULL; mtp = mtp->ks_next) {
819909ed16cSRobert Watson 		mtip = (struct malloc_type_internal *)mtp->ks_handle;
820909ed16cSRobert Watson 		allocs = 0;
821909ed16cSRobert Watson 		frees = 0;
82224076d13SRobert Watson 		alloced = 0;
82324076d13SRobert Watson 		freed = 0;
824909ed16cSRobert Watson 		for (i = 0; i < MAXCPU; i++) {
825909ed16cSRobert Watson 			allocs += mtip->mti_stats[i].mts_numallocs;
826909ed16cSRobert Watson 			frees += mtip->mti_stats[i].mts_numfrees;
82724076d13SRobert Watson 			alloced += mtip->mti_stats[i].mts_memalloced;
82824076d13SRobert Watson 			freed += mtip->mti_stats[i].mts_memfreed;
829909ed16cSRobert Watson 		}
83024076d13SRobert Watson 		db_printf("%18s %12ju %12juK %12ju\n",
83124076d13SRobert Watson 		    mtp->ks_shortdesc, allocs - frees,
83224076d13SRobert Watson 		    (alloced - freed + 1023) / 1024, allocs);
833909ed16cSRobert Watson 	}
834909ed16cSRobert Watson }
835909ed16cSRobert Watson #endif
836909ed16cSRobert Watson 
8375e914b96SJeff Roberson #ifdef MALLOC_PROFILE
8385e914b96SJeff Roberson 
8395e914b96SJeff Roberson static int
8405e914b96SJeff Roberson sysctl_kern_mprof(SYSCTL_HANDLER_ARGS)
8415e914b96SJeff Roberson {
8425e914b96SJeff Roberson 	int linesize = 64;
84363a7e0a3SRobert Watson 	struct sbuf sbuf;
8445e914b96SJeff Roberson 	uint64_t count;
8455e914b96SJeff Roberson 	uint64_t waste;
8465e914b96SJeff Roberson 	uint64_t mem;
8475e914b96SJeff Roberson 	int bufsize;
8485e914b96SJeff Roberson 	int error;
8495e914b96SJeff Roberson 	char *buf;
8505e914b96SJeff Roberson 	int rsize;
8515e914b96SJeff Roberson 	int size;
8525e914b96SJeff Roberson 	int i;
8535e914b96SJeff Roberson 
8545e914b96SJeff Roberson 	bufsize = linesize * (KMEM_ZSIZE + 1);
8555e914b96SJeff Roberson 	bufsize += 128; 	/* For the stats line */
8565e914b96SJeff Roberson 	bufsize += 128; 	/* For the banner line */
8575e914b96SJeff Roberson 	waste = 0;
8585e914b96SJeff Roberson 	mem = 0;
8595e914b96SJeff Roberson 
86063a7e0a3SRobert Watson 	buf = malloc(bufsize, M_TEMP, M_WAITOK|M_ZERO);
86163a7e0a3SRobert Watson 	sbuf_new(&sbuf, buf, bufsize, SBUF_FIXEDLEN);
86263a7e0a3SRobert Watson 	sbuf_printf(&sbuf,
8635e914b96SJeff Roberson 	    "\n  Size                    Requests  Real Size\n");
8645e914b96SJeff Roberson 	for (i = 0; i < KMEM_ZSIZE; i++) {
8655e914b96SJeff Roberson 		size = i << KMEM_ZSHIFT;
8665e914b96SJeff Roberson 		rsize = kmemzones[kmemsize[i]].kz_size;
8675e914b96SJeff Roberson 		count = (long long unsigned)krequests[i];
8685e914b96SJeff Roberson 
86963a7e0a3SRobert Watson 		sbuf_printf(&sbuf, "%6d%28llu%11d\n", size,
87063a7e0a3SRobert Watson 		    (unsigned long long)count, rsize);
8715e914b96SJeff Roberson 
8725e914b96SJeff Roberson 		if ((rsize * count) > (size * count))
8735e914b96SJeff Roberson 			waste += (rsize * count) - (size * count);
8745e914b96SJeff Roberson 		mem += (rsize * count);
8755e914b96SJeff Roberson 	}
87663a7e0a3SRobert Watson 	sbuf_printf(&sbuf,
8775e914b96SJeff Roberson 	    "\nTotal memory used:\t%30llu\nTotal Memory wasted:\t%30llu\n",
8785e914b96SJeff Roberson 	    (unsigned long long)mem, (unsigned long long)waste);
87963a7e0a3SRobert Watson 	sbuf_finish(&sbuf);
8805e914b96SJeff Roberson 
88163a7e0a3SRobert Watson 	error = SYSCTL_OUT(req, sbuf_data(&sbuf), sbuf_len(&sbuf));
8825e914b96SJeff Roberson 
88363a7e0a3SRobert Watson 	sbuf_delete(&sbuf);
8845e914b96SJeff Roberson 	free(buf, M_TEMP);
8855e914b96SJeff Roberson 	return (error);
8865e914b96SJeff Roberson }
8875e914b96SJeff Roberson 
8885e914b96SJeff Roberson SYSCTL_OID(_kern, OID_AUTO, mprof, CTLTYPE_STRING|CTLFLAG_RD,
8895e914b96SJeff Roberson     NULL, 0, sysctl_kern_mprof, "A", "Malloc Profiling");
8905e914b96SJeff Roberson #endif /* MALLOC_PROFILE */
891