xref: /freebsd/sys/kern/kern_malloc.c (revision db66937855926ee7438055046190e3c4ad8e17df)
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
34db669378SPeter Wemm  * $Id: kern_malloc.c,v 1.48 1998/10/25 17:44:51 phk Exp $
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>
42254c6cb3SPoul-Henning Kamp #define MALLOC_INSTANTIATE
43df8bae1dSRodney W. Grimes #include <sys/malloc.h>
4454e7152cSDavid Greenman #include <sys/mbuf.h>
45efeaf95aSDavid Greenman #include <sys/vmmeter.h>
463075778bSJohn Dyson #include <sys/lock.h>
47df8bae1dSRodney W. Grimes 
48df8bae1dSRodney W. Grimes #include <vm/vm.h>
49efeaf95aSDavid Greenman #include <vm/vm_param.h>
50df8bae1dSRodney W. Grimes #include <vm/vm_kern.h>
51efeaf95aSDavid Greenman #include <vm/vm_extern.h>
523075778bSJohn Dyson #include <vm/pmap.h>
533075778bSJohn Dyson #include <vm/vm_map.h>
54df8bae1dSRodney W. Grimes 
554590fd3aSDavid Greenman static void kmeminit __P((void *));
562b14f991SJulian Elischer SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL)
572b14f991SJulian Elischer 
58a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FREE, "free", "should be on free list");
59a1c995b6SPoul-Henning Kamp 
60db669378SPeter Wemm static struct malloc_type *kmemstatistics;
61254c6cb3SPoul-Henning Kamp static struct kmembuckets bucket[MINBUCKET + 16];
62254c6cb3SPoul-Henning Kamp static struct kmemusage *kmemusage;
63254c6cb3SPoul-Henning Kamp static char *kmembase;
64043a2f3bSBruce Evans static char *kmemlimit;
658a58a9f6SJohn Dyson static int vm_kmem_size;
66df8bae1dSRodney W. Grimes 
67df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
68df8bae1dSRodney W. Grimes /*
69df8bae1dSRodney W. Grimes  * This structure provides a set of masks to catch unaligned frees.
70df8bae1dSRodney W. Grimes  */
7187b6de2bSPoul-Henning Kamp static long addrmask[] = { 0,
72df8bae1dSRodney W. Grimes 	0x00000001, 0x00000003, 0x00000007, 0x0000000f,
73df8bae1dSRodney W. Grimes 	0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
74df8bae1dSRodney W. Grimes 	0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
75df8bae1dSRodney W. Grimes 	0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
76df8bae1dSRodney W. Grimes };
77df8bae1dSRodney W. Grimes 
78df8bae1dSRodney W. Grimes /*
79df8bae1dSRodney W. Grimes  * The WEIRD_ADDR is used as known text to copy into free objects so
80df8bae1dSRodney W. Grimes  * that modifications after frees can be detected.
81df8bae1dSRodney W. Grimes  */
825124d598SDavid Greenman #define WEIRD_ADDR	0xdeadc0de
835124d598SDavid Greenman #define MAX_COPY	64
84df8bae1dSRodney W. Grimes 
85df8bae1dSRodney W. Grimes /*
86df8bae1dSRodney W. Grimes  * Normally the first word of the structure is used to hold the list
87df8bae1dSRodney W. Grimes  * pointer for free objects. However, when running with diagnostics,
88df8bae1dSRodney W. Grimes  * we use the third and fourth fields, so as to catch modifications
89df8bae1dSRodney W. Grimes  * in the most commonly trashed first two words.
90df8bae1dSRodney W. Grimes  */
91df8bae1dSRodney W. Grimes struct freelist {
92df8bae1dSRodney W. Grimes 	long	spare0;
9360a513e9SPoul-Henning Kamp 	struct malloc_type *type;
94df8bae1dSRodney W. Grimes 	long	spare1;
95df8bae1dSRodney W. Grimes 	caddr_t	next;
96df8bae1dSRodney W. Grimes };
97df8bae1dSRodney W. Grimes #else /* !DIAGNOSTIC */
98df8bae1dSRodney W. Grimes struct freelist {
99df8bae1dSRodney W. Grimes 	caddr_t	next;
100df8bae1dSRodney W. Grimes };
101df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
102df8bae1dSRodney W. Grimes 
103df8bae1dSRodney W. Grimes /*
104df8bae1dSRodney W. Grimes  * Allocate a block of memory
105df8bae1dSRodney W. Grimes  */
106df8bae1dSRodney W. Grimes void *
107df8bae1dSRodney W. Grimes malloc(size, type, flags)
108df8bae1dSRodney W. Grimes 	unsigned long size;
10960a513e9SPoul-Henning Kamp 	struct malloc_type *type;
110254c6cb3SPoul-Henning Kamp 	int flags;
111df8bae1dSRodney W. Grimes {
112df8bae1dSRodney W. Grimes 	register struct kmembuckets *kbp;
113df8bae1dSRodney W. Grimes 	register struct kmemusage *kup;
114df8bae1dSRodney W. Grimes 	register struct freelist *freep;
115df8bae1dSRodney W. Grimes 	long indx, npg, allocsize;
116df8bae1dSRodney W. Grimes 	int s;
117df8bae1dSRodney W. Grimes 	caddr_t va, cp, savedlist;
118df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
119df8bae1dSRodney W. Grimes 	long *end, *lp;
120df8bae1dSRodney W. Grimes 	int copysize;
121df8bae1dSRodney W. Grimes 	char *savedtype;
122df8bae1dSRodney W. Grimes #endif
12360a513e9SPoul-Henning Kamp 	register struct malloc_type *ksp = type;
124df8bae1dSRodney W. Grimes 
125254c6cb3SPoul-Henning Kamp 	if (!type->ks_next)
126254c6cb3SPoul-Henning Kamp 		malloc_init(type);
127254c6cb3SPoul-Henning Kamp 
128df8bae1dSRodney W. Grimes 	indx = BUCKETINDX(size);
129df8bae1dSRodney W. Grimes 	kbp = &bucket[indx];
130b1897c19SJulian Elischer 	s = splmem();
131df8bae1dSRodney W. Grimes 	while (ksp->ks_memuse >= ksp->ks_limit) {
132df8bae1dSRodney W. Grimes 		if (flags & M_NOWAIT) {
133df8bae1dSRodney W. Grimes 			splx(s);
134df8bae1dSRodney W. Grimes 			return ((void *) NULL);
135df8bae1dSRodney W. Grimes 		}
136df8bae1dSRodney W. Grimes 		if (ksp->ks_limblocks < 65535)
137df8bae1dSRodney W. Grimes 			ksp->ks_limblocks++;
138254c6cb3SPoul-Henning Kamp 		tsleep((caddr_t)ksp, PSWP+2, type->ks_shortdesc, 0);
139df8bae1dSRodney W. Grimes 	}
140df8bae1dSRodney W. Grimes 	ksp->ks_size |= 1 << indx;
141df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
142df8bae1dSRodney W. Grimes 	copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
143df8bae1dSRodney W. Grimes #endif
144df8bae1dSRodney W. Grimes 	if (kbp->kb_next == NULL) {
145df8bae1dSRodney W. Grimes 		kbp->kb_last = NULL;
146df8bae1dSRodney W. Grimes 		if (size > MAXALLOCSAVE)
147f8845af0SPoul-Henning Kamp 			allocsize = roundup(size, PAGE_SIZE);
148df8bae1dSRodney W. Grimes 		else
149df8bae1dSRodney W. Grimes 			allocsize = 1 << indx;
150e911eafcSPoul-Henning Kamp 		npg = btoc(allocsize);
1519f518539SDavid Greenman 		va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags);
152df8bae1dSRodney W. Grimes 		if (va == NULL) {
153df8bae1dSRodney W. Grimes 			splx(s);
154df8bae1dSRodney W. Grimes 			return ((void *) NULL);
155df8bae1dSRodney W. Grimes 		}
156df8bae1dSRodney W. Grimes 		kbp->kb_total += kbp->kb_elmpercl;
157df8bae1dSRodney W. Grimes 		kup = btokup(va);
158df8bae1dSRodney W. Grimes 		kup->ku_indx = indx;
159df8bae1dSRodney W. Grimes 		if (allocsize > MAXALLOCSAVE) {
160df8bae1dSRodney W. Grimes 			if (npg > 65535)
161df8bae1dSRodney W. Grimes 				panic("malloc: allocation too large");
162df8bae1dSRodney W. Grimes 			kup->ku_pagecnt = npg;
163df8bae1dSRodney W. Grimes 			ksp->ks_memuse += allocsize;
164df8bae1dSRodney W. Grimes 			goto out;
165df8bae1dSRodney W. Grimes 		}
166df8bae1dSRodney W. Grimes 		kup->ku_freecnt = kbp->kb_elmpercl;
167df8bae1dSRodney W. Grimes 		kbp->kb_totalfree += kbp->kb_elmpercl;
168df8bae1dSRodney W. Grimes 		/*
169df8bae1dSRodney W. Grimes 		 * Just in case we blocked while allocating memory,
170df8bae1dSRodney W. Grimes 		 * and someone else also allocated memory for this
171df8bae1dSRodney W. Grimes 		 * bucket, don't assume the list is still empty.
172df8bae1dSRodney W. Grimes 		 */
173df8bae1dSRodney W. Grimes 		savedlist = kbp->kb_next;
174e911eafcSPoul-Henning Kamp 		kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize;
175df8bae1dSRodney W. Grimes 		for (;;) {
176df8bae1dSRodney W. Grimes 			freep = (struct freelist *)cp;
177df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
178df8bae1dSRodney W. Grimes 			/*
179df8bae1dSRodney W. Grimes 			 * Copy in known text to detect modification
180df8bae1dSRodney W. Grimes 			 * after freeing.
181df8bae1dSRodney W. Grimes 			 */
182df8bae1dSRodney W. Grimes 			end = (long *)&cp[copysize];
183df8bae1dSRodney W. Grimes 			for (lp = (long *)cp; lp < end; lp++)
184df8bae1dSRodney W. Grimes 				*lp = WEIRD_ADDR;
185df8bae1dSRodney W. Grimes 			freep->type = M_FREE;
186df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
187df8bae1dSRodney W. Grimes 			if (cp <= va)
188df8bae1dSRodney W. Grimes 				break;
189df8bae1dSRodney W. Grimes 			cp -= allocsize;
190df8bae1dSRodney W. Grimes 			freep->next = cp;
191df8bae1dSRodney W. Grimes 		}
192df8bae1dSRodney W. Grimes 		freep->next = savedlist;
193df8bae1dSRodney W. Grimes 		if (kbp->kb_last == NULL)
194df8bae1dSRodney W. Grimes 			kbp->kb_last = (caddr_t)freep;
195df8bae1dSRodney W. Grimes 	}
196df8bae1dSRodney W. Grimes 	va = kbp->kb_next;
197df8bae1dSRodney W. Grimes 	kbp->kb_next = ((struct freelist *)va)->next;
198df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
199df8bae1dSRodney W. Grimes 	freep = (struct freelist *)va;
20095461b45SJohn Dyson 	savedtype = (char *) type->ks_shortdesc;
201df8bae1dSRodney W. Grimes #if BYTE_ORDER == BIG_ENDIAN
20260a513e9SPoul-Henning Kamp 	freep->type = (struct malloc_type *)WEIRD_ADDR >> 16;
203df8bae1dSRodney W. Grimes #endif
204df8bae1dSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN
20560a513e9SPoul-Henning Kamp 	freep->type = (struct malloc_type *)WEIRD_ADDR;
206df8bae1dSRodney W. Grimes #endif
20786a14a7aSBruce Evans 	if ((intptr_t)(void *)&freep->next & 0x2)
208df8bae1dSRodney W. Grimes 		freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16));
209df8bae1dSRodney W. Grimes 	else
210df8bae1dSRodney W. Grimes 		freep->next = (caddr_t)WEIRD_ADDR;
211df8bae1dSRodney W. Grimes 	end = (long *)&va[copysize];
212df8bae1dSRodney W. Grimes 	for (lp = (long *)va; lp < end; lp++) {
213df8bae1dSRodney W. Grimes 		if (*lp == WEIRD_ADDR)
214df8bae1dSRodney W. Grimes 			continue;
215d974cf4dSBruce Evans 		printf("%s %ld of object %p size %lu %s %s (0x%lx != 0x%lx)\n",
216d974cf4dSBruce Evans 			"Data modified on freelist: word",
217d974cf4dSBruce Evans 			(long)(lp - (long *)va), (void *)va, size,
218d974cf4dSBruce Evans 			"previous type", savedtype, *lp, (u_long)WEIRD_ADDR);
219df8bae1dSRodney W. Grimes 		break;
220df8bae1dSRodney W. Grimes 	}
221df8bae1dSRodney W. Grimes 	freep->spare0 = 0;
222df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
223df8bae1dSRodney W. Grimes 	kup = btokup(va);
224df8bae1dSRodney W. Grimes 	if (kup->ku_indx != indx)
225df8bae1dSRodney W. Grimes 		panic("malloc: wrong bucket");
226df8bae1dSRodney W. Grimes 	if (kup->ku_freecnt == 0)
227df8bae1dSRodney W. Grimes 		panic("malloc: lost data");
228df8bae1dSRodney W. Grimes 	kup->ku_freecnt--;
229df8bae1dSRodney W. Grimes 	kbp->kb_totalfree--;
230df8bae1dSRodney W. Grimes 	ksp->ks_memuse += 1 << indx;
231df8bae1dSRodney W. Grimes out:
232df8bae1dSRodney W. Grimes 	kbp->kb_calls++;
233df8bae1dSRodney W. Grimes 	ksp->ks_inuse++;
234df8bae1dSRodney W. Grimes 	ksp->ks_calls++;
235df8bae1dSRodney W. Grimes 	if (ksp->ks_memuse > ksp->ks_maxused)
236df8bae1dSRodney W. Grimes 		ksp->ks_maxused = ksp->ks_memuse;
237df8bae1dSRodney W. Grimes 	splx(s);
238df8bae1dSRodney W. Grimes 	return ((void *) va);
239df8bae1dSRodney W. Grimes }
240df8bae1dSRodney W. Grimes 
241df8bae1dSRodney W. Grimes /*
242df8bae1dSRodney W. Grimes  * Free a block of memory allocated by malloc.
243df8bae1dSRodney W. Grimes  */
244df8bae1dSRodney W. Grimes void
245df8bae1dSRodney W. Grimes free(addr, type)
246df8bae1dSRodney W. Grimes 	void *addr;
24760a513e9SPoul-Henning Kamp 	struct malloc_type *type;
248df8bae1dSRodney W. Grimes {
249df8bae1dSRodney W. Grimes 	register struct kmembuckets *kbp;
250df8bae1dSRodney W. Grimes 	register struct kmemusage *kup;
251df8bae1dSRodney W. Grimes 	register struct freelist *freep;
252df8bae1dSRodney W. Grimes 	long size;
253df8bae1dSRodney W. Grimes 	int s;
254df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
255ca67a4e4SPoul-Henning Kamp 	struct freelist *fp;
256df8bae1dSRodney W. Grimes 	long *end, *lp, alloc, copysize;
257df8bae1dSRodney W. Grimes #endif
25860a513e9SPoul-Henning Kamp 	register struct malloc_type *ksp = type;
259254c6cb3SPoul-Henning Kamp 
260254c6cb3SPoul-Henning Kamp 	if (!type->ks_next)
26122c64348SPoul-Henning Kamp 		panic("freeing with unknown type (%s)", type->ks_shortdesc);
262df8bae1dSRodney W. Grimes 
26317dda4c9SDavid Greenman #ifdef DIAGNOSTIC
26417dda4c9SDavid Greenman 	if ((char *)addr < kmembase || (char *)addr >= kmemlimit) {
265d974cf4dSBruce Evans 		panic("free: address %p out of range", (void *)addr);
26617dda4c9SDavid Greenman 	}
26717dda4c9SDavid Greenman #endif
268df8bae1dSRodney W. Grimes 	kup = btokup(addr);
269df8bae1dSRodney W. Grimes 	size = 1 << kup->ku_indx;
270df8bae1dSRodney W. Grimes 	kbp = &bucket[kup->ku_indx];
271b1897c19SJulian Elischer 	s = splmem();
272df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
273df8bae1dSRodney W. Grimes 	/*
274df8bae1dSRodney W. Grimes 	 * Check for returns of data that do not point to the
275df8bae1dSRodney W. Grimes 	 * beginning of the allocation.
276df8bae1dSRodney W. Grimes 	 */
277f8845af0SPoul-Henning Kamp 	if (size > PAGE_SIZE)
278f8845af0SPoul-Henning Kamp 		alloc = addrmask[BUCKETINDX(PAGE_SIZE)];
279df8bae1dSRodney W. Grimes 	else
280df8bae1dSRodney W. Grimes 		alloc = addrmask[kup->ku_indx];
28186a14a7aSBruce Evans 	if (((uintptr_t)(void *)addr & alloc) != 0)
282d974cf4dSBruce Evans 		panic("free: unaligned addr %p, size %ld, type %s, mask %ld",
283d974cf4dSBruce Evans 		    (void *)addr, size, type->ks_shortdesc, alloc);
284df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
285df8bae1dSRodney W. Grimes 	if (size > MAXALLOCSAVE) {
286df8bae1dSRodney W. Grimes 		kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt));
287e911eafcSPoul-Henning Kamp 		size = kup->ku_pagecnt << PAGE_SHIFT;
288df8bae1dSRodney W. Grimes 		ksp->ks_memuse -= size;
289df8bae1dSRodney W. Grimes 		kup->ku_indx = 0;
290df8bae1dSRodney W. Grimes 		kup->ku_pagecnt = 0;
291df8bae1dSRodney W. Grimes 		if (ksp->ks_memuse + size >= ksp->ks_limit &&
292df8bae1dSRodney W. Grimes 		    ksp->ks_memuse < ksp->ks_limit)
293df8bae1dSRodney W. Grimes 			wakeup((caddr_t)ksp);
294df8bae1dSRodney W. Grimes 		ksp->ks_inuse--;
295df8bae1dSRodney W. Grimes 		kbp->kb_total -= 1;
296df8bae1dSRodney W. Grimes 		splx(s);
297df8bae1dSRodney W. Grimes 		return;
298df8bae1dSRodney W. Grimes 	}
299df8bae1dSRodney W. Grimes 	freep = (struct freelist *)addr;
300df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
301df8bae1dSRodney W. Grimes 	/*
302df8bae1dSRodney W. Grimes 	 * Check for multiple frees. Use a quick check to see if
303df8bae1dSRodney W. Grimes 	 * it looks free before laboriously searching the freelist.
304df8bae1dSRodney W. Grimes 	 */
305df8bae1dSRodney W. Grimes 	if (freep->spare0 == WEIRD_ADDR) {
306ca67a4e4SPoul-Henning Kamp 		fp = (struct freelist *)kbp->kb_next;
307ca67a4e4SPoul-Henning Kamp 		while (fp) {
308ca67a4e4SPoul-Henning Kamp 			if (fp->spare0 != WEIRD_ADDR) {
309ca67a4e4SPoul-Henning Kamp 				printf("trashed free item %p\n", fp);
310ca67a4e4SPoul-Henning Kamp 				panic("free: free item modified");
311ca67a4e4SPoul-Henning Kamp 			} else if (addr == (caddr_t)fp) {
312ca67a4e4SPoul-Henning Kamp 				printf("multiple freed item %p\n", addr);
313ca67a4e4SPoul-Henning Kamp 				panic("free: multiple free");
314ca67a4e4SPoul-Henning Kamp 			}
315ca67a4e4SPoul-Henning Kamp 			fp = (struct freelist *)fp->next;
316df8bae1dSRodney W. Grimes 		}
317df8bae1dSRodney W. Grimes 	}
318df8bae1dSRodney W. Grimes 	/*
319df8bae1dSRodney W. Grimes 	 * Copy in known text to detect modification after freeing
320df8bae1dSRodney W. Grimes 	 * and to make it look free. Also, save the type being freed
321df8bae1dSRodney W. Grimes 	 * so we can list likely culprit if modification is detected
322df8bae1dSRodney W. Grimes 	 * when the object is reallocated.
323df8bae1dSRodney W. Grimes 	 */
324df8bae1dSRodney W. Grimes 	copysize = size < MAX_COPY ? size : MAX_COPY;
325df8bae1dSRodney W. Grimes 	end = (long *)&((caddr_t)addr)[copysize];
326df8bae1dSRodney W. Grimes 	for (lp = (long *)addr; lp < end; lp++)
327df8bae1dSRodney W. Grimes 		*lp = WEIRD_ADDR;
328df8bae1dSRodney W. Grimes 	freep->type = type;
329df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
330df8bae1dSRodney W. Grimes 	kup->ku_freecnt++;
331df8bae1dSRodney W. Grimes 	if (kup->ku_freecnt >= kbp->kb_elmpercl)
332df8bae1dSRodney W. Grimes 		if (kup->ku_freecnt > kbp->kb_elmpercl)
333df8bae1dSRodney W. Grimes 			panic("free: multiple frees");
334df8bae1dSRodney W. Grimes 		else if (kbp->kb_totalfree > kbp->kb_highwat)
335df8bae1dSRodney W. Grimes 			kbp->kb_couldfree++;
336df8bae1dSRodney W. Grimes 	kbp->kb_totalfree++;
337df8bae1dSRodney W. Grimes 	ksp->ks_memuse -= size;
338df8bae1dSRodney W. Grimes 	if (ksp->ks_memuse + size >= ksp->ks_limit &&
339df8bae1dSRodney W. Grimes 	    ksp->ks_memuse < ksp->ks_limit)
340df8bae1dSRodney W. Grimes 		wakeup((caddr_t)ksp);
341df8bae1dSRodney W. Grimes 	ksp->ks_inuse--;
34214bf02f8SJohn Dyson #ifdef OLD_MALLOC_MEMORY_POLICY
343df8bae1dSRodney W. Grimes 	if (kbp->kb_next == NULL)
344df8bae1dSRodney W. Grimes 		kbp->kb_next = addr;
345df8bae1dSRodney W. Grimes 	else
346df8bae1dSRodney W. Grimes 		((struct freelist *)kbp->kb_last)->next = addr;
347df8bae1dSRodney W. Grimes 	freep->next = NULL;
348df8bae1dSRodney W. Grimes 	kbp->kb_last = addr;
34914bf02f8SJohn Dyson #else
35014bf02f8SJohn Dyson 	/*
35114bf02f8SJohn Dyson 	 * Return memory to the head of the queue for quick reuse.  This
35214bf02f8SJohn Dyson 	 * can improve performance by improving the probability of the
35314bf02f8SJohn Dyson 	 * item being in the cache when it is reused.
35414bf02f8SJohn Dyson 	 */
35514bf02f8SJohn Dyson 	if (kbp->kb_next == NULL) {
35614bf02f8SJohn Dyson 		kbp->kb_next = addr;
35714bf02f8SJohn Dyson 		kbp->kb_last = addr;
35814bf02f8SJohn Dyson 		freep->next = NULL;
35914bf02f8SJohn Dyson 	} else {
36014bf02f8SJohn Dyson 		freep->next = kbp->kb_next;
36114bf02f8SJohn Dyson 		kbp->kb_next = addr;
36214bf02f8SJohn Dyson 	}
36314bf02f8SJohn Dyson #endif
364df8bae1dSRodney W. Grimes 	splx(s);
365df8bae1dSRodney W. Grimes }
366df8bae1dSRodney W. Grimes 
367df8bae1dSRodney W. Grimes /*
368df8bae1dSRodney W. Grimes  * Initialize the kernel memory allocator
369df8bae1dSRodney W. Grimes  */
3702b14f991SJulian Elischer /* ARGSUSED*/
3712b14f991SJulian Elischer static void
372d841aaa7SBruce Evans kmeminit(dummy)
373d841aaa7SBruce Evans 	void *dummy;
374df8bae1dSRodney W. Grimes {
375df8bae1dSRodney W. Grimes 	register long indx;
376df8bae1dSRodney W. Grimes 	int npg;
3778a58a9f6SJohn Dyson 	int mem_size;
378df8bae1dSRodney W. Grimes 
379df8bae1dSRodney W. Grimes #if	((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
380cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE not power of 2"
381df8bae1dSRodney W. Grimes #endif
382df8bae1dSRodney W. Grimes #if	(MAXALLOCSAVE > MINALLOCSIZE * 32768)
383cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too big"
384df8bae1dSRodney W. Grimes #endif
385f8845af0SPoul-Henning Kamp #if	(MAXALLOCSAVE < PAGE_SIZE)
386cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too small"
387df8bae1dSRodney W. Grimes #endif
3888a58a9f6SJohn Dyson 
3898a58a9f6SJohn Dyson 	/*
3908a58a9f6SJohn Dyson 	 * Try to auto-tune the kernel memory size, so that it is
3918a58a9f6SJohn Dyson 	 * more applicable for a wider range of machine sizes.
3928a58a9f6SJohn Dyson 	 * On an X86, a VM_KMEM_SIZE_SCALE value of 4 is good, while
3938a58a9f6SJohn Dyson 	 * a VM_KMEM_SIZE of 12MB is a fair compromise.  The
3948a58a9f6SJohn Dyson 	 * VM_KMEM_SIZE_MAX is dependent on the maximum KVA space
3958a58a9f6SJohn Dyson 	 * available, and on an X86 with a total KVA space of 256MB,
3968a58a9f6SJohn Dyson 	 * try to keep VM_KMEM_SIZE_MAX at 80MB or below.
3978a58a9f6SJohn Dyson 	 *
3988a58a9f6SJohn Dyson 	 * Note that the kmem_map is also used by the zone allocator,
3998a58a9f6SJohn Dyson 	 * so make sure that there is enough space.
4008a58a9f6SJohn Dyson 	 */
4018a58a9f6SJohn Dyson 	vm_kmem_size = VM_KMEM_SIZE;
4028a58a9f6SJohn Dyson 	mem_size = cnt.v_page_count * PAGE_SIZE;
4038a58a9f6SJohn Dyson 
4048a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_SCALE)
4058a58a9f6SJohn Dyson 	if ((mem_size / VM_KMEM_SIZE_SCALE) > vm_kmem_size)
4068a58a9f6SJohn Dyson 		vm_kmem_size = mem_size / VM_KMEM_SIZE_SCALE;
4078a58a9f6SJohn Dyson #endif
4088a58a9f6SJohn Dyson 
4098a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_MAX)
4108a58a9f6SJohn Dyson 	if (vm_kmem_size >= VM_KMEM_SIZE_MAX)
4118a58a9f6SJohn Dyson 		vm_kmem_size = VM_KMEM_SIZE_MAX;
4128a58a9f6SJohn Dyson #endif
4138a58a9f6SJohn Dyson 
4148a58a9f6SJohn Dyson 	if (vm_kmem_size > 2 * (cnt.v_page_count * PAGE_SIZE))
4158a58a9f6SJohn Dyson 		vm_kmem_size = 2 * (cnt.v_page_count * PAGE_SIZE);
4168a58a9f6SJohn Dyson 
4178a58a9f6SJohn Dyson 	npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + vm_kmem_size)
418cb7545a9SGarrett Wollman 		/ PAGE_SIZE;
4190d94caffSDavid Greenman 
420df8bae1dSRodney W. Grimes 	kmemusage = (struct kmemusage *) kmem_alloc(kernel_map,
421df8bae1dSRodney W. Grimes 		(vm_size_t)(npg * sizeof(struct kmemusage)));
422df8bae1dSRodney W. Grimes 	kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase,
4232d8acc0fSJohn Dyson 		(vm_offset_t *)&kmemlimit, (vm_size_t)(npg * PAGE_SIZE));
4243075778bSJohn Dyson 	kmem_map->system_map = 1;
425df8bae1dSRodney W. Grimes 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
426f8845af0SPoul-Henning Kamp 		if (1 << indx >= PAGE_SIZE)
427df8bae1dSRodney W. Grimes 			bucket[indx].kb_elmpercl = 1;
428df8bae1dSRodney W. Grimes 		else
429f8845af0SPoul-Henning Kamp 			bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
430df8bae1dSRodney W. Grimes 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
431df8bae1dSRodney W. Grimes 	}
432254c6cb3SPoul-Henning Kamp }
433254c6cb3SPoul-Henning Kamp 
434db669378SPeter Wemm void
435db669378SPeter Wemm malloc_init(data)
436db669378SPeter Wemm 	void *data;
437254c6cb3SPoul-Henning Kamp {
438db669378SPeter Wemm 	struct malloc_type *type = (struct malloc_type *)data;
439254c6cb3SPoul-Henning Kamp 
440d1bbc7ecSPoul-Henning Kamp 	if (type->ks_magic != M_MAGIC)
441d1bbc7ecSPoul-Henning Kamp 		panic("malloc type lacks magic");
442d1bbc7ecSPoul-Henning Kamp 
443db669378SPeter Wemm 	if (type->ks_next)
444db669378SPeter Wemm 		return;
445db669378SPeter Wemm 
446d4060a87SJohn Dyson 	if (cnt.v_page_count == 0)
447d4060a87SJohn Dyson 		panic("malloc_init not allowed before vm init");
448d4060a87SJohn Dyson 
44907bbd7f1SDavid Greenman 	/*
4508a58a9f6SJohn Dyson 	 * The default limits for each malloc region is 1/2 of the
4518a58a9f6SJohn Dyson 	 * malloc portion of the kmem map size.
45207bbd7f1SDavid Greenman 	 */
4538a58a9f6SJohn Dyson 	type->ks_limit = vm_kmem_size / 2;
454254c6cb3SPoul-Henning Kamp 	type->ks_next = kmemstatistics;
455254c6cb3SPoul-Henning Kamp 	kmemstatistics = type;
456df8bae1dSRodney W. Grimes }
457db669378SPeter Wemm 
458db669378SPeter Wemm void
459db669378SPeter Wemm malloc_uninit(data)
460db669378SPeter Wemm 	void *data;
461db669378SPeter Wemm {
462db669378SPeter Wemm 	struct malloc_type *type = (struct malloc_type *)data;
463db669378SPeter Wemm 	struct malloc_type *t;
464db669378SPeter Wemm 
465db669378SPeter Wemm 	if (type->ks_magic != M_MAGIC)
466db669378SPeter Wemm 		panic("malloc type lacks magic");
467db669378SPeter Wemm 
468db669378SPeter Wemm 	if (cnt.v_page_count == 0)
469db669378SPeter Wemm 		panic("malloc_uninit not allowed before vm init");
470db669378SPeter Wemm 
471db669378SPeter Wemm 	if (type == kmemstatistics)
472db669378SPeter Wemm 		kmemstatistics = type->ks_next;
473db669378SPeter Wemm 	else {
474db669378SPeter Wemm 		for (t = kmemstatistics; t->ks_next != NULL; t = t->ks_next) {
475db669378SPeter Wemm 			if (t->ks_next == type) {
476db669378SPeter Wemm 				t->ks_next = type->ks_next;
477db669378SPeter Wemm 				break;
478db669378SPeter Wemm 			}
479db669378SPeter Wemm 		}
480db669378SPeter Wemm 	}
481db669378SPeter Wemm }
482