xref: /freebsd/sys/kern/kern_malloc.c (revision 9a02e8c68f3dc9aee3e2d0fe1feb34a15b85e6d1)
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>
42df8bae1dSRodney W. Grimes #include <sys/malloc.h>
4354e7152cSDavid Greenman #include <sys/mbuf.h>
44efeaf95aSDavid Greenman #include <sys/vmmeter.h>
453075778bSJohn Dyson #include <sys/lock.h>
469a02e8c6SJason Evans 
479360d3ebSJason Evans #include <machine/mutex.h>
48df8bae1dSRodney W. Grimes 
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 
603b6fb885SPoul-Henning Kamp MALLOC_DEFINE(M_CACHE, "cache", "Various Dynamically allocated caches");
619ef246c6SBruce Evans MALLOC_DEFINE(M_DEVBUF, "devbuf", "device driver memory");
629ef246c6SBruce Evans MALLOC_DEFINE(M_TEMP, "temp", "misc temporary data buffers");
639ef246c6SBruce Evans 
6482cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6OPT, "ip6opt", "IPv6 options");
6582cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6NDP, "ip6ndp", "IPv6 Neighbor Discovery");
6682cd038dSYoshinobu Inoue 
674590fd3aSDavid Greenman static void kmeminit __P((void *));
682b14f991SJulian Elischer SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL)
692b14f991SJulian Elischer 
70a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FREE, "free", "should be on free list");
71a1c995b6SPoul-Henning Kamp 
72db669378SPeter Wemm static struct malloc_type *kmemstatistics;
73254c6cb3SPoul-Henning Kamp static struct kmembuckets bucket[MINBUCKET + 16];
74254c6cb3SPoul-Henning Kamp static struct kmemusage *kmemusage;
75254c6cb3SPoul-Henning Kamp static char *kmembase;
76043a2f3bSBruce Evans static char *kmemlimit;
771f6889a1SMatthew Dillon 
78606f8eb2SJohn Baldwin struct mtx malloc_mtx;
7969ef67f9SJason Evans 
801f6889a1SMatthew Dillon u_int vm_kmem_size;
81df8bae1dSRodney W. Grimes 
82219cbf59SEivind Eklund #ifdef INVARIANTS
83df8bae1dSRodney W. Grimes /*
84df8bae1dSRodney W. Grimes  * This structure provides a set of masks to catch unaligned frees.
85df8bae1dSRodney W. Grimes  */
8687b6de2bSPoul-Henning Kamp static long addrmask[] = { 0,
87df8bae1dSRodney W. Grimes 	0x00000001, 0x00000003, 0x00000007, 0x0000000f,
88df8bae1dSRodney W. Grimes 	0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
89df8bae1dSRodney W. Grimes 	0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
90df8bae1dSRodney W. Grimes 	0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
91df8bae1dSRodney W. Grimes };
92df8bae1dSRodney W. Grimes 
93df8bae1dSRodney W. Grimes /*
94df8bae1dSRodney W. Grimes  * The WEIRD_ADDR is used as known text to copy into free objects so
95df8bae1dSRodney W. Grimes  * that modifications after frees can be detected.
96df8bae1dSRodney W. Grimes  */
975124d598SDavid Greenman #define WEIRD_ADDR	0xdeadc0de
985124d598SDavid Greenman #define MAX_COPY	64
99df8bae1dSRodney W. Grimes 
100df8bae1dSRodney W. Grimes /*
101df8bae1dSRodney W. Grimes  * Normally the first word of the structure is used to hold the list
102df8bae1dSRodney W. Grimes  * pointer for free objects. However, when running with diagnostics,
103df8bae1dSRodney W. Grimes  * we use the third and fourth fields, so as to catch modifications
104df8bae1dSRodney W. Grimes  * in the most commonly trashed first two words.
105df8bae1dSRodney W. Grimes  */
106df8bae1dSRodney W. Grimes struct freelist {
107df8bae1dSRodney W. Grimes 	long	spare0;
10860a513e9SPoul-Henning Kamp 	struct malloc_type *type;
109df8bae1dSRodney W. Grimes 	long	spare1;
110df8bae1dSRodney W. Grimes 	caddr_t	next;
111df8bae1dSRodney W. Grimes };
1125526d2d9SEivind Eklund #else /* !INVARIANTS */
113df8bae1dSRodney W. Grimes struct freelist {
114df8bae1dSRodney W. Grimes 	caddr_t	next;
115df8bae1dSRodney W. Grimes };
1165526d2d9SEivind Eklund #endif /* INVARIANTS */
117df8bae1dSRodney W. Grimes 
118df8bae1dSRodney W. Grimes /*
1191c7c3c6aSMatthew Dillon  *	malloc:
1201c7c3c6aSMatthew Dillon  *
1211c7c3c6aSMatthew Dillon  *	Allocate a block of memory.
1221c7c3c6aSMatthew Dillon  *
1231c7c3c6aSMatthew Dillon  *	If M_NOWAIT is set, this routine will not block and return NULL if
1241c7c3c6aSMatthew Dillon  *	the allocation fails.
1251c7c3c6aSMatthew Dillon  *
1261c7c3c6aSMatthew Dillon  *	If M_ASLEEP is set (M_NOWAIT must also be set), this routine
1271c7c3c6aSMatthew Dillon  *	will have the side effect of calling asleep() if it returns NULL,
1281c7c3c6aSMatthew Dillon  *	allowing the parent to await() at some future time.
129df8bae1dSRodney W. Grimes  */
130df8bae1dSRodney W. Grimes void *
131df8bae1dSRodney W. Grimes malloc(size, type, flags)
132df8bae1dSRodney W. Grimes 	unsigned long size;
13360a513e9SPoul-Henning Kamp 	struct malloc_type *type;
134254c6cb3SPoul-Henning Kamp 	int flags;
135df8bae1dSRodney W. Grimes {
136df8bae1dSRodney W. Grimes 	register struct kmembuckets *kbp;
137df8bae1dSRodney W. Grimes 	register struct kmemusage *kup;
138df8bae1dSRodney W. Grimes 	register struct freelist *freep;
139df8bae1dSRodney W. Grimes 	long indx, npg, allocsize;
140df8bae1dSRodney W. Grimes 	int s;
141df8bae1dSRodney W. Grimes 	caddr_t va, cp, savedlist;
1425526d2d9SEivind Eklund #ifdef INVARIANTS
143df8bae1dSRodney W. Grimes 	long *end, *lp;
144df8bae1dSRodney W. Grimes 	int copysize;
145d254af07SMatthew Dillon 	const char *savedtype;
146df8bae1dSRodney W. Grimes #endif
14760a513e9SPoul-Henning Kamp 	register struct malloc_type *ksp = type;
148df8bae1dSRodney W. Grimes 
149984982d6SPoul-Henning Kamp #if defined(INVARIANTS) && defined(__i386__)
150984982d6SPoul-Henning Kamp 	if (flags == M_WAITOK)
151984982d6SPoul-Henning Kamp 		KASSERT(intr_nesting_level == 0,
152984982d6SPoul-Henning Kamp 		   ("malloc(M_WAITOK) in interrupt context"));
153984982d6SPoul-Henning Kamp #endif
154df8bae1dSRodney W. Grimes 	indx = BUCKETINDX(size);
155df8bae1dSRodney W. Grimes 	kbp = &bucket[indx];
1568e8cac55SBruce Evans 	s = splmem();
15769ef67f9SJason Evans 	mtx_enter(&malloc_mtx, MTX_DEF);
158df8bae1dSRodney W. Grimes 	while (ksp->ks_memuse >= ksp->ks_limit) {
1591c7c3c6aSMatthew Dillon 		if (flags & M_ASLEEP) {
1601c7c3c6aSMatthew Dillon 			if (ksp->ks_limblocks < 65535)
1611c7c3c6aSMatthew Dillon 				ksp->ks_limblocks++;
1621c7c3c6aSMatthew Dillon 			asleep((caddr_t)ksp, PSWP+2, type->ks_shortdesc, 0);
1631c7c3c6aSMatthew Dillon 		}
164df8bae1dSRodney W. Grimes 		if (flags & M_NOWAIT) {
165df8bae1dSRodney W. Grimes 			splx(s);
16669ef67f9SJason Evans 			mtx_exit(&malloc_mtx, MTX_DEF);
167df8bae1dSRodney W. Grimes 			return ((void *) NULL);
168df8bae1dSRodney W. Grimes 		}
169df8bae1dSRodney W. Grimes 		if (ksp->ks_limblocks < 65535)
170df8bae1dSRodney W. Grimes 			ksp->ks_limblocks++;
17169ef67f9SJason Evans 		msleep((caddr_t)ksp, &malloc_mtx, PSWP+2, type->ks_shortdesc,
17269ef67f9SJason Evans 		    0);
173df8bae1dSRodney W. Grimes 	}
174df8bae1dSRodney W. Grimes 	ksp->ks_size |= 1 << indx;
1755526d2d9SEivind Eklund #ifdef INVARIANTS
176df8bae1dSRodney W. Grimes 	copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
177df8bae1dSRodney W. Grimes #endif
178df8bae1dSRodney W. Grimes 	if (kbp->kb_next == NULL) {
179df8bae1dSRodney W. Grimes 		kbp->kb_last = NULL;
180df8bae1dSRodney W. Grimes 		if (size > MAXALLOCSAVE)
181f8845af0SPoul-Henning Kamp 			allocsize = roundup(size, PAGE_SIZE);
182df8bae1dSRodney W. Grimes 		else
183df8bae1dSRodney W. Grimes 			allocsize = 1 << indx;
184e911eafcSPoul-Henning Kamp 		npg = btoc(allocsize);
18569ef67f9SJason Evans 
18669ef67f9SJason Evans 		mtx_exit(&malloc_mtx, MTX_DEF);
18769ef67f9SJason Evans 		mtx_enter(&Giant, MTX_DEF);
1889f518539SDavid Greenman 		va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags);
18969ef67f9SJason Evans 		mtx_exit(&Giant, MTX_DEF);
19069ef67f9SJason Evans 
191df8bae1dSRodney W. Grimes 		if (va == NULL) {
192df8bae1dSRodney W. Grimes 			splx(s);
193df8bae1dSRodney W. Grimes 			return ((void *) NULL);
194df8bae1dSRodney W. Grimes 		}
19569ef67f9SJason Evans 		/*
19669ef67f9SJason Evans 		 * Enter malloc_mtx after the error check to avoid having to
19769ef67f9SJason Evans 		 * immediately exit it again if there is an error.
19869ef67f9SJason Evans 		 */
19969ef67f9SJason Evans 		mtx_enter(&malloc_mtx, MTX_DEF);
20069ef67f9SJason Evans 
201df8bae1dSRodney W. Grimes 		kbp->kb_total += kbp->kb_elmpercl;
202df8bae1dSRodney W. Grimes 		kup = btokup(va);
203df8bae1dSRodney W. Grimes 		kup->ku_indx = indx;
204df8bae1dSRodney W. Grimes 		if (allocsize > MAXALLOCSAVE) {
205df8bae1dSRodney W. Grimes 			if (npg > 65535)
206df8bae1dSRodney W. Grimes 				panic("malloc: allocation too large");
207df8bae1dSRodney W. Grimes 			kup->ku_pagecnt = npg;
208df8bae1dSRodney W. Grimes 			ksp->ks_memuse += allocsize;
209df8bae1dSRodney W. Grimes 			goto out;
210df8bae1dSRodney W. Grimes 		}
211df8bae1dSRodney W. Grimes 		kup->ku_freecnt = kbp->kb_elmpercl;
212df8bae1dSRodney W. Grimes 		kbp->kb_totalfree += kbp->kb_elmpercl;
213df8bae1dSRodney W. Grimes 		/*
214df8bae1dSRodney W. Grimes 		 * Just in case we blocked while allocating memory,
215df8bae1dSRodney W. Grimes 		 * and someone else also allocated memory for this
216df8bae1dSRodney W. Grimes 		 * bucket, don't assume the list is still empty.
217df8bae1dSRodney W. Grimes 		 */
218df8bae1dSRodney W. Grimes 		savedlist = kbp->kb_next;
219e911eafcSPoul-Henning Kamp 		kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize;
220df8bae1dSRodney W. Grimes 		for (;;) {
221df8bae1dSRodney W. Grimes 			freep = (struct freelist *)cp;
2225526d2d9SEivind Eklund #ifdef INVARIANTS
223df8bae1dSRodney W. Grimes 			/*
224df8bae1dSRodney W. Grimes 			 * Copy in known text to detect modification
225df8bae1dSRodney W. Grimes 			 * after freeing.
226df8bae1dSRodney W. Grimes 			 */
227df8bae1dSRodney W. Grimes 			end = (long *)&cp[copysize];
228df8bae1dSRodney W. Grimes 			for (lp = (long *)cp; lp < end; lp++)
229df8bae1dSRodney W. Grimes 				*lp = WEIRD_ADDR;
230df8bae1dSRodney W. Grimes 			freep->type = M_FREE;
2315526d2d9SEivind Eklund #endif /* INVARIANTS */
232df8bae1dSRodney W. Grimes 			if (cp <= va)
233df8bae1dSRodney W. Grimes 				break;
234df8bae1dSRodney W. Grimes 			cp -= allocsize;
235df8bae1dSRodney W. Grimes 			freep->next = cp;
236df8bae1dSRodney W. Grimes 		}
237df8bae1dSRodney W. Grimes 		freep->next = savedlist;
238df8bae1dSRodney W. Grimes 		if (kbp->kb_last == NULL)
239df8bae1dSRodney W. Grimes 			kbp->kb_last = (caddr_t)freep;
240df8bae1dSRodney W. Grimes 	}
241df8bae1dSRodney W. Grimes 	va = kbp->kb_next;
242df8bae1dSRodney W. Grimes 	kbp->kb_next = ((struct freelist *)va)->next;
2435526d2d9SEivind Eklund #ifdef INVARIANTS
244df8bae1dSRodney W. Grimes 	freep = (struct freelist *)va;
245dc760634SJun Kuriyama 	savedtype = (const char *) freep->type->ks_shortdesc;
246df8bae1dSRodney W. Grimes #if BYTE_ORDER == BIG_ENDIAN
24760a513e9SPoul-Henning Kamp 	freep->type = (struct malloc_type *)WEIRD_ADDR >> 16;
248df8bae1dSRodney W. Grimes #endif
249df8bae1dSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN
25060a513e9SPoul-Henning Kamp 	freep->type = (struct malloc_type *)WEIRD_ADDR;
251df8bae1dSRodney W. Grimes #endif
25286a14a7aSBruce Evans 	if ((intptr_t)(void *)&freep->next & 0x2)
253df8bae1dSRodney W. Grimes 		freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16));
254df8bae1dSRodney W. Grimes 	else
255df8bae1dSRodney W. Grimes 		freep->next = (caddr_t)WEIRD_ADDR;
256df8bae1dSRodney W. Grimes 	end = (long *)&va[copysize];
257df8bae1dSRodney W. Grimes 	for (lp = (long *)va; lp < end; lp++) {
258df8bae1dSRodney W. Grimes 		if (*lp == WEIRD_ADDR)
259df8bae1dSRodney W. Grimes 			continue;
260d974cf4dSBruce Evans 		printf("%s %ld of object %p size %lu %s %s (0x%lx != 0x%lx)\n",
261d974cf4dSBruce Evans 			"Data modified on freelist: word",
262d974cf4dSBruce Evans 			(long)(lp - (long *)va), (void *)va, size,
263d974cf4dSBruce Evans 			"previous type", savedtype, *lp, (u_long)WEIRD_ADDR);
264df8bae1dSRodney W. Grimes 		break;
265df8bae1dSRodney W. Grimes 	}
266df8bae1dSRodney W. Grimes 	freep->spare0 = 0;
2675526d2d9SEivind Eklund #endif /* INVARIANTS */
268df8bae1dSRodney W. Grimes 	kup = btokup(va);
269df8bae1dSRodney W. Grimes 	if (kup->ku_indx != indx)
270df8bae1dSRodney W. Grimes 		panic("malloc: wrong bucket");
271df8bae1dSRodney W. Grimes 	if (kup->ku_freecnt == 0)
272df8bae1dSRodney W. Grimes 		panic("malloc: lost data");
273df8bae1dSRodney W. Grimes 	kup->ku_freecnt--;
274df8bae1dSRodney W. Grimes 	kbp->kb_totalfree--;
275df8bae1dSRodney W. Grimes 	ksp->ks_memuse += 1 << indx;
276df8bae1dSRodney W. Grimes out:
277df8bae1dSRodney W. Grimes 	kbp->kb_calls++;
278df8bae1dSRodney W. Grimes 	ksp->ks_inuse++;
279df8bae1dSRodney W. Grimes 	ksp->ks_calls++;
280df8bae1dSRodney W. Grimes 	if (ksp->ks_memuse > ksp->ks_maxused)
281df8bae1dSRodney W. Grimes 		ksp->ks_maxused = ksp->ks_memuse;
282df8bae1dSRodney W. Grimes 	splx(s);
28369ef67f9SJason Evans 	mtx_exit(&malloc_mtx, MTX_DEF);
284df8bae1dSRodney W. Grimes 	return ((void *) va);
285df8bae1dSRodney W. Grimes }
286df8bae1dSRodney W. Grimes 
287df8bae1dSRodney W. Grimes /*
2881c7c3c6aSMatthew Dillon  *	free:
2891c7c3c6aSMatthew Dillon  *
290df8bae1dSRodney W. Grimes  *	Free a block of memory allocated by malloc.
2911c7c3c6aSMatthew Dillon  *
2921c7c3c6aSMatthew Dillon  *	This routine may not block.
293df8bae1dSRodney W. Grimes  */
294df8bae1dSRodney W. Grimes void
295df8bae1dSRodney W. Grimes free(addr, type)
296df8bae1dSRodney W. Grimes 	void *addr;
29760a513e9SPoul-Henning Kamp 	struct malloc_type *type;
298df8bae1dSRodney W. Grimes {
299df8bae1dSRodney W. Grimes 	register struct kmembuckets *kbp;
300df8bae1dSRodney W. Grimes 	register struct kmemusage *kup;
301df8bae1dSRodney W. Grimes 	register struct freelist *freep;
302df8bae1dSRodney W. Grimes 	long size;
303df8bae1dSRodney W. Grimes 	int s;
3045526d2d9SEivind Eklund #ifdef INVARIANTS
305ca67a4e4SPoul-Henning Kamp 	struct freelist *fp;
306df8bae1dSRodney W. Grimes 	long *end, *lp, alloc, copysize;
307df8bae1dSRodney W. Grimes #endif
30860a513e9SPoul-Henning Kamp 	register struct malloc_type *ksp = type;
309254c6cb3SPoul-Henning Kamp 
3105526d2d9SEivind Eklund 	KASSERT(kmembase <= (char *)addr && (char *)addr < kmemlimit,
3115526d2d9SEivind Eklund 	    ("free: address %p out of range", (void *)addr));
312df8bae1dSRodney W. Grimes 	kup = btokup(addr);
313df8bae1dSRodney W. Grimes 	size = 1 << kup->ku_indx;
314df8bae1dSRodney W. Grimes 	kbp = &bucket[kup->ku_indx];
315b1897c19SJulian Elischer 	s = splmem();
31669ef67f9SJason Evans 	mtx_enter(&malloc_mtx, MTX_DEF);
3175526d2d9SEivind Eklund #ifdef INVARIANTS
318df8bae1dSRodney W. Grimes 	/*
319df8bae1dSRodney W. Grimes 	 * Check for returns of data that do not point to the
320df8bae1dSRodney W. Grimes 	 * beginning of the allocation.
321df8bae1dSRodney W. Grimes 	 */
322f8845af0SPoul-Henning Kamp 	if (size > PAGE_SIZE)
323f8845af0SPoul-Henning Kamp 		alloc = addrmask[BUCKETINDX(PAGE_SIZE)];
324df8bae1dSRodney W. Grimes 	else
325df8bae1dSRodney W. Grimes 		alloc = addrmask[kup->ku_indx];
32686a14a7aSBruce Evans 	if (((uintptr_t)(void *)addr & alloc) != 0)
327d974cf4dSBruce Evans 		panic("free: unaligned addr %p, size %ld, type %s, mask %ld",
328d974cf4dSBruce Evans 		    (void *)addr, size, type->ks_shortdesc, alloc);
3295526d2d9SEivind Eklund #endif /* INVARIANTS */
330df8bae1dSRodney W. Grimes 	if (size > MAXALLOCSAVE) {
33169ef67f9SJason Evans 		mtx_exit(&malloc_mtx, MTX_DEF);
33269ef67f9SJason Evans 		mtx_enter(&Giant, MTX_DEF);
333df8bae1dSRodney W. Grimes 		kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt));
33469ef67f9SJason Evans 		mtx_exit(&Giant, MTX_DEF);
33569ef67f9SJason Evans 		mtx_enter(&malloc_mtx, MTX_DEF);
33669ef67f9SJason Evans 
337e911eafcSPoul-Henning Kamp 		size = kup->ku_pagecnt << PAGE_SHIFT;
338df8bae1dSRodney W. Grimes 		ksp->ks_memuse -= size;
339df8bae1dSRodney W. Grimes 		kup->ku_indx = 0;
340df8bae1dSRodney W. Grimes 		kup->ku_pagecnt = 0;
341df8bae1dSRodney W. Grimes 		if (ksp->ks_memuse + size >= ksp->ks_limit &&
342df8bae1dSRodney W. Grimes 		    ksp->ks_memuse < ksp->ks_limit)
343df8bae1dSRodney W. Grimes 			wakeup((caddr_t)ksp);
344df8bae1dSRodney W. Grimes 		ksp->ks_inuse--;
345df8bae1dSRodney W. Grimes 		kbp->kb_total -= 1;
346df8bae1dSRodney W. Grimes 		splx(s);
34769ef67f9SJason Evans 		mtx_exit(&malloc_mtx, MTX_DEF);
348df8bae1dSRodney W. Grimes 		return;
349df8bae1dSRodney W. Grimes 	}
350df8bae1dSRodney W. Grimes 	freep = (struct freelist *)addr;
3515526d2d9SEivind Eklund #ifdef INVARIANTS
352df8bae1dSRodney W. Grimes 	/*
353df8bae1dSRodney W. Grimes 	 * Check for multiple frees. Use a quick check to see if
354df8bae1dSRodney W. Grimes 	 * it looks free before laboriously searching the freelist.
355df8bae1dSRodney W. Grimes 	 */
356df8bae1dSRodney W. Grimes 	if (freep->spare0 == WEIRD_ADDR) {
357ca67a4e4SPoul-Henning Kamp 		fp = (struct freelist *)kbp->kb_next;
358ca67a4e4SPoul-Henning Kamp 		while (fp) {
359219cbf59SEivind Eklund 			if (fp->spare0 != WEIRD_ADDR)
3605526d2d9SEivind Eklund 				panic("free: free item %p modified", fp);
361219cbf59SEivind Eklund 			else if (addr == (caddr_t)fp)
3625526d2d9SEivind Eklund 				panic("free: multiple freed item %p", addr);
363ca67a4e4SPoul-Henning Kamp 			fp = (struct freelist *)fp->next;
364df8bae1dSRodney W. Grimes 		}
365df8bae1dSRodney W. Grimes 	}
366df8bae1dSRodney W. Grimes 	/*
367df8bae1dSRodney W. Grimes 	 * Copy in known text to detect modification after freeing
368df8bae1dSRodney W. Grimes 	 * and to make it look free. Also, save the type being freed
369df8bae1dSRodney W. Grimes 	 * so we can list likely culprit if modification is detected
370df8bae1dSRodney W. Grimes 	 * when the object is reallocated.
371df8bae1dSRodney W. Grimes 	 */
372df8bae1dSRodney W. Grimes 	copysize = size < MAX_COPY ? size : MAX_COPY;
373df8bae1dSRodney W. Grimes 	end = (long *)&((caddr_t)addr)[copysize];
374df8bae1dSRodney W. Grimes 	for (lp = (long *)addr; lp < end; lp++)
375df8bae1dSRodney W. Grimes 		*lp = WEIRD_ADDR;
376df8bae1dSRodney W. Grimes 	freep->type = type;
3775526d2d9SEivind Eklund #endif /* INVARIANTS */
378df8bae1dSRodney W. Grimes 	kup->ku_freecnt++;
379dfd5dee1SPeter Wemm 	if (kup->ku_freecnt >= kbp->kb_elmpercl) {
380df8bae1dSRodney W. Grimes 		if (kup->ku_freecnt > kbp->kb_elmpercl)
381df8bae1dSRodney W. Grimes 			panic("free: multiple frees");
382df8bae1dSRodney W. Grimes 		else if (kbp->kb_totalfree > kbp->kb_highwat)
383df8bae1dSRodney W. Grimes 			kbp->kb_couldfree++;
384dfd5dee1SPeter Wemm 	}
385df8bae1dSRodney W. Grimes 	kbp->kb_totalfree++;
386df8bae1dSRodney W. Grimes 	ksp->ks_memuse -= size;
387df8bae1dSRodney W. Grimes 	if (ksp->ks_memuse + size >= ksp->ks_limit &&
388df8bae1dSRodney W. Grimes 	    ksp->ks_memuse < ksp->ks_limit)
389df8bae1dSRodney W. Grimes 		wakeup((caddr_t)ksp);
390df8bae1dSRodney W. Grimes 	ksp->ks_inuse--;
39114bf02f8SJohn Dyson #ifdef OLD_MALLOC_MEMORY_POLICY
392df8bae1dSRodney W. Grimes 	if (kbp->kb_next == NULL)
393df8bae1dSRodney W. Grimes 		kbp->kb_next = addr;
394df8bae1dSRodney W. Grimes 	else
395df8bae1dSRodney W. Grimes 		((struct freelist *)kbp->kb_last)->next = addr;
396df8bae1dSRodney W. Grimes 	freep->next = NULL;
397df8bae1dSRodney W. Grimes 	kbp->kb_last = addr;
39814bf02f8SJohn Dyson #else
39914bf02f8SJohn Dyson 	/*
40014bf02f8SJohn Dyson 	 * Return memory to the head of the queue for quick reuse.  This
40114bf02f8SJohn Dyson 	 * can improve performance by improving the probability of the
40214bf02f8SJohn Dyson 	 * item being in the cache when it is reused.
40314bf02f8SJohn Dyson 	 */
40414bf02f8SJohn Dyson 	if (kbp->kb_next == NULL) {
40514bf02f8SJohn Dyson 		kbp->kb_next = addr;
40614bf02f8SJohn Dyson 		kbp->kb_last = addr;
40714bf02f8SJohn Dyson 		freep->next = NULL;
40814bf02f8SJohn Dyson 	} else {
40914bf02f8SJohn Dyson 		freep->next = kbp->kb_next;
41014bf02f8SJohn Dyson 		kbp->kb_next = addr;
41114bf02f8SJohn Dyson 	}
41214bf02f8SJohn Dyson #endif
413df8bae1dSRodney W. Grimes 	splx(s);
41469ef67f9SJason Evans 	mtx_exit(&malloc_mtx, MTX_DEF);
415df8bae1dSRodney W. Grimes }
416df8bae1dSRodney W. Grimes 
417df8bae1dSRodney W. Grimes /*
418df8bae1dSRodney W. Grimes  * Initialize the kernel memory allocator
419df8bae1dSRodney W. Grimes  */
4202b14f991SJulian Elischer /* ARGSUSED*/
4212b14f991SJulian Elischer static void
422d841aaa7SBruce Evans kmeminit(dummy)
423d841aaa7SBruce Evans 	void *dummy;
424df8bae1dSRodney W. Grimes {
425df8bae1dSRodney W. Grimes 	register long indx;
42627b8623fSDavid Greenman 	u_long npg;
42727b8623fSDavid Greenman 	u_long mem_size;
42827b8623fSDavid Greenman 	u_long xvm_kmem_size;
429df8bae1dSRodney W. Grimes 
430df8bae1dSRodney W. Grimes #if	((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
431cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE not power of 2"
432df8bae1dSRodney W. Grimes #endif
433df8bae1dSRodney W. Grimes #if	(MAXALLOCSAVE > MINALLOCSIZE * 32768)
434cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too big"
435df8bae1dSRodney W. Grimes #endif
436f8845af0SPoul-Henning Kamp #if	(MAXALLOCSAVE < PAGE_SIZE)
437cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too small"
438df8bae1dSRodney W. Grimes #endif
4398a58a9f6SJohn Dyson 
44069ef67f9SJason Evans 	mtx_init(&malloc_mtx, "malloc", MTX_DEF);
44169ef67f9SJason Evans 
4428a58a9f6SJohn Dyson 	/*
4438a58a9f6SJohn Dyson 	 * Try to auto-tune the kernel memory size, so that it is
4448a58a9f6SJohn Dyson 	 * more applicable for a wider range of machine sizes.
4458a58a9f6SJohn Dyson 	 * On an X86, a VM_KMEM_SIZE_SCALE value of 4 is good, while
4468a58a9f6SJohn Dyson 	 * a VM_KMEM_SIZE of 12MB is a fair compromise.  The
4478a58a9f6SJohn Dyson 	 * VM_KMEM_SIZE_MAX is dependent on the maximum KVA space
4488a58a9f6SJohn Dyson 	 * available, and on an X86 with a total KVA space of 256MB,
4498a58a9f6SJohn Dyson 	 * try to keep VM_KMEM_SIZE_MAX at 80MB or below.
4508a58a9f6SJohn Dyson 	 *
4518a58a9f6SJohn Dyson 	 * Note that the kmem_map is also used by the zone allocator,
4528a58a9f6SJohn Dyson 	 * so make sure that there is enough space.
4538a58a9f6SJohn Dyson 	 */
454134c934cSMike Smith 	xvm_kmem_size = VM_KMEM_SIZE;
4558a58a9f6SJohn Dyson 	mem_size = cnt.v_page_count * PAGE_SIZE;
4568a58a9f6SJohn Dyson 
4578a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_SCALE)
458134c934cSMike Smith 	if ((mem_size / VM_KMEM_SIZE_SCALE) > xvm_kmem_size)
459134c934cSMike Smith 		xvm_kmem_size = mem_size / VM_KMEM_SIZE_SCALE;
4608a58a9f6SJohn Dyson #endif
4618a58a9f6SJohn Dyson 
4628a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_MAX)
463134c934cSMike Smith 	if (xvm_kmem_size >= VM_KMEM_SIZE_MAX)
464134c934cSMike Smith 		xvm_kmem_size = VM_KMEM_SIZE_MAX;
4658a58a9f6SJohn Dyson #endif
4668a58a9f6SJohn Dyson 
4678de6e8e1SMike Smith 	/* Allow final override from the kernel environment */
468134c934cSMike Smith 	TUNABLE_INT_FETCH("kern.vm.kmem.size", xvm_kmem_size, vm_kmem_size);
4698de6e8e1SMike Smith 
47027b8623fSDavid Greenman 	/*
47127b8623fSDavid Greenman 	 * Limit kmem virtual size to twice the physical memory.
47227b8623fSDavid Greenman 	 * This allows for kmem map sparseness, but limits the size
47327b8623fSDavid Greenman 	 * to something sane. Be careful to not overflow the 32bit
47427b8623fSDavid Greenman 	 * ints while doing the check.
47527b8623fSDavid Greenman 	 */
47627b8623fSDavid Greenman 	if ((vm_kmem_size / 2) > (cnt.v_page_count * PAGE_SIZE))
47727b8623fSDavid Greenman 		vm_kmem_size = 2 * cnt.v_page_count * PAGE_SIZE;
4788a58a9f6SJohn Dyson 
4798a58a9f6SJohn Dyson 	npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + vm_kmem_size)
480cb7545a9SGarrett Wollman 		/ PAGE_SIZE;
4810d94caffSDavid Greenman 
482df8bae1dSRodney W. Grimes 	kmemusage = (struct kmemusage *) kmem_alloc(kernel_map,
483df8bae1dSRodney W. Grimes 		(vm_size_t)(npg * sizeof(struct kmemusage)));
484df8bae1dSRodney W. Grimes 	kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase,
4852d8acc0fSJohn Dyson 		(vm_offset_t *)&kmemlimit, (vm_size_t)(npg * PAGE_SIZE));
4863075778bSJohn Dyson 	kmem_map->system_map = 1;
487df8bae1dSRodney W. Grimes 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
488f8845af0SPoul-Henning Kamp 		if (1 << indx >= PAGE_SIZE)
489df8bae1dSRodney W. Grimes 			bucket[indx].kb_elmpercl = 1;
490df8bae1dSRodney W. Grimes 		else
491f8845af0SPoul-Henning Kamp 			bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
492df8bae1dSRodney W. Grimes 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
493df8bae1dSRodney W. Grimes 	}
494254c6cb3SPoul-Henning Kamp }
495254c6cb3SPoul-Henning Kamp 
496db669378SPeter Wemm void
497db669378SPeter Wemm malloc_init(data)
498db669378SPeter Wemm 	void *data;
499254c6cb3SPoul-Henning Kamp {
500db669378SPeter Wemm 	struct malloc_type *type = (struct malloc_type *)data;
501254c6cb3SPoul-Henning Kamp 
502d1bbc7ecSPoul-Henning Kamp 	if (type->ks_magic != M_MAGIC)
503d1bbc7ecSPoul-Henning Kamp 		panic("malloc type lacks magic");
504d1bbc7ecSPoul-Henning Kamp 
505ce45b512SBruce Evans 	if (type->ks_limit != 0)
506db669378SPeter Wemm 		return;
507db669378SPeter Wemm 
508d4060a87SJohn Dyson 	if (cnt.v_page_count == 0)
509d4060a87SJohn Dyson 		panic("malloc_init not allowed before vm init");
510d4060a87SJohn Dyson 
51107bbd7f1SDavid Greenman 	/*
5128a58a9f6SJohn Dyson 	 * The default limits for each malloc region is 1/2 of the
5138a58a9f6SJohn Dyson 	 * malloc portion of the kmem map size.
51407bbd7f1SDavid Greenman 	 */
5158a58a9f6SJohn Dyson 	type->ks_limit = vm_kmem_size / 2;
516254c6cb3SPoul-Henning Kamp 	type->ks_next = kmemstatistics;
517254c6cb3SPoul-Henning Kamp 	kmemstatistics = type;
518df8bae1dSRodney W. Grimes }
519db669378SPeter Wemm 
520db669378SPeter Wemm void
521db669378SPeter Wemm malloc_uninit(data)
522db669378SPeter Wemm 	void *data;
523db669378SPeter Wemm {
524db669378SPeter Wemm 	struct malloc_type *type = (struct malloc_type *)data;
525db669378SPeter Wemm 	struct malloc_type *t;
5265badeabaSBoris Popov #ifdef INVARIANTS
52799063cf8SBoris Popov 	struct kmembuckets *kbp;
52899063cf8SBoris Popov 	struct freelist *freep;
52999063cf8SBoris Popov 	long indx;
53099063cf8SBoris Popov 	int s;
53199063cf8SBoris Popov #endif
532db669378SPeter Wemm 
533db669378SPeter Wemm 	if (type->ks_magic != M_MAGIC)
534db669378SPeter Wemm 		panic("malloc type lacks magic");
535db669378SPeter Wemm 
536db669378SPeter Wemm 	if (cnt.v_page_count == 0)
537db669378SPeter Wemm 		panic("malloc_uninit not allowed before vm init");
538db669378SPeter Wemm 
539ce45b512SBruce Evans 	if (type->ks_limit == 0)
540ce45b512SBruce Evans 		panic("malloc_uninit on uninitialized type");
541ce45b512SBruce Evans 
54299063cf8SBoris Popov #ifdef INVARIANTS
54399063cf8SBoris Popov 	s = splmem();
54469ef67f9SJason Evans 	mtx_enter(&malloc_mtx, MTX_DEF);
54599063cf8SBoris Popov 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
54699063cf8SBoris Popov 		kbp = bucket + indx;
54799063cf8SBoris Popov 		freep = (struct freelist*)kbp->kb_next;
54899063cf8SBoris Popov 		while (freep) {
54999063cf8SBoris Popov 			if (freep->type == type)
55099063cf8SBoris Popov 				freep->type = M_FREE;
55199063cf8SBoris Popov 			freep = (struct freelist*)freep->next;
55299063cf8SBoris Popov 		}
55399063cf8SBoris Popov 	}
55499063cf8SBoris Popov 	splx(s);
55569ef67f9SJason Evans 	mtx_exit(&malloc_mtx, MTX_DEF);
55699063cf8SBoris Popov 
55799063cf8SBoris Popov 	if (type->ks_memuse != 0)
55899063cf8SBoris Popov 		printf("malloc_uninit: %ld bytes of '%s' still allocated\n",
55999063cf8SBoris Popov 		    type->ks_memuse, type->ks_shortdesc);
56099063cf8SBoris Popov #endif
56199063cf8SBoris Popov 
562db669378SPeter Wemm 	if (type == kmemstatistics)
563db669378SPeter Wemm 		kmemstatistics = type->ks_next;
564db669378SPeter Wemm 	else {
565db669378SPeter Wemm 		for (t = kmemstatistics; t->ks_next != NULL; t = t->ks_next) {
566db669378SPeter Wemm 			if (t->ks_next == type) {
567db669378SPeter Wemm 				t->ks_next = type->ks_next;
568db669378SPeter Wemm 				break;
569db669378SPeter Wemm 			}
570db669378SPeter Wemm 		}
571db669378SPeter Wemm 	}
572ce45b512SBruce Evans 	type->ks_next = NULL;
573ce45b512SBruce Evans 	type->ks_limit = 0;
574db669378SPeter Wemm }
575