xref: /freebsd/sys/kern/kern_malloc.c (revision 3075778b634c3a76ea954560848faff5f097d418)
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
343075778bSJohn Dyson  * $Id: kern_malloc.c,v 1.27 1997/06/24 09:41:00 davidg Exp $
35df8bae1dSRodney W. Grimes  */
36df8bae1dSRodney W. Grimes 
37df8bae1dSRodney W. Grimes #include <sys/param.h>
3826f9a767SRodney W. Grimes #include <sys/systm.h>
39df8bae1dSRodney W. Grimes #include <sys/proc.h>
40df8bae1dSRodney W. Grimes #include <sys/kernel.h>
41df8bae1dSRodney W. Grimes #include <sys/malloc.h>
4254e7152cSDavid Greenman #include <sys/mbuf.h>
43efeaf95aSDavid Greenman #include <sys/vmmeter.h>
443075778bSJohn Dyson #include <sys/lock.h>
45df8bae1dSRodney W. Grimes 
46df8bae1dSRodney W. Grimes #include <vm/vm.h>
47efeaf95aSDavid Greenman #include <vm/vm_param.h>
48df8bae1dSRodney W. Grimes #include <vm/vm_kern.h>
49efeaf95aSDavid Greenman #include <vm/vm_extern.h>
503075778bSJohn Dyson #include <vm/pmap.h>
513075778bSJohn Dyson #include <vm/vm_map.h>
52df8bae1dSRodney W. Grimes 
534590fd3aSDavid Greenman static void kmeminit __P((void *));
542b14f991SJulian Elischer SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL)
552b14f991SJulian Elischer 
5687b6de2bSPoul-Henning Kamp static struct kmembuckets bucket[MINBUCKET + 16];
57df8bae1dSRodney W. Grimes struct kmemstats kmemstats[M_LAST];
58df8bae1dSRodney W. Grimes struct kmemusage *kmemusage;
59df8bae1dSRodney W. Grimes char *kmembase, *kmemlimit;
60df8bae1dSRodney W. Grimes char *memname[] = INITKMEMNAMES;
61df8bae1dSRodney W. Grimes 
62df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
63df8bae1dSRodney W. Grimes /*
64df8bae1dSRodney W. Grimes  * This structure provides a set of masks to catch unaligned frees.
65df8bae1dSRodney W. Grimes  */
6687b6de2bSPoul-Henning Kamp static long addrmask[] = { 0,
67df8bae1dSRodney W. Grimes 	0x00000001, 0x00000003, 0x00000007, 0x0000000f,
68df8bae1dSRodney W. Grimes 	0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
69df8bae1dSRodney W. Grimes 	0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
70df8bae1dSRodney W. Grimes 	0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
71df8bae1dSRodney W. Grimes };
72df8bae1dSRodney W. Grimes 
73df8bae1dSRodney W. Grimes /*
74df8bae1dSRodney W. Grimes  * The WEIRD_ADDR is used as known text to copy into free objects so
75df8bae1dSRodney W. Grimes  * that modifications after frees can be detected.
76df8bae1dSRodney W. Grimes  */
775124d598SDavid Greenman #define WEIRD_ADDR	0xdeadc0de
785124d598SDavid Greenman #define MAX_COPY	64
79df8bae1dSRodney W. Grimes 
80df8bae1dSRodney W. Grimes /*
81df8bae1dSRodney W. Grimes  * Normally the first word of the structure is used to hold the list
82df8bae1dSRodney W. Grimes  * pointer for free objects. However, when running with diagnostics,
83df8bae1dSRodney W. Grimes  * we use the third and fourth fields, so as to catch modifications
84df8bae1dSRodney W. Grimes  * in the most commonly trashed first two words.
85df8bae1dSRodney W. Grimes  */
86df8bae1dSRodney W. Grimes struct freelist {
87df8bae1dSRodney W. Grimes 	long	spare0;
88df8bae1dSRodney W. Grimes 	short	type;
89df8bae1dSRodney W. Grimes 	long	spare1;
90df8bae1dSRodney W. Grimes 	caddr_t	next;
91df8bae1dSRodney W. Grimes };
92df8bae1dSRodney W. Grimes #else /* !DIAGNOSTIC */
93df8bae1dSRodney W. Grimes struct freelist {
94df8bae1dSRodney W. Grimes 	caddr_t	next;
95df8bae1dSRodney W. Grimes };
96df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
97df8bae1dSRodney W. Grimes 
98df8bae1dSRodney W. Grimes /*
99df8bae1dSRodney W. Grimes  * Allocate a block of memory
100df8bae1dSRodney W. Grimes  */
101df8bae1dSRodney W. Grimes void *
102df8bae1dSRodney W. Grimes malloc(size, type, flags)
103df8bae1dSRodney W. Grimes 	unsigned long size;
104df8bae1dSRodney W. Grimes 	int type, flags;
105df8bae1dSRodney W. Grimes {
106df8bae1dSRodney W. Grimes 	register struct kmembuckets *kbp;
107df8bae1dSRodney W. Grimes 	register struct kmemusage *kup;
108df8bae1dSRodney W. Grimes 	register struct freelist *freep;
109df8bae1dSRodney W. Grimes 	long indx, npg, allocsize;
110df8bae1dSRodney W. Grimes 	int s;
111df8bae1dSRodney W. Grimes 	caddr_t va, cp, savedlist;
112df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
113df8bae1dSRodney W. Grimes 	long *end, *lp;
114df8bae1dSRodney W. Grimes 	int copysize;
115df8bae1dSRodney W. Grimes 	char *savedtype;
116df8bae1dSRodney W. Grimes #endif
117df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
118df8bae1dSRodney W. Grimes 	register struct kmemstats *ksp = &kmemstats[type];
119df8bae1dSRodney W. Grimes 
120df8bae1dSRodney W. Grimes 	if (((unsigned long)type) > M_LAST)
121df8bae1dSRodney W. Grimes 		panic("malloc - bogus type");
122df8bae1dSRodney W. Grimes #endif
123df8bae1dSRodney W. Grimes 	indx = BUCKETINDX(size);
124df8bae1dSRodney W. Grimes 	kbp = &bucket[indx];
125763424fcSDavid Greenman 	s = splhigh();
126df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
127df8bae1dSRodney W. Grimes 	while (ksp->ks_memuse >= ksp->ks_limit) {
128df8bae1dSRodney W. Grimes 		if (flags & M_NOWAIT) {
129df8bae1dSRodney W. Grimes 			splx(s);
130df8bae1dSRodney W. Grimes 			return ((void *) NULL);
131df8bae1dSRodney W. Grimes 		}
132df8bae1dSRodney W. Grimes 		if (ksp->ks_limblocks < 65535)
133df8bae1dSRodney W. Grimes 			ksp->ks_limblocks++;
134df8bae1dSRodney W. Grimes 		tsleep((caddr_t)ksp, PSWP+2, memname[type], 0);
135df8bae1dSRodney W. Grimes 	}
136df8bae1dSRodney W. Grimes 	ksp->ks_size |= 1 << indx;
137df8bae1dSRodney W. Grimes #endif
138df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
139df8bae1dSRodney W. Grimes 	copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
140df8bae1dSRodney W. Grimes #endif
141df8bae1dSRodney W. Grimes 	if (kbp->kb_next == NULL) {
142df8bae1dSRodney W. Grimes 		kbp->kb_last = NULL;
143df8bae1dSRodney W. Grimes 		if (size > MAXALLOCSAVE)
144f8845af0SPoul-Henning Kamp 			allocsize = roundup(size, PAGE_SIZE);
145df8bae1dSRodney W. Grimes 		else
146df8bae1dSRodney W. Grimes 			allocsize = 1 << indx;
147e911eafcSPoul-Henning Kamp 		npg = btoc(allocsize);
1489f518539SDavid Greenman 		va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags);
149df8bae1dSRodney W. Grimes 		if (va == NULL) {
150df8bae1dSRodney W. Grimes 			splx(s);
151df8bae1dSRodney W. Grimes 			return ((void *) NULL);
152df8bae1dSRodney W. Grimes 		}
153df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
154df8bae1dSRodney W. Grimes 		kbp->kb_total += kbp->kb_elmpercl;
155df8bae1dSRodney W. Grimes #endif
156df8bae1dSRodney W. Grimes 		kup = btokup(va);
157df8bae1dSRodney W. Grimes 		kup->ku_indx = indx;
158df8bae1dSRodney W. Grimes 		if (allocsize > MAXALLOCSAVE) {
159df8bae1dSRodney W. Grimes 			if (npg > 65535)
160df8bae1dSRodney W. Grimes 				panic("malloc: allocation too large");
161df8bae1dSRodney W. Grimes 			kup->ku_pagecnt = npg;
162df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
163df8bae1dSRodney W. Grimes 			ksp->ks_memuse += allocsize;
164df8bae1dSRodney W. Grimes #endif
165df8bae1dSRodney W. Grimes 			goto out;
166df8bae1dSRodney W. Grimes 		}
167df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
168df8bae1dSRodney W. Grimes 		kup->ku_freecnt = kbp->kb_elmpercl;
169df8bae1dSRodney W. Grimes 		kbp->kb_totalfree += kbp->kb_elmpercl;
170df8bae1dSRodney W. Grimes #endif
171df8bae1dSRodney W. Grimes 		/*
172df8bae1dSRodney W. Grimes 		 * Just in case we blocked while allocating memory,
173df8bae1dSRodney W. Grimes 		 * and someone else also allocated memory for this
174df8bae1dSRodney W. Grimes 		 * bucket, don't assume the list is still empty.
175df8bae1dSRodney W. Grimes 		 */
176df8bae1dSRodney W. Grimes 		savedlist = kbp->kb_next;
177e911eafcSPoul-Henning Kamp 		kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize;
178df8bae1dSRodney W. Grimes 		for (;;) {
179df8bae1dSRodney W. Grimes 			freep = (struct freelist *)cp;
180df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
181df8bae1dSRodney W. Grimes 			/*
182df8bae1dSRodney W. Grimes 			 * Copy in known text to detect modification
183df8bae1dSRodney W. Grimes 			 * after freeing.
184df8bae1dSRodney W. Grimes 			 */
185df8bae1dSRodney W. Grimes 			end = (long *)&cp[copysize];
186df8bae1dSRodney W. Grimes 			for (lp = (long *)cp; lp < end; lp++)
187df8bae1dSRodney W. Grimes 				*lp = WEIRD_ADDR;
188df8bae1dSRodney W. Grimes 			freep->type = M_FREE;
189df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
190df8bae1dSRodney W. Grimes 			if (cp <= va)
191df8bae1dSRodney W. Grimes 				break;
192df8bae1dSRodney W. Grimes 			cp -= allocsize;
193df8bae1dSRodney W. Grimes 			freep->next = cp;
194df8bae1dSRodney W. Grimes 		}
195df8bae1dSRodney W. Grimes 		freep->next = savedlist;
196df8bae1dSRodney W. Grimes 		if (kbp->kb_last == NULL)
197df8bae1dSRodney W. Grimes 			kbp->kb_last = (caddr_t)freep;
198df8bae1dSRodney W. Grimes 	}
199df8bae1dSRodney W. Grimes 	va = kbp->kb_next;
200df8bae1dSRodney W. Grimes 	kbp->kb_next = ((struct freelist *)va)->next;
201df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
202df8bae1dSRodney W. Grimes 	freep = (struct freelist *)va;
203df8bae1dSRodney W. Grimes 	savedtype = (unsigned)freep->type < M_LAST ?
204df8bae1dSRodney W. Grimes 		memname[freep->type] : "???";
205df8bae1dSRodney W. Grimes #if BYTE_ORDER == BIG_ENDIAN
206df8bae1dSRodney W. Grimes 	freep->type = WEIRD_ADDR >> 16;
207df8bae1dSRodney W. Grimes #endif
208df8bae1dSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN
209df8bae1dSRodney W. Grimes 	freep->type = (short)WEIRD_ADDR;
210df8bae1dSRodney W. Grimes #endif
211df8bae1dSRodney W. Grimes 	if (((long)(&freep->next)) & 0x2)
212df8bae1dSRodney W. Grimes 		freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16));
213df8bae1dSRodney W. Grimes 	else
214df8bae1dSRodney W. Grimes 		freep->next = (caddr_t)WEIRD_ADDR;
215df8bae1dSRodney W. Grimes 	end = (long *)&va[copysize];
216df8bae1dSRodney W. Grimes 	for (lp = (long *)va; lp < end; lp++) {
217df8bae1dSRodney W. Grimes 		if (*lp == WEIRD_ADDR)
218df8bae1dSRodney W. Grimes 			continue;
219797f2d22SPoul-Henning Kamp 		printf("%s %d of object %p size %ld %s %s (0x%lx != 0x%x)\n",
220df8bae1dSRodney W. Grimes 			"Data modified on freelist: word", lp - (long *)va,
221df8bae1dSRodney W. Grimes 			va, size, "previous type", savedtype, *lp, WEIRD_ADDR);
222df8bae1dSRodney W. Grimes 		break;
223df8bae1dSRodney W. Grimes 	}
224df8bae1dSRodney W. Grimes 	freep->spare0 = 0;
225df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
226df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
227df8bae1dSRodney W. Grimes 	kup = btokup(va);
228df8bae1dSRodney W. Grimes 	if (kup->ku_indx != indx)
229df8bae1dSRodney W. Grimes 		panic("malloc: wrong bucket");
230df8bae1dSRodney W. Grimes 	if (kup->ku_freecnt == 0)
231df8bae1dSRodney W. Grimes 		panic("malloc: lost data");
232df8bae1dSRodney W. Grimes 	kup->ku_freecnt--;
233df8bae1dSRodney W. Grimes 	kbp->kb_totalfree--;
234df8bae1dSRodney W. Grimes 	ksp->ks_memuse += 1 << indx;
235df8bae1dSRodney W. Grimes out:
236df8bae1dSRodney W. Grimes 	kbp->kb_calls++;
237df8bae1dSRodney W. Grimes 	ksp->ks_inuse++;
238df8bae1dSRodney W. Grimes 	ksp->ks_calls++;
239df8bae1dSRodney W. Grimes 	if (ksp->ks_memuse > ksp->ks_maxused)
240df8bae1dSRodney W. Grimes 		ksp->ks_maxused = ksp->ks_memuse;
241df8bae1dSRodney W. Grimes #else
242df8bae1dSRodney W. Grimes out:
243df8bae1dSRodney W. Grimes #endif
244df8bae1dSRodney W. Grimes 	splx(s);
245df8bae1dSRodney W. Grimes 	return ((void *) va);
246df8bae1dSRodney W. Grimes }
247df8bae1dSRodney W. Grimes 
248df8bae1dSRodney W. Grimes /*
249df8bae1dSRodney W. Grimes  * Free a block of memory allocated by malloc.
250df8bae1dSRodney W. Grimes  */
251df8bae1dSRodney W. Grimes void
252df8bae1dSRodney W. Grimes free(addr, type)
253df8bae1dSRodney W. Grimes 	void *addr;
254df8bae1dSRodney W. Grimes 	int type;
255df8bae1dSRodney W. Grimes {
256df8bae1dSRodney W. Grimes 	register struct kmembuckets *kbp;
257df8bae1dSRodney W. Grimes 	register struct kmemusage *kup;
258df8bae1dSRodney W. Grimes 	register struct freelist *freep;
259df8bae1dSRodney W. Grimes 	long size;
260df8bae1dSRodney W. Grimes 	int s;
261df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
262ca67a4e4SPoul-Henning Kamp 	struct freelist *fp;
263df8bae1dSRodney W. Grimes 	long *end, *lp, alloc, copysize;
264df8bae1dSRodney W. Grimes #endif
265df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
266df8bae1dSRodney W. Grimes 	register struct kmemstats *ksp = &kmemstats[type];
267df8bae1dSRodney W. Grimes #endif
268df8bae1dSRodney W. Grimes 
26917dda4c9SDavid Greenman #ifdef DIAGNOSTIC
27017dda4c9SDavid Greenman 	if ((char *)addr < kmembase || (char *)addr >= kmemlimit) {
271edf8a815SDavid Greenman 		panic("free: address 0x%x out of range", addr);
27217dda4c9SDavid Greenman 	}
27317dda4c9SDavid Greenman 	if ((u_long)type > M_LAST) {
274edf8a815SDavid Greenman 		panic("free: type %d out of range", type);
27517dda4c9SDavid Greenman 	}
27617dda4c9SDavid Greenman #endif
277df8bae1dSRodney W. Grimes 	kup = btokup(addr);
278df8bae1dSRodney W. Grimes 	size = 1 << kup->ku_indx;
279df8bae1dSRodney W. Grimes 	kbp = &bucket[kup->ku_indx];
280763424fcSDavid Greenman 	s = splhigh();
281df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
282df8bae1dSRodney W. Grimes 	/*
283df8bae1dSRodney W. Grimes 	 * Check for returns of data that do not point to the
284df8bae1dSRodney W. Grimes 	 * beginning of the allocation.
285df8bae1dSRodney W. Grimes 	 */
286f8845af0SPoul-Henning Kamp 	if (size > PAGE_SIZE)
287f8845af0SPoul-Henning Kamp 		alloc = addrmask[BUCKETINDX(PAGE_SIZE)];
288df8bae1dSRodney W. Grimes 	else
289df8bae1dSRodney W. Grimes 		alloc = addrmask[kup->ku_indx];
290df8bae1dSRodney W. Grimes 	if (((u_long)addr & alloc) != 0)
291edf8a815SDavid Greenman 		panic("free: unaligned addr 0x%x, size %d, type %s, mask %d",
292df8bae1dSRodney W. Grimes 			addr, size, memname[type], alloc);
293df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
294df8bae1dSRodney W. Grimes 	if (size > MAXALLOCSAVE) {
295df8bae1dSRodney W. Grimes 		kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt));
296df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
297e911eafcSPoul-Henning Kamp 		size = kup->ku_pagecnt << PAGE_SHIFT;
298df8bae1dSRodney W. Grimes 		ksp->ks_memuse -= size;
299df8bae1dSRodney W. Grimes 		kup->ku_indx = 0;
300df8bae1dSRodney W. Grimes 		kup->ku_pagecnt = 0;
301df8bae1dSRodney W. Grimes 		if (ksp->ks_memuse + size >= ksp->ks_limit &&
302df8bae1dSRodney W. Grimes 		    ksp->ks_memuse < ksp->ks_limit)
303df8bae1dSRodney W. Grimes 			wakeup((caddr_t)ksp);
304df8bae1dSRodney W. Grimes 		ksp->ks_inuse--;
305df8bae1dSRodney W. Grimes 		kbp->kb_total -= 1;
306df8bae1dSRodney W. Grimes #endif
307df8bae1dSRodney W. Grimes 		splx(s);
308df8bae1dSRodney W. Grimes 		return;
309df8bae1dSRodney W. Grimes 	}
310df8bae1dSRodney W. Grimes 	freep = (struct freelist *)addr;
311df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC
312df8bae1dSRodney W. Grimes 	/*
313df8bae1dSRodney W. Grimes 	 * Check for multiple frees. Use a quick check to see if
314df8bae1dSRodney W. Grimes 	 * it looks free before laboriously searching the freelist.
315df8bae1dSRodney W. Grimes 	 */
316df8bae1dSRodney W. Grimes 	if (freep->spare0 == WEIRD_ADDR) {
317ca67a4e4SPoul-Henning Kamp 		fp = (struct freelist *)kbp->kb_next;
318ca67a4e4SPoul-Henning Kamp 		while (fp) {
319ca67a4e4SPoul-Henning Kamp 			if (fp->spare0 != WEIRD_ADDR) {
320ca67a4e4SPoul-Henning Kamp 				printf("trashed free item %p\n", fp);
321ca67a4e4SPoul-Henning Kamp 				panic("free: free item modified");
322ca67a4e4SPoul-Henning Kamp 			} else if (addr == (caddr_t)fp) {
323ca67a4e4SPoul-Henning Kamp 				printf("multiple freed item %p\n", addr);
324ca67a4e4SPoul-Henning Kamp 				panic("free: multiple free");
325ca67a4e4SPoul-Henning Kamp 			}
326ca67a4e4SPoul-Henning Kamp 			fp = (struct freelist *)fp->next;
327df8bae1dSRodney W. Grimes 		}
328df8bae1dSRodney W. Grimes 	}
329df8bae1dSRodney W. Grimes 	/*
330df8bae1dSRodney W. Grimes 	 * Copy in known text to detect modification after freeing
331df8bae1dSRodney W. Grimes 	 * and to make it look free. Also, save the type being freed
332df8bae1dSRodney W. Grimes 	 * so we can list likely culprit if modification is detected
333df8bae1dSRodney W. Grimes 	 * when the object is reallocated.
334df8bae1dSRodney W. Grimes 	 */
335df8bae1dSRodney W. Grimes 	copysize = size < MAX_COPY ? size : MAX_COPY;
336df8bae1dSRodney W. Grimes 	end = (long *)&((caddr_t)addr)[copysize];
337df8bae1dSRodney W. Grimes 	for (lp = (long *)addr; lp < end; lp++)
338df8bae1dSRodney W. Grimes 		*lp = WEIRD_ADDR;
339df8bae1dSRodney W. Grimes 	freep->type = type;
340df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */
341df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
342df8bae1dSRodney W. Grimes 	kup->ku_freecnt++;
343df8bae1dSRodney W. Grimes 	if (kup->ku_freecnt >= kbp->kb_elmpercl)
344df8bae1dSRodney W. Grimes 		if (kup->ku_freecnt > kbp->kb_elmpercl)
345df8bae1dSRodney W. Grimes 			panic("free: multiple frees");
346df8bae1dSRodney W. Grimes 		else if (kbp->kb_totalfree > kbp->kb_highwat)
347df8bae1dSRodney W. Grimes 			kbp->kb_couldfree++;
348df8bae1dSRodney W. Grimes 	kbp->kb_totalfree++;
349df8bae1dSRodney W. Grimes 	ksp->ks_memuse -= size;
350df8bae1dSRodney W. Grimes 	if (ksp->ks_memuse + size >= ksp->ks_limit &&
351df8bae1dSRodney W. Grimes 	    ksp->ks_memuse < ksp->ks_limit)
352df8bae1dSRodney W. Grimes 		wakeup((caddr_t)ksp);
353df8bae1dSRodney W. Grimes 	ksp->ks_inuse--;
354df8bae1dSRodney W. Grimes #endif
35514bf02f8SJohn Dyson #ifdef OLD_MALLOC_MEMORY_POLICY
356df8bae1dSRodney W. Grimes 	if (kbp->kb_next == NULL)
357df8bae1dSRodney W. Grimes 		kbp->kb_next = addr;
358df8bae1dSRodney W. Grimes 	else
359df8bae1dSRodney W. Grimes 		((struct freelist *)kbp->kb_last)->next = addr;
360df8bae1dSRodney W. Grimes 	freep->next = NULL;
361df8bae1dSRodney W. Grimes 	kbp->kb_last = addr;
36214bf02f8SJohn Dyson #else
36314bf02f8SJohn Dyson 	/*
36414bf02f8SJohn Dyson 	 * Return memory to the head of the queue for quick reuse.  This
36514bf02f8SJohn Dyson 	 * can improve performance by improving the probability of the
36614bf02f8SJohn Dyson 	 * item being in the cache when it is reused.
36714bf02f8SJohn Dyson 	 */
36814bf02f8SJohn Dyson 	if (kbp->kb_next == NULL) {
36914bf02f8SJohn Dyson 		kbp->kb_next = addr;
37014bf02f8SJohn Dyson 		kbp->kb_last = addr;
37114bf02f8SJohn Dyson 		freep->next = NULL;
37214bf02f8SJohn Dyson 	} else {
37314bf02f8SJohn Dyson 		freep->next = kbp->kb_next;
37414bf02f8SJohn Dyson 		kbp->kb_next = addr;
37514bf02f8SJohn Dyson 	}
37614bf02f8SJohn Dyson #endif
377df8bae1dSRodney W. Grimes 	splx(s);
378df8bae1dSRodney W. Grimes }
379df8bae1dSRodney W. Grimes 
380df8bae1dSRodney W. Grimes /*
381df8bae1dSRodney W. Grimes  * Initialize the kernel memory allocator
382df8bae1dSRodney W. Grimes  */
3832b14f991SJulian Elischer /* ARGSUSED*/
3842b14f991SJulian Elischer static void
385d841aaa7SBruce Evans kmeminit(dummy)
386d841aaa7SBruce Evans 	void *dummy;
387df8bae1dSRodney W. Grimes {
388df8bae1dSRodney W. Grimes 	register long indx;
389df8bae1dSRodney W. Grimes 	int npg;
390df8bae1dSRodney W. Grimes 
391df8bae1dSRodney W. Grimes #if	((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
392cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE not power of 2"
393df8bae1dSRodney W. Grimes #endif
394df8bae1dSRodney W. Grimes #if	(MAXALLOCSAVE > MINALLOCSIZE * 32768)
395cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too big"
396df8bae1dSRodney W. Grimes #endif
397f8845af0SPoul-Henning Kamp #if	(MAXALLOCSAVE < PAGE_SIZE)
398cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too small"
399df8bae1dSRodney W. Grimes #endif
400cb7545a9SGarrett Wollman 	npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + VM_KMEM_SIZE)
401cb7545a9SGarrett Wollman 		/ PAGE_SIZE;
4020d94caffSDavid Greenman 
403df8bae1dSRodney W. Grimes 	kmemusage = (struct kmemusage *) kmem_alloc(kernel_map,
404df8bae1dSRodney W. Grimes 		(vm_size_t)(npg * sizeof(struct kmemusage)));
405df8bae1dSRodney W. Grimes 	kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase,
40654e7152cSDavid Greenman 		(vm_offset_t *)&kmemlimit, (vm_size_t)(npg * PAGE_SIZE),
40754e7152cSDavid Greenman 		FALSE);
4083075778bSJohn Dyson 	kmem_map->system_map = 1;
409df8bae1dSRodney W. Grimes #ifdef KMEMSTATS
410df8bae1dSRodney W. Grimes 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
411f8845af0SPoul-Henning Kamp 		if (1 << indx >= PAGE_SIZE)
412df8bae1dSRodney W. Grimes 			bucket[indx].kb_elmpercl = 1;
413df8bae1dSRodney W. Grimes 		else
414f8845af0SPoul-Henning Kamp 			bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx);
415df8bae1dSRodney W. Grimes 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
416df8bae1dSRodney W. Grimes 	}
41707bbd7f1SDavid Greenman 	/*
41807bbd7f1SDavid Greenman 	 * Limit maximum memory for each type to 60% of malloc area size or
41907bbd7f1SDavid Greenman 	 * 60% of physical memory, whichever is smaller.
42007bbd7f1SDavid Greenman 	 */
42154e7152cSDavid Greenman 	for (indx = 0; indx < M_LAST; indx++) {
42207bbd7f1SDavid Greenman 		kmemstats[indx].ks_limit = min(cnt.v_page_count * PAGE_SIZE,
423cb7545a9SGarrett Wollman 			(npg * PAGE_SIZE - nmbclusters * MCLBYTES
424cb7545a9SGarrett Wollman 			 - nmbufs * MSIZE)) * 6 / 10;
42554e7152cSDavid Greenman 	}
426df8bae1dSRodney W. Grimes #endif
427df8bae1dSRodney W. Grimes }
428