xref: /freebsd/sys/kern/kern_malloc.c (revision 44a8ff315e2a51614155fcbb86ab0577bb1f1152)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1987, 1991, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
14df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
15df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
16df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
17df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
18df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
19df8bae1dSRodney W. Grimes  *    without specific prior written permission.
20df8bae1dSRodney W. Grimes  *
21df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
32df8bae1dSRodney W. Grimes  *
33df8bae1dSRodney W. Grimes  *	@(#)kern_malloc.c	8.3 (Berkeley) 1/4/94
34c3aac50fSPeter Wemm  * $FreeBSD$
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
378a58a9f6SJohn Dyson #include "opt_vm.h"
388a58a9f6SJohn Dyson 
39df8bae1dSRodney W. Grimes #include <sys/param.h>
4026f9a767SRodney W. Grimes #include <sys/systm.h>
41df8bae1dSRodney W. Grimes #include <sys/kernel.h>
42fb919e4dSMark Murray #include <sys/lock.h>
43df8bae1dSRodney W. Grimes #include <sys/malloc.h>
4454e7152cSDavid Greenman #include <sys/mbuf.h>
45eec258d2SJohn Baldwin #include <sys/mutex.h>
46efeaf95aSDavid Greenman #include <sys/vmmeter.h>
47a448b62aSJake Burkholder #include <sys/proc.h>
489a02e8c6SJason Evans 
49df8bae1dSRodney W. Grimes #include <vm/vm.h>
50efeaf95aSDavid Greenman #include <vm/vm_param.h>
51df8bae1dSRodney W. Grimes #include <vm/vm_kern.h>
52efeaf95aSDavid Greenman #include <vm/vm_extern.h>
533075778bSJohn Dyson #include <vm/pmap.h>
543075778bSJohn Dyson #include <vm/vm_map.h>
55df8bae1dSRodney W. Grimes 
56984982d6SPoul-Henning Kamp #if defined(INVARIANTS) && defined(__i386__)
57984982d6SPoul-Henning Kamp #include <machine/cpu.h>
58984982d6SPoul-Henning Kamp #endif
59984982d6SPoul-Henning Kamp 
6044a8ff31SArchie Cobbs /*
6144a8ff31SArchie Cobbs  * When realloc() is called, if the new size is sufficiently smaller than
6244a8ff31SArchie Cobbs  * the old size, realloc() will allocate a new, smaller block to avoid
6344a8ff31SArchie Cobbs  * wasting memory. 'Sufficiently smaller' is defined as: newsize <=
6444a8ff31SArchie Cobbs  * oldsize / 2^n, where REALLOC_FRACTION defines the value of 'n'.
6544a8ff31SArchie Cobbs  */
6644a8ff31SArchie Cobbs #ifndef REALLOC_FRACTION
6744a8ff31SArchie Cobbs #define	REALLOC_FRACTION	1	/* new block if <= half the size */
6844a8ff31SArchie Cobbs #endif
6944a8ff31SArchie Cobbs 
703b6fb885SPoul-Henning Kamp MALLOC_DEFINE(M_CACHE, "cache", "Various Dynamically allocated caches");
719ef246c6SBruce Evans MALLOC_DEFINE(M_DEVBUF, "devbuf", "device driver memory");
729ef246c6SBruce Evans MALLOC_DEFINE(M_TEMP, "temp", "misc temporary data buffers");
739ef246c6SBruce Evans 
7482cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6OPT, "ip6opt", "IPv6 options");
7582cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6NDP, "ip6ndp", "IPv6 Neighbor Discovery");
7682cd038dSYoshinobu Inoue 
774590fd3aSDavid Greenman static void kmeminit __P((void *));
782b14f991SJulian Elischer SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL)
792b14f991SJulian Elischer 
80a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FREE, "free", "should be on free list");
81a1c995b6SPoul-Henning Kamp 
82db669378SPeter Wemm static struct malloc_type *kmemstatistics;
83254c6cb3SPoul-Henning Kamp static struct kmembuckets bucket[MINBUCKET + 16];
84254c6cb3SPoul-Henning Kamp static struct kmemusage *kmemusage;
85254c6cb3SPoul-Henning Kamp static char *kmembase;
86043a2f3bSBruce Evans static char *kmemlimit;
871f6889a1SMatthew Dillon 
88d1c1b841SJason Evans static struct mtx malloc_mtx;
8969ef67f9SJason Evans 
901f6889a1SMatthew Dillon u_int vm_kmem_size;
91df8bae1dSRodney W. Grimes 
92219cbf59SEivind Eklund #ifdef INVARIANTS
93df8bae1dSRodney W. Grimes /*
94df8bae1dSRodney W. Grimes  * This structure provides a set of masks to catch unaligned frees.
95df8bae1dSRodney W. Grimes  */
9687b6de2bSPoul-Henning Kamp static long addrmask[] = { 0,
97df8bae1dSRodney W. Grimes 	0x00000001, 0x00000003, 0x00000007, 0x0000000f,
98df8bae1dSRodney W. Grimes 	0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
99df8bae1dSRodney W. Grimes 	0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
100df8bae1dSRodney W. Grimes 	0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
101df8bae1dSRodney W. Grimes };
102df8bae1dSRodney W. Grimes 
103df8bae1dSRodney W. Grimes /*
104df8bae1dSRodney W. Grimes  * The WEIRD_ADDR is used as known text to copy into free objects so
105df8bae1dSRodney W. Grimes  * that modifications after frees can be detected.
106df8bae1dSRodney W. Grimes  */
1075124d598SDavid Greenman #define WEIRD_ADDR	0xdeadc0de
1085124d598SDavid Greenman #define MAX_COPY	64
109df8bae1dSRodney W. Grimes 
110df8bae1dSRodney W. Grimes /*
111df8bae1dSRodney W. Grimes  * Normally the first word of the structure is used to hold the list
112df8bae1dSRodney W. Grimes  * pointer for free objects. However, when running with diagnostics,
113df8bae1dSRodney W. Grimes  * we use the third and fourth fields, so as to catch modifications
114df8bae1dSRodney W. Grimes  * in the most commonly trashed first two words.
115df8bae1dSRodney W. Grimes  */
116df8bae1dSRodney W. Grimes struct freelist {
117df8bae1dSRodney W. Grimes 	long	spare0;
11860a513e9SPoul-Henning Kamp 	struct malloc_type *type;
119df8bae1dSRodney W. Grimes 	long	spare1;
120df8bae1dSRodney W. Grimes 	caddr_t	next;
121df8bae1dSRodney W. Grimes };
1225526d2d9SEivind Eklund #else /* !INVARIANTS */
123df8bae1dSRodney W. Grimes struct freelist {
124df8bae1dSRodney W. Grimes 	caddr_t	next;
125df8bae1dSRodney W. Grimes };
1265526d2d9SEivind Eklund #endif /* INVARIANTS */
127df8bae1dSRodney W. Grimes 
128df8bae1dSRodney W. Grimes /*
1291c7c3c6aSMatthew Dillon  *	malloc:
1301c7c3c6aSMatthew Dillon  *
1311c7c3c6aSMatthew Dillon  *	Allocate a block of memory.
1321c7c3c6aSMatthew Dillon  *
1331c7c3c6aSMatthew Dillon  *	If M_NOWAIT is set, this routine will not block and return NULL if
1341c7c3c6aSMatthew Dillon  *	the allocation fails.
135df8bae1dSRodney W. Grimes  */
136df8bae1dSRodney W. Grimes void *
137df8bae1dSRodney W. Grimes malloc(size, type, flags)
138df8bae1dSRodney W. Grimes 	unsigned long size;
13960a513e9SPoul-Henning Kamp 	struct malloc_type *type;
140254c6cb3SPoul-Henning Kamp 	int flags;
141df8bae1dSRodney W. Grimes {
142df8bae1dSRodney W. Grimes 	register struct kmembuckets *kbp;
143df8bae1dSRodney W. Grimes 	register struct kmemusage *kup;
144df8bae1dSRodney W. Grimes 	register struct freelist *freep;
145df8bae1dSRodney W. Grimes 	long indx, npg, allocsize;
146df8bae1dSRodney W. Grimes 	int s;
147df8bae1dSRodney W. Grimes 	caddr_t va, cp, savedlist;
1485526d2d9SEivind Eklund #ifdef INVARIANTS
149df8bae1dSRodney W. Grimes 	long *end, *lp;
150df8bae1dSRodney W. Grimes 	int copysize;
151d254af07SMatthew Dillon 	const char *savedtype;
152df8bae1dSRodney W. Grimes #endif
15360a513e9SPoul-Henning Kamp 	register struct malloc_type *ksp = type;
154df8bae1dSRodney W. Grimes 
1550fee3d35SPeter Wemm #if defined(INVARIANTS)
156984982d6SPoul-Henning Kamp 	if (flags == M_WAITOK)
157b40ce416SJulian Elischer 		KASSERT(curthread->td_intr_nesting_level == 0,
158984982d6SPoul-Henning Kamp 		   ("malloc(M_WAITOK) in interrupt context"));
159984982d6SPoul-Henning Kamp #endif
160df8bae1dSRodney W. Grimes 	indx = BUCKETINDX(size);
161df8bae1dSRodney W. Grimes 	kbp = &bucket[indx];
1628e8cac55SBruce Evans 	s = splmem();
1639ed346baSBosko Milekic 	mtx_lock(&malloc_mtx);
164df8bae1dSRodney W. Grimes 	while (ksp->ks_memuse >= ksp->ks_limit) {
165df8bae1dSRodney W. Grimes 		if (flags & M_NOWAIT) {
166df8bae1dSRodney W. Grimes 			splx(s);
1679ed346baSBosko Milekic 			mtx_unlock(&malloc_mtx);
1681707240dSBoris Popov 			return ((void *) NULL);
169df8bae1dSRodney W. Grimes 		}
170df8bae1dSRodney W. Grimes 		if (ksp->ks_limblocks < 65535)
171df8bae1dSRodney W. Grimes 			ksp->ks_limblocks++;
17269ef67f9SJason Evans 		msleep((caddr_t)ksp, &malloc_mtx, PSWP+2, type->ks_shortdesc,
17369ef67f9SJason Evans 		    0);
174df8bae1dSRodney W. Grimes 	}
175df8bae1dSRodney W. Grimes 	ksp->ks_size |= 1 << indx;
1765526d2d9SEivind Eklund #ifdef INVARIANTS
177df8bae1dSRodney W. Grimes 	copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
178df8bae1dSRodney W. Grimes #endif
179df8bae1dSRodney W. Grimes 	if (kbp->kb_next == NULL) {
180df8bae1dSRodney W. Grimes 		kbp->kb_last = NULL;
181df8bae1dSRodney W. Grimes 		if (size > MAXALLOCSAVE)
182f8845af0SPoul-Henning Kamp 			allocsize = roundup(size, PAGE_SIZE);
183df8bae1dSRodney W. Grimes 		else
184df8bae1dSRodney W. Grimes 			allocsize = 1 << indx;
185e911eafcSPoul-Henning Kamp 		npg = btoc(allocsize);
18669ef67f9SJason Evans 
1879ed346baSBosko Milekic 		mtx_unlock(&malloc_mtx);
1889f518539SDavid Greenman 		va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags);
18969ef67f9SJason Evans 
190df8bae1dSRodney W. Grimes 		if (va == NULL) {
191df8bae1dSRodney W. Grimes 			splx(s);
1921707240dSBoris Popov 			return ((void *) NULL);
193df8bae1dSRodney W. Grimes 		}
19469ef67f9SJason Evans 		/*
19569ef67f9SJason Evans 		 * Enter malloc_mtx after the error check to avoid having to
19669ef67f9SJason Evans 		 * immediately exit it again if there is an error.
19769ef67f9SJason Evans 		 */
1989ed346baSBosko Milekic 		mtx_lock(&malloc_mtx);
19969ef67f9SJason Evans 
200df8bae1dSRodney W. Grimes 		kbp->kb_total += kbp->kb_elmpercl;
201df8bae1dSRodney W. Grimes 		kup = btokup(va);
202df8bae1dSRodney W. Grimes 		kup->ku_indx = indx;
203df8bae1dSRodney W. Grimes 		if (allocsize > MAXALLOCSAVE) {
204df8bae1dSRodney W. Grimes 			if (npg > 65535)
205df8bae1dSRodney W. Grimes 				panic("malloc: allocation too large");
206df8bae1dSRodney W. Grimes 			kup->ku_pagecnt = npg;
207df8bae1dSRodney W. Grimes 			ksp->ks_memuse += allocsize;
208df8bae1dSRodney W. Grimes 			goto out;
209df8bae1dSRodney W. Grimes 		}
210df8bae1dSRodney W. Grimes 		kup->ku_freecnt = kbp->kb_elmpercl;
211df8bae1dSRodney W. Grimes 		kbp->kb_totalfree += kbp->kb_elmpercl;
212df8bae1dSRodney W. Grimes 		/*
213df8bae1dSRodney W. Grimes 		 * Just in case we blocked while allocating memory,
214df8bae1dSRodney W. Grimes 		 * and someone else also allocated memory for this
215df8bae1dSRodney W. Grimes 		 * bucket, don't assume the list is still empty.
216df8bae1dSRodney W. Grimes 		 */
217df8bae1dSRodney W. Grimes 		savedlist = kbp->kb_next;
218e911eafcSPoul-Henning Kamp 		kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize;
219df8bae1dSRodney W. Grimes 		for (;;) {
220df8bae1dSRodney W. Grimes 			freep = (struct freelist *)cp;
2215526d2d9SEivind Eklund #ifdef INVARIANTS
222df8bae1dSRodney W. Grimes 			/*
223df8bae1dSRodney W. Grimes 			 * Copy in known text to detect modification
224df8bae1dSRodney W. Grimes 			 * after freeing.
225df8bae1dSRodney W. Grimes 			 */
226df8bae1dSRodney W. Grimes 			end = (long *)&cp[copysize];
227df8bae1dSRodney W. Grimes 			for (lp = (long *)cp; lp < end; lp++)
228df8bae1dSRodney W. Grimes 				*lp = WEIRD_ADDR;
229df8bae1dSRodney W. Grimes 			freep->type = M_FREE;
2305526d2d9SEivind Eklund #endif /* INVARIANTS */
231df8bae1dSRodney W. Grimes 			if (cp <= va)
232df8bae1dSRodney W. Grimes 				break;
233df8bae1dSRodney W. Grimes 			cp -= allocsize;
234df8bae1dSRodney W. Grimes 			freep->next = cp;
235df8bae1dSRodney W. Grimes 		}
236df8bae1dSRodney W. Grimes 		freep->next = savedlist;
237df8bae1dSRodney W. Grimes 		if (kbp->kb_last == NULL)
238df8bae1dSRodney W. Grimes 			kbp->kb_last = (caddr_t)freep;
239df8bae1dSRodney W. Grimes 	}
240df8bae1dSRodney W. Grimes 	va = kbp->kb_next;
241df8bae1dSRodney W. Grimes 	kbp->kb_next = ((struct freelist *)va)->next;
2425526d2d9SEivind Eklund #ifdef INVARIANTS
243df8bae1dSRodney W. Grimes 	freep = (struct freelist *)va;
244dc760634SJun Kuriyama 	savedtype = (const char *) freep->type->ks_shortdesc;
24560a513e9SPoul-Henning Kamp 	freep->type = (struct malloc_type *)WEIRD_ADDR;
24686a14a7aSBruce Evans 	if ((intptr_t)(void *)&freep->next & 0x2)
247df8bae1dSRodney W. Grimes 		freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16));
248df8bae1dSRodney W. Grimes 	else
249df8bae1dSRodney W. Grimes 		freep->next = (caddr_t)WEIRD_ADDR;
250df8bae1dSRodney W. Grimes 	end = (long *)&va[copysize];
251df8bae1dSRodney W. Grimes 	for (lp = (long *)va; lp < end; lp++) {
252df8bae1dSRodney W. Grimes 		if (*lp == WEIRD_ADDR)
253df8bae1dSRodney W. Grimes 			continue;
254d974cf4dSBruce Evans 		printf("%s %ld of object %p size %lu %s %s (0x%lx != 0x%lx)\n",
255d974cf4dSBruce Evans 			"Data modified on freelist: word",
256d974cf4dSBruce Evans 			(long)(lp - (long *)va), (void *)va, size,
257d974cf4dSBruce Evans 			"previous type", savedtype, *lp, (u_long)WEIRD_ADDR);
258df8bae1dSRodney W. Grimes 		break;
259df8bae1dSRodney W. Grimes 	}
260df8bae1dSRodney W. Grimes 	freep->spare0 = 0;
2615526d2d9SEivind Eklund #endif /* INVARIANTS */
262df8bae1dSRodney W. Grimes 	kup = btokup(va);
263df8bae1dSRodney W. Grimes 	if (kup->ku_indx != indx)
264df8bae1dSRodney W. Grimes 		panic("malloc: wrong bucket");
265df8bae1dSRodney W. Grimes 	if (kup->ku_freecnt == 0)
266df8bae1dSRodney W. Grimes 		panic("malloc: lost data");
267df8bae1dSRodney W. Grimes 	kup->ku_freecnt--;
268df8bae1dSRodney W. Grimes 	kbp->kb_totalfree--;
269df8bae1dSRodney W. Grimes 	ksp->ks_memuse += 1 << indx;
270df8bae1dSRodney W. Grimes out:
271df8bae1dSRodney W. Grimes 	kbp->kb_calls++;
272df8bae1dSRodney W. Grimes 	ksp->ks_inuse++;
273df8bae1dSRodney W. Grimes 	ksp->ks_calls++;
274df8bae1dSRodney W. Grimes 	if (ksp->ks_memuse > ksp->ks_maxused)
275df8bae1dSRodney W. Grimes 		ksp->ks_maxused = ksp->ks_memuse;
276df8bae1dSRodney W. Grimes 	splx(s);
2779ed346baSBosko Milekic 	mtx_unlock(&malloc_mtx);
2781921a06dSPoul-Henning Kamp 	/* XXX: Do idle pre-zeroing.  */
2791921a06dSPoul-Henning Kamp 	if (va != NULL && (flags & M_ZERO))
2801921a06dSPoul-Henning Kamp 		bzero(va, size);
281df8bae1dSRodney W. Grimes 	return ((void *) va);
282df8bae1dSRodney W. Grimes }
283df8bae1dSRodney W. Grimes 
284df8bae1dSRodney W. Grimes /*
2851c7c3c6aSMatthew Dillon  *	free:
2861c7c3c6aSMatthew Dillon  *
287df8bae1dSRodney W. Grimes  *	Free a block of memory allocated by malloc.
2881c7c3c6aSMatthew Dillon  *
2891c7c3c6aSMatthew Dillon  *	This routine may not block.
290df8bae1dSRodney W. Grimes  */
291df8bae1dSRodney W. Grimes void
292df8bae1dSRodney W. Grimes free(addr, type)
293df8bae1dSRodney W. Grimes 	void *addr;
29460a513e9SPoul-Henning Kamp 	struct malloc_type *type;
295df8bae1dSRodney W. Grimes {
296df8bae1dSRodney W. Grimes 	register struct kmembuckets *kbp;
297df8bae1dSRodney W. Grimes 	register struct kmemusage *kup;
298df8bae1dSRodney W. Grimes 	register struct freelist *freep;
299df8bae1dSRodney W. Grimes 	long size;
300df8bae1dSRodney W. Grimes 	int s;
3015526d2d9SEivind Eklund #ifdef INVARIANTS
302ca67a4e4SPoul-Henning Kamp 	struct freelist *fp;
303df8bae1dSRodney W. Grimes 	long *end, *lp, alloc, copysize;
304df8bae1dSRodney W. Grimes #endif
30560a513e9SPoul-Henning Kamp 	register struct malloc_type *ksp = type;
306254c6cb3SPoul-Henning Kamp 
30744a8ff31SArchie Cobbs 	/* free(NULL, ...) does nothing */
30844a8ff31SArchie Cobbs 	if (addr == NULL)
30944a8ff31SArchie Cobbs 		return;
31044a8ff31SArchie Cobbs 
3115526d2d9SEivind Eklund 	KASSERT(kmembase <= (char *)addr && (char *)addr < kmemlimit,
3125526d2d9SEivind Eklund 	    ("free: address %p out of range", (void *)addr));
313df8bae1dSRodney W. Grimes 	kup = btokup(addr);
314df8bae1dSRodney W. Grimes 	size = 1 << kup->ku_indx;
315df8bae1dSRodney W. Grimes 	kbp = &bucket[kup->ku_indx];
316b1897c19SJulian Elischer 	s = splmem();
3179ed346baSBosko Milekic 	mtx_lock(&malloc_mtx);
3185526d2d9SEivind Eklund #ifdef INVARIANTS
319df8bae1dSRodney W. Grimes 	/*
320df8bae1dSRodney W. Grimes 	 * Check for returns of data that do not point to the
321df8bae1dSRodney W. Grimes 	 * beginning of the allocation.
322df8bae1dSRodney W. Grimes 	 */
323f8845af0SPoul-Henning Kamp 	if (size > PAGE_SIZE)
324f8845af0SPoul-Henning Kamp 		alloc = addrmask[BUCKETINDX(PAGE_SIZE)];
325df8bae1dSRodney W. Grimes 	else
326df8bae1dSRodney W. Grimes 		alloc = addrmask[kup->ku_indx];
32786a14a7aSBruce Evans 	if (((uintptr_t)(void *)addr & alloc) != 0)
328d974cf4dSBruce Evans 		panic("free: unaligned addr %p, size %ld, type %s, mask %ld",
329d974cf4dSBruce Evans 		    (void *)addr, size, type->ks_shortdesc, alloc);
3305526d2d9SEivind Eklund #endif /* INVARIANTS */
331df8bae1dSRodney W. Grimes 	if (size > MAXALLOCSAVE) {
3329ed346baSBosko Milekic 		mtx_unlock(&malloc_mtx);
333df8bae1dSRodney W. Grimes 		kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt));
3349ed346baSBosko Milekic 		mtx_lock(&malloc_mtx);
33569ef67f9SJason Evans 
336e911eafcSPoul-Henning Kamp 		size = kup->ku_pagecnt << PAGE_SHIFT;
337df8bae1dSRodney W. Grimes 		ksp->ks_memuse -= size;
338df8bae1dSRodney W. Grimes 		kup->ku_indx = 0;
339df8bae1dSRodney W. Grimes 		kup->ku_pagecnt = 0;
340df8bae1dSRodney W. Grimes 		if (ksp->ks_memuse + size >= ksp->ks_limit &&
341df8bae1dSRodney W. Grimes 		    ksp->ks_memuse < ksp->ks_limit)
342df8bae1dSRodney W. Grimes 			wakeup((caddr_t)ksp);
343df8bae1dSRodney W. Grimes 		ksp->ks_inuse--;
344df8bae1dSRodney W. Grimes 		kbp->kb_total -= 1;
345df8bae1dSRodney W. Grimes 		splx(s);
3469ed346baSBosko Milekic 		mtx_unlock(&malloc_mtx);
347df8bae1dSRodney W. Grimes 		return;
348df8bae1dSRodney W. Grimes 	}
349df8bae1dSRodney W. Grimes 	freep = (struct freelist *)addr;
3505526d2d9SEivind Eklund #ifdef INVARIANTS
351df8bae1dSRodney W. Grimes 	/*
352df8bae1dSRodney W. Grimes 	 * Check for multiple frees. Use a quick check to see if
353df8bae1dSRodney W. Grimes 	 * it looks free before laboriously searching the freelist.
354df8bae1dSRodney W. Grimes 	 */
355df8bae1dSRodney W. Grimes 	if (freep->spare0 == WEIRD_ADDR) {
356ca67a4e4SPoul-Henning Kamp 		fp = (struct freelist *)kbp->kb_next;
357ca67a4e4SPoul-Henning Kamp 		while (fp) {
358219cbf59SEivind Eklund 			if (fp->spare0 != WEIRD_ADDR)
3595526d2d9SEivind Eklund 				panic("free: free item %p modified", fp);
360219cbf59SEivind Eklund 			else if (addr == (caddr_t)fp)
3615526d2d9SEivind Eklund 				panic("free: multiple freed item %p", addr);
362ca67a4e4SPoul-Henning Kamp 			fp = (struct freelist *)fp->next;
363df8bae1dSRodney W. Grimes 		}
364df8bae1dSRodney W. Grimes 	}
365df8bae1dSRodney W. Grimes 	/*
366df8bae1dSRodney W. Grimes 	 * Copy in known text to detect modification after freeing
367df8bae1dSRodney W. Grimes 	 * and to make it look free. Also, save the type being freed
368df8bae1dSRodney W. Grimes 	 * so we can list likely culprit if modification is detected
369df8bae1dSRodney W. Grimes 	 * when the object is reallocated.
370df8bae1dSRodney W. Grimes 	 */
371df8bae1dSRodney W. Grimes 	copysize = size < MAX_COPY ? size : MAX_COPY;
372df8bae1dSRodney W. Grimes 	end = (long *)&((caddr_t)addr)[copysize];
373df8bae1dSRodney W. Grimes 	for (lp = (long *)addr; lp < end; lp++)
374df8bae1dSRodney W. Grimes 		*lp = WEIRD_ADDR;
375df8bae1dSRodney W. Grimes 	freep->type = type;
3765526d2d9SEivind Eklund #endif /* INVARIANTS */
377df8bae1dSRodney W. Grimes 	kup->ku_freecnt++;
378dfd5dee1SPeter Wemm 	if (kup->ku_freecnt >= kbp->kb_elmpercl) {
379df8bae1dSRodney W. Grimes 		if (kup->ku_freecnt > kbp->kb_elmpercl)
380df8bae1dSRodney W. Grimes 			panic("free: multiple frees");
381df8bae1dSRodney W. Grimes 		else if (kbp->kb_totalfree > kbp->kb_highwat)
382df8bae1dSRodney W. Grimes 			kbp->kb_couldfree++;
383dfd5dee1SPeter Wemm 	}
384df8bae1dSRodney W. Grimes 	kbp->kb_totalfree++;
385df8bae1dSRodney W. Grimes 	ksp->ks_memuse -= size;
386df8bae1dSRodney W. Grimes 	if (ksp->ks_memuse + size >= ksp->ks_limit &&
387df8bae1dSRodney W. Grimes 	    ksp->ks_memuse < ksp->ks_limit)
388df8bae1dSRodney W. Grimes 		wakeup((caddr_t)ksp);
389df8bae1dSRodney W. Grimes 	ksp->ks_inuse--;
39014bf02f8SJohn Dyson #ifdef OLD_MALLOC_MEMORY_POLICY
391df8bae1dSRodney W. Grimes 	if (kbp->kb_next == NULL)
392df8bae1dSRodney W. Grimes 		kbp->kb_next = addr;
393df8bae1dSRodney W. Grimes 	else
394df8bae1dSRodney W. Grimes 		((struct freelist *)kbp->kb_last)->next = addr;
395df8bae1dSRodney W. Grimes 	freep->next = NULL;
396df8bae1dSRodney W. Grimes 	kbp->kb_last = addr;
39714bf02f8SJohn Dyson #else
39814bf02f8SJohn Dyson 	/*
39914bf02f8SJohn Dyson 	 * Return memory to the head of the queue for quick reuse.  This
40014bf02f8SJohn Dyson 	 * can improve performance by improving the probability of the
40114bf02f8SJohn Dyson 	 * item being in the cache when it is reused.
40214bf02f8SJohn Dyson 	 */
40314bf02f8SJohn Dyson 	if (kbp->kb_next == NULL) {
40414bf02f8SJohn Dyson 		kbp->kb_next = addr;
40514bf02f8SJohn Dyson 		kbp->kb_last = addr;
40614bf02f8SJohn Dyson 		freep->next = NULL;
40714bf02f8SJohn Dyson 	} else {
40814bf02f8SJohn Dyson 		freep->next = kbp->kb_next;
40914bf02f8SJohn Dyson 		kbp->kb_next = addr;
41014bf02f8SJohn Dyson 	}
41114bf02f8SJohn Dyson #endif
412df8bae1dSRodney W. Grimes 	splx(s);
4139ed346baSBosko Milekic 	mtx_unlock(&malloc_mtx);
414df8bae1dSRodney W. Grimes }
415df8bae1dSRodney W. Grimes 
416df8bae1dSRodney W. Grimes /*
41744a8ff31SArchie Cobbs  *	realloc: change the size of a memory block
41844a8ff31SArchie Cobbs  */
41944a8ff31SArchie Cobbs void *
42044a8ff31SArchie Cobbs realloc(addr, size, type, flags)
42144a8ff31SArchie Cobbs 	void *addr;
42244a8ff31SArchie Cobbs 	unsigned long size;
42344a8ff31SArchie Cobbs 	struct malloc_type *type;
42444a8ff31SArchie Cobbs 	int flags;
42544a8ff31SArchie Cobbs {
42644a8ff31SArchie Cobbs 	struct kmemusage *kup;
42744a8ff31SArchie Cobbs 	unsigned long alloc;
42844a8ff31SArchie Cobbs 	void *newaddr;
42944a8ff31SArchie Cobbs 
43044a8ff31SArchie Cobbs 	/* realloc(NULL, ...) is equivalent to malloc(...) */
43144a8ff31SArchie Cobbs 	if (addr == NULL)
43244a8ff31SArchie Cobbs 		return (malloc(size, type, flags));
43344a8ff31SArchie Cobbs 
43444a8ff31SArchie Cobbs 	/* Sanity check */
43544a8ff31SArchie Cobbs 	KASSERT(kmembase <= (char *)addr && (char *)addr < kmemlimit,
43644a8ff31SArchie Cobbs 	    ("realloc: address %p out of range", (void *)addr));
43744a8ff31SArchie Cobbs 
43844a8ff31SArchie Cobbs 	/* Get the size of the original block */
43944a8ff31SArchie Cobbs 	kup = btokup(addr);
44044a8ff31SArchie Cobbs 	alloc = 1 << kup->ku_indx;
44144a8ff31SArchie Cobbs 	if (alloc > MAXALLOCSAVE)
44244a8ff31SArchie Cobbs 		alloc = kup->ku_pagecnt << PAGE_SHIFT;
44344a8ff31SArchie Cobbs 
44444a8ff31SArchie Cobbs 	/* Reuse the original block if appropriate */
44544a8ff31SArchie Cobbs 	if (size <= alloc
44644a8ff31SArchie Cobbs 	    && (size > (alloc >> REALLOC_FRACTION) || alloc == MINALLOCSIZE))
44744a8ff31SArchie Cobbs 		return (addr);
44844a8ff31SArchie Cobbs 
44944a8ff31SArchie Cobbs 	/* Allocate a new, bigger (or smaller) block */
45044a8ff31SArchie Cobbs 	if ((newaddr = malloc(size, type, flags)) == NULL)
45144a8ff31SArchie Cobbs 		return (NULL);
45244a8ff31SArchie Cobbs 
45344a8ff31SArchie Cobbs 	/* Copy over original contents */
45444a8ff31SArchie Cobbs 	bcopy(addr, newaddr, min(size, alloc));
45544a8ff31SArchie Cobbs 	free(addr, type);
45644a8ff31SArchie Cobbs 	return (newaddr);
45744a8ff31SArchie Cobbs }
45844a8ff31SArchie Cobbs 
45944a8ff31SArchie Cobbs /*
46044a8ff31SArchie Cobbs  *	reallocf: same as realloc() but free memory on failure.
46144a8ff31SArchie Cobbs  */
46244a8ff31SArchie Cobbs void *
46344a8ff31SArchie Cobbs reallocf(addr, size, type, flags)
46444a8ff31SArchie Cobbs 	void *addr;
46544a8ff31SArchie Cobbs 	unsigned long size;
46644a8ff31SArchie Cobbs 	struct malloc_type *type;
46744a8ff31SArchie Cobbs 	int flags;
46844a8ff31SArchie Cobbs {
46944a8ff31SArchie Cobbs 	void *mem;
47044a8ff31SArchie Cobbs 
47144a8ff31SArchie Cobbs 	if ((mem = realloc(addr, size, type, flags)) == NULL)
47244a8ff31SArchie Cobbs 		free(addr, type);
47344a8ff31SArchie Cobbs 	return (mem);
47444a8ff31SArchie Cobbs }
47544a8ff31SArchie Cobbs 
47644a8ff31SArchie Cobbs /*
477df8bae1dSRodney W. Grimes  * Initialize the kernel memory allocator
478df8bae1dSRodney W. Grimes  */
4792b14f991SJulian Elischer /* ARGSUSED*/
4802b14f991SJulian Elischer static void
481d841aaa7SBruce Evans kmeminit(dummy)
482d841aaa7SBruce Evans 	void *dummy;
483df8bae1dSRodney W. Grimes {
484df8bae1dSRodney W. Grimes 	register long indx;
48527b8623fSDavid Greenman 	u_long npg;
48627b8623fSDavid Greenman 	u_long mem_size;
487df8bae1dSRodney W. Grimes 
488df8bae1dSRodney W. Grimes #if	((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
489cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE not power of 2"
490df8bae1dSRodney W. Grimes #endif
491df8bae1dSRodney W. Grimes #if	(MAXALLOCSAVE > MINALLOCSIZE * 32768)
492cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too big"
493df8bae1dSRodney W. Grimes #endif
494f8845af0SPoul-Henning Kamp #if	(MAXALLOCSAVE < PAGE_SIZE)
495cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too small"
496df8bae1dSRodney W. Grimes #endif
4978a58a9f6SJohn Dyson 
498d1c1b841SJason Evans 	mtx_init(&malloc_mtx, "malloc", MTX_DEF);
49969ef67f9SJason Evans 
5008a58a9f6SJohn Dyson 	/*
5018a58a9f6SJohn Dyson 	 * Try to auto-tune the kernel memory size, so that it is
5028a58a9f6SJohn Dyson 	 * more applicable for a wider range of machine sizes.
5038a58a9f6SJohn Dyson 	 * On an X86, a VM_KMEM_SIZE_SCALE value of 4 is good, while
5048a58a9f6SJohn Dyson 	 * a VM_KMEM_SIZE of 12MB is a fair compromise.  The
5058a58a9f6SJohn Dyson 	 * VM_KMEM_SIZE_MAX is dependent on the maximum KVA space
5068a58a9f6SJohn Dyson 	 * available, and on an X86 with a total KVA space of 256MB,
5078a58a9f6SJohn Dyson 	 * try to keep VM_KMEM_SIZE_MAX at 80MB or below.
5088a58a9f6SJohn Dyson 	 *
5098a58a9f6SJohn Dyson 	 * Note that the kmem_map is also used by the zone allocator,
5108a58a9f6SJohn Dyson 	 * so make sure that there is enough space.
5118a58a9f6SJohn Dyson 	 */
51281930014SPeter Wemm 	vm_kmem_size = VM_KMEM_SIZE;
5138a58a9f6SJohn Dyson 	mem_size = cnt.v_page_count * PAGE_SIZE;
5148a58a9f6SJohn Dyson 
5158a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_SCALE)
51681930014SPeter Wemm 	if ((mem_size / VM_KMEM_SIZE_SCALE) > vm_kmem_size)
51781930014SPeter Wemm 		vm_kmem_size = mem_size / VM_KMEM_SIZE_SCALE;
5188a58a9f6SJohn Dyson #endif
5198a58a9f6SJohn Dyson 
5208a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_MAX)
52181930014SPeter Wemm 	if (vm_kmem_size >= VM_KMEM_SIZE_MAX)
52281930014SPeter Wemm 		vm_kmem_size = VM_KMEM_SIZE_MAX;
5238a58a9f6SJohn Dyson #endif
5248a58a9f6SJohn Dyson 
5258de6e8e1SMike Smith 	/* Allow final override from the kernel environment */
52609786698SPeter Wemm 	TUNABLE_INT_FETCH("kern.vm.kmem.size", &vm_kmem_size);
5278de6e8e1SMike Smith 
52827b8623fSDavid Greenman 	/*
52927b8623fSDavid Greenman 	 * Limit kmem virtual size to twice the physical memory.
53027b8623fSDavid Greenman 	 * This allows for kmem map sparseness, but limits the size
53127b8623fSDavid Greenman 	 * to something sane. Be careful to not overflow the 32bit
53227b8623fSDavid Greenman 	 * ints while doing the check.
53327b8623fSDavid Greenman 	 */
53427b8623fSDavid Greenman 	if ((vm_kmem_size / 2) > (cnt.v_page_count * PAGE_SIZE))
53527b8623fSDavid Greenman 		vm_kmem_size = 2 * cnt.v_page_count * PAGE_SIZE;
5368a58a9f6SJohn Dyson 
53708442f8aSBosko Milekic 	/*
538ba3e8826SBosko Milekic 	 * In mbuf_init(), we set up submaps for mbufs and clusters, in which
53908442f8aSBosko Milekic 	 * case we rounddown() (nmbufs * MSIZE) and (nmbclusters * MCLBYTES),
54008442f8aSBosko Milekic 	 * respectively. Mathematically, this means that what we do here may
54108442f8aSBosko Milekic 	 * amount to slightly more address space than we need for the submaps,
54208442f8aSBosko Milekic 	 * but it never hurts to have an extra page in kmem_map.
54308442f8aSBosko Milekic 	 */
544d04d50d1SBosko Milekic 	npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + nmbcnt *
54508442f8aSBosko Milekic 	    sizeof(u_int) + vm_kmem_size) / PAGE_SIZE;
5460d94caffSDavid Greenman 
547df8bae1dSRodney W. Grimes 	kmemusage = (struct kmemusage *) kmem_alloc(kernel_map,
548df8bae1dSRodney W. Grimes 		(vm_size_t)(npg * sizeof(struct kmemusage)));
549df8bae1dSRodney W. Grimes 	kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase,
5502d8acc0fSJohn Dyson 		(vm_offset_t *)&kmemlimit, (vm_size_t)(npg * PAGE_SIZE));
5513075778bSJohn Dyson 	kmem_map->system_map = 1;
552df8bae1dSRodney W. Grimes 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
553f8845af0SPoul-Henning Kamp 		if (1 << indx >= PAGE_SIZE)
554df8bae1dSRodney W. Grimes 			bucket[indx].kb_elmpercl = 1;
555df8bae1dSRodney W. Grimes 		else
556f8845af0SPoul-Henning Kamp 			bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
557df8bae1dSRodney W. Grimes 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
558df8bae1dSRodney W. Grimes 	}
559254c6cb3SPoul-Henning Kamp }
560254c6cb3SPoul-Henning Kamp 
561db669378SPeter Wemm void
562db669378SPeter Wemm malloc_init(data)
563db669378SPeter Wemm 	void *data;
564254c6cb3SPoul-Henning Kamp {
565db669378SPeter Wemm 	struct malloc_type *type = (struct malloc_type *)data;
566254c6cb3SPoul-Henning Kamp 
567d1bbc7ecSPoul-Henning Kamp 	if (type->ks_magic != M_MAGIC)
568d1bbc7ecSPoul-Henning Kamp 		panic("malloc type lacks magic");
569d1bbc7ecSPoul-Henning Kamp 
570ce45b512SBruce Evans 	if (type->ks_limit != 0)
571db669378SPeter Wemm 		return;
572db669378SPeter Wemm 
573d4060a87SJohn Dyson 	if (cnt.v_page_count == 0)
574d4060a87SJohn Dyson 		panic("malloc_init not allowed before vm init");
575d4060a87SJohn Dyson 
57607bbd7f1SDavid Greenman 	/*
5778a58a9f6SJohn Dyson 	 * The default limits for each malloc region is 1/2 of the
5788a58a9f6SJohn Dyson 	 * malloc portion of the kmem map size.
57907bbd7f1SDavid Greenman 	 */
5808a58a9f6SJohn Dyson 	type->ks_limit = vm_kmem_size / 2;
581254c6cb3SPoul-Henning Kamp 	type->ks_next = kmemstatistics;
582254c6cb3SPoul-Henning Kamp 	kmemstatistics = type;
583df8bae1dSRodney W. Grimes }
584db669378SPeter Wemm 
585db669378SPeter Wemm void
586db669378SPeter Wemm malloc_uninit(data)
587db669378SPeter Wemm 	void *data;
588db669378SPeter Wemm {
589db669378SPeter Wemm 	struct malloc_type *type = (struct malloc_type *)data;
590db669378SPeter Wemm 	struct malloc_type *t;
5915badeabaSBoris Popov #ifdef INVARIANTS
59299063cf8SBoris Popov 	struct kmembuckets *kbp;
59399063cf8SBoris Popov 	struct freelist *freep;
59499063cf8SBoris Popov 	long indx;
59599063cf8SBoris Popov 	int s;
59699063cf8SBoris Popov #endif
597db669378SPeter Wemm 
598db669378SPeter Wemm 	if (type->ks_magic != M_MAGIC)
599db669378SPeter Wemm 		panic("malloc type lacks magic");
600db669378SPeter Wemm 
601db669378SPeter Wemm 	if (cnt.v_page_count == 0)
602db669378SPeter Wemm 		panic("malloc_uninit not allowed before vm init");
603db669378SPeter Wemm 
604ce45b512SBruce Evans 	if (type->ks_limit == 0)
605ce45b512SBruce Evans 		panic("malloc_uninit on uninitialized type");
606ce45b512SBruce Evans 
60799063cf8SBoris Popov #ifdef INVARIANTS
60899063cf8SBoris Popov 	s = splmem();
6099ed346baSBosko Milekic 	mtx_lock(&malloc_mtx);
61099063cf8SBoris Popov 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
61199063cf8SBoris Popov 		kbp = bucket + indx;
61299063cf8SBoris Popov 		freep = (struct freelist*)kbp->kb_next;
61399063cf8SBoris Popov 		while (freep) {
61499063cf8SBoris Popov 			if (freep->type == type)
61599063cf8SBoris Popov 				freep->type = M_FREE;
61699063cf8SBoris Popov 			freep = (struct freelist*)freep->next;
61799063cf8SBoris Popov 		}
61899063cf8SBoris Popov 	}
61999063cf8SBoris Popov 	splx(s);
6209ed346baSBosko Milekic 	mtx_unlock(&malloc_mtx);
62199063cf8SBoris Popov 
62299063cf8SBoris Popov 	if (type->ks_memuse != 0)
62399063cf8SBoris Popov 		printf("malloc_uninit: %ld bytes of '%s' still allocated\n",
62499063cf8SBoris Popov 		    type->ks_memuse, type->ks_shortdesc);
62599063cf8SBoris Popov #endif
62699063cf8SBoris Popov 
627db669378SPeter Wemm 	if (type == kmemstatistics)
628db669378SPeter Wemm 		kmemstatistics = type->ks_next;
629db669378SPeter Wemm 	else {
630db669378SPeter Wemm 		for (t = kmemstatistics; t->ks_next != NULL; t = t->ks_next) {
631db669378SPeter Wemm 			if (t->ks_next == type) {
632db669378SPeter Wemm 				t->ks_next = type->ks_next;
633db669378SPeter Wemm 				break;
634db669378SPeter Wemm 			}
635db669378SPeter Wemm 		}
636db669378SPeter Wemm 	}
637ce45b512SBruce Evans 	type->ks_next = NULL;
638ce45b512SBruce Evans 	type->ks_limit = 0;
639db669378SPeter Wemm }
640