xref: /openbsd-src/regress/usr.bin/diff/t8.1 (revision 7dad4e2a75c50be482f71dba10f1f48dc664c0fe)
1bad3ecd0Sotto/*	$NetBSD: kern_malloc.c,v 1.11 1995/05/01 22:39:11 cgd Exp $	*/
2bad3ecd0Sotto
3bad3ecd0Sotto/*
4bad3ecd0Sotto * Copyright (c) 1987, 1991, 1993
5bad3ecd0Sotto *	The Regents of the University of California.  All rights reserved.
6bad3ecd0Sotto *
7bad3ecd0Sotto * Redistribution and use in source and binary forms, with or without
8bad3ecd0Sotto * modification, are permitted provided that the following conditions
9bad3ecd0Sotto * are met:
10bad3ecd0Sotto * 1. Redistributions of source code must retain the above copyright
11bad3ecd0Sotto *    notice, this list of conditions and the following disclaimer.
12bad3ecd0Sotto * 2. Redistributions in binary form must reproduce the above copyright
13bad3ecd0Sotto *    notice, this list of conditions and the following disclaimer in the
14bad3ecd0Sotto *    documentation and/or other materials provided with the distribution.
15*7dad4e2aSderaadt * 3. Neither the name of the University nor the names of its contributors
16bad3ecd0Sotto *    may be used to endorse or promote products derived from this software
17bad3ecd0Sotto *    without specific prior written permission.
18bad3ecd0Sotto *
19bad3ecd0Sotto * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20bad3ecd0Sotto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21bad3ecd0Sotto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22bad3ecd0Sotto * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23bad3ecd0Sotto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24bad3ecd0Sotto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25bad3ecd0Sotto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26bad3ecd0Sotto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27bad3ecd0Sotto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28bad3ecd0Sotto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29bad3ecd0Sotto * SUCH DAMAGE.
30bad3ecd0Sotto *
31bad3ecd0Sotto *	@(#)kern_malloc.c	8.3 (Berkeley) 1/4/94
32bad3ecd0Sotto */
33bad3ecd0Sotto
34bad3ecd0Sotto#include <sys/param.h>
35bad3ecd0Sotto#include <sys/proc.h>
36bad3ecd0Sotto#include <sys/map.h>
37bad3ecd0Sotto#include <sys/kernel.h>
38bad3ecd0Sotto#include <sys/malloc.h>
39bad3ecd0Sotto
40bad3ecd0Sotto#include <vm/vm.h>
41bad3ecd0Sotto#include <vm/vm_kern.h>
42bad3ecd0Sotto
43bad3ecd0Sottostruct kmembuckets bucket[MINBUCKET + 16];
44bad3ecd0Sottostruct kmemstats kmemstats[M_LAST];
45bad3ecd0Sottostruct kmemusage *kmemusage;
46bad3ecd0Sottochar *kmembase, *kmemlimit;
47bad3ecd0Sottochar *memname[] = INITKMEMNAMES;
48bad3ecd0Sotto
49bad3ecd0Sotto#ifdef DIAGNOSTIC
50bad3ecd0Sotto/*
51bad3ecd0Sotto * This structure provides a set of masks to catch unaligned frees.
52bad3ecd0Sotto */
53bad3ecd0Sottolong addrmask[] = { 0,
54bad3ecd0Sotto	0x00000001, 0x00000003, 0x00000007, 0x0000000f,
55bad3ecd0Sotto	0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
56bad3ecd0Sotto	0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
57bad3ecd0Sotto	0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
58bad3ecd0Sotto};
59bad3ecd0Sotto
60bad3ecd0Sotto/*
61bad3ecd0Sotto * The WEIRD_ADDR is used as known text to copy into free objects so
62bad3ecd0Sotto * that modifications after frees can be detected.
63bad3ecd0Sotto */
64bad3ecd0Sotto#define WEIRD_ADDR	0xdeadbeef
65bad3ecd0Sotto#define MAX_COPY	32
66bad3ecd0Sotto
67bad3ecd0Sotto/*
68bad3ecd0Sotto * Normally the freelist structure is used only to hold the list pointer
69bad3ecd0Sotto * for free objects.  However, when running with diagnostics, the first
70bad3ecd0Sotto * 8 bytes of the structure is unused except for diagnostic information,
71bad3ecd0Sotto * and the free list pointer is at offst 8 in the structure.  Since the
72bad3ecd0Sotto * first 8 bytes is the portion of the structure most often modified, this
73bad3ecd0Sotto * helps to detect memory reuse problems and avoid free list corruption.
74bad3ecd0Sotto */
75bad3ecd0Sottostruct freelist {
76bad3ecd0Sotto	int32_t	spare0;
77bad3ecd0Sotto	int16_t	type;
78bad3ecd0Sotto	int16_t	spare1;
79bad3ecd0Sotto	caddr_t	next;
80bad3ecd0Sotto};
81bad3ecd0Sotto#else /* !DIAGNOSTIC */
82bad3ecd0Sottostruct freelist {
83bad3ecd0Sotto	caddr_t	next;
84bad3ecd0Sotto};
85bad3ecd0Sotto#endif /* DIAGNOSTIC */
86bad3ecd0Sotto
87bad3ecd0Sotto/*
88bad3ecd0Sotto * Allocate a block of memory
89bad3ecd0Sotto */
90bad3ecd0Sottovoid *
91bad3ecd0Sottomalloc(size, type, flags)
92bad3ecd0Sotto	unsigned long size;
93bad3ecd0Sotto	int type, flags;
94bad3ecd0Sotto{
95bad3ecd0Sotto	register struct kmembuckets *kbp;
96bad3ecd0Sotto	register struct kmemusage *kup;
97bad3ecd0Sotto	register struct freelist *freep;
98bad3ecd0Sotto	long indx, npg, allocsize;
99bad3ecd0Sotto	int s;
100bad3ecd0Sotto	caddr_t va, cp, savedlist;
101bad3ecd0Sotto#ifdef DIAGNOSTIC
102bad3ecd0Sotto	int32_t *end, *lp;
103bad3ecd0Sotto	int copysize;
104bad3ecd0Sotto	char *savedtype;
105bad3ecd0Sotto#endif
106bad3ecd0Sotto#ifdef KMEMSTATS
107bad3ecd0Sotto	register struct kmemstats *ksp = &kmemstats[type];
108bad3ecd0Sotto
109bad3ecd0Sotto	if (((unsigned long)type) > M_LAST)
110bad3ecd0Sotto		panic("malloc - bogus type");
111bad3ecd0Sotto#endif
112bad3ecd0Sotto	indx = BUCKETINDX(size);
113bad3ecd0Sotto	kbp = &bucket[indx];
114bad3ecd0Sotto	s = splimp();
115bad3ecd0Sotto#ifdef KMEMSTATS
116bad3ecd0Sotto	while (ksp->ks_memuse >= ksp->ks_limit) {
117bad3ecd0Sotto		if (flags & M_NOWAIT) {
118bad3ecd0Sotto			splx(s);
119bad3ecd0Sotto			return ((void *) NULL);
120bad3ecd0Sotto		}
121bad3ecd0Sotto		if (ksp->ks_limblocks < 65535)
122bad3ecd0Sotto			ksp->ks_limblocks++;
123bad3ecd0Sotto		tsleep((caddr_t)ksp, PSWP+2, memname[type], 0);
124bad3ecd0Sotto	}
125bad3ecd0Sotto	ksp->ks_size |= 1 << indx;
126bad3ecd0Sotto#endif
127bad3ecd0Sotto#ifdef DIAGNOSTIC
128bad3ecd0Sotto	copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY;
129bad3ecd0Sotto#endif
130bad3ecd0Sotto	if (kbp->kb_next == NULL) {
131bad3ecd0Sotto		kbp->kb_last = NULL;
132bad3ecd0Sotto		if (size > MAXALLOCSAVE)
133bad3ecd0Sotto			allocsize = roundup(size, CLBYTES);
134bad3ecd0Sotto		else
135bad3ecd0Sotto			allocsize = 1 << indx;
136bad3ecd0Sotto		npg = clrnd(btoc(allocsize));
137bad3ecd0Sotto		va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg),
138bad3ecd0Sotto					   !(flags & M_NOWAIT));
139bad3ecd0Sotto		if (va == NULL) {
140bad3ecd0Sotto			splx(s);
141bad3ecd0Sotto			return ((void *) NULL);
142bad3ecd0Sotto		}
143bad3ecd0Sotto#ifdef KMEMSTATS
144bad3ecd0Sotto		kbp->kb_total += kbp->kb_elmpercl;
145bad3ecd0Sotto#endif
146bad3ecd0Sotto		kup = btokup(va);
147bad3ecd0Sotto		kup->ku_indx = indx;
148bad3ecd0Sotto		if (allocsize > MAXALLOCSAVE) {
149bad3ecd0Sotto			if (npg > 65535)
150bad3ecd0Sotto				panic("malloc: allocation too large");
151bad3ecd0Sotto			kup->ku_pagecnt = npg;
152bad3ecd0Sotto#ifdef KMEMSTATS
153bad3ecd0Sotto			ksp->ks_memuse += allocsize;
154bad3ecd0Sotto#endif
155bad3ecd0Sotto			goto out;
156bad3ecd0Sotto		}
157bad3ecd0Sotto#ifdef KMEMSTATS
158bad3ecd0Sotto		kup->ku_freecnt = kbp->kb_elmpercl;
159bad3ecd0Sotto		kbp->kb_totalfree += kbp->kb_elmpercl;
160bad3ecd0Sotto#endif
161bad3ecd0Sotto		/*
162bad3ecd0Sotto		 * Just in case we blocked while allocating memory,
163bad3ecd0Sotto		 * and someone else also allocated memory for this
164bad3ecd0Sotto		 * bucket, don't assume the list is still empty.
165bad3ecd0Sotto		 */
166bad3ecd0Sotto		savedlist = kbp->kb_next;
167bad3ecd0Sotto		kbp->kb_next = cp = va + (npg * NBPG) - allocsize;
168bad3ecd0Sotto		for (;;) {
169bad3ecd0Sotto			freep = (struct freelist *)cp;
170bad3ecd0Sotto#ifdef DIAGNOSTIC
171bad3ecd0Sotto			/*
172bad3ecd0Sotto			 * Copy in known text to detect modification
173bad3ecd0Sotto			 * after freeing.
174bad3ecd0Sotto			 */
175bad3ecd0Sotto			end = (int32_t *)&cp[copysize];
176bad3ecd0Sotto			for (lp = (int32_t *)cp; lp < end; lp++)
177bad3ecd0Sotto				*lp = WEIRD_ADDR;
178bad3ecd0Sotto			freep->type = M_FREE;
179bad3ecd0Sotto#endif /* DIAGNOSTIC */
180bad3ecd0Sotto			if (cp <= va)
181bad3ecd0Sotto				break;
182bad3ecd0Sotto			cp -= allocsize;
183bad3ecd0Sotto			freep->next = cp;
184bad3ecd0Sotto		}
185bad3ecd0Sotto		freep->next = savedlist;
186bad3ecd0Sotto		if (kbp->kb_last == NULL)
187bad3ecd0Sotto			kbp->kb_last = (caddr_t)freep;
188bad3ecd0Sotto	}
189bad3ecd0Sotto	va = kbp->kb_next;
190bad3ecd0Sotto	kbp->kb_next = ((struct freelist *)va)->next;
191bad3ecd0Sotto#ifdef DIAGNOSTIC
192bad3ecd0Sotto	freep = (struct freelist *)va;
193bad3ecd0Sotto	savedtype = (unsigned)freep->type < M_LAST ?
194bad3ecd0Sotto		memname[freep->type] : "???";
195bad3ecd0Sotto	if (kbp->kb_next &&
196bad3ecd0Sotto	    !kernacc(kbp->kb_next, sizeof(struct freelist), 0)) {
197bad3ecd0Sotto		printf("%s %d of object %p size %d %s %s (invalid addr %p)\n",
198bad3ecd0Sotto			"Data modified on freelist: word",
199bad3ecd0Sotto			(int32_t *)&kbp->kb_next - (int32_t *)kbp, va, size,
200bad3ecd0Sotto			"previous type", savedtype, kbp->kb_next);
201bad3ecd0Sotto		kbp->kb_next = NULL;
202bad3ecd0Sotto	}
203bad3ecd0Sotto
204bad3ecd0Sotto	/* Fill the fields that we've used with WEIRD_ADDR */
205bad3ecd0Sotto#if BYTE_ORDER == BIG_ENDIAN
206bad3ecd0Sotto	freep->type = WEIRD_ADDR >> 16;
207bad3ecd0Sotto#endif
208bad3ecd0Sotto#if BYTE_ORDER == LITTLE_ENDIAN
209bad3ecd0Sotto	freep->type = (short)WEIRD_ADDR;
210bad3ecd0Sotto#endif
211bad3ecd0Sotto	end = (int32_t *)&freep->next +
212bad3ecd0Sotto	    (sizeof(freep->next) / sizeof(int32_t));
213bad3ecd0Sotto	for (lp = (int32_t *)&freep->next; lp < end; lp++)
214bad3ecd0Sotto		*lp = WEIRD_ADDR;
215bad3ecd0Sotto
216bad3ecd0Sotto	/* and check that the data hasn't been modified. */
217bad3ecd0Sotto	end = (int32_t *)&va[copysize];
218bad3ecd0Sotto	for (lp = (int32_t *)va; lp < end; lp++) {
219bad3ecd0Sotto		if (*lp == WEIRD_ADDR)
220bad3ecd0Sotto			continue;
221bad3ecd0Sotto		printf("%s %d of object %p size %d %s %s (%p != %p)\n",
222bad3ecd0Sotto			"Data modified on freelist: word", lp - (int32_t *)va,
223bad3ecd0Sotto			va, size, "previous type", savedtype, *lp, WEIRD_ADDR);
224bad3ecd0Sotto		break;
225bad3ecd0Sotto	}
226bad3ecd0Sotto
227bad3ecd0Sotto	freep->spare0 = 0;
228bad3ecd0Sotto#endif /* DIAGNOSTIC */
229bad3ecd0Sotto#ifdef KMEMSTATS
230bad3ecd0Sotto	kup = btokup(va);
231bad3ecd0Sotto	if (kup->ku_indx != indx)
232bad3ecd0Sotto		panic("malloc: wrong bucket");
233bad3ecd0Sotto	if (kup->ku_freecnt == 0)
234bad3ecd0Sotto		panic("malloc: lost data");
235bad3ecd0Sotto	kup->ku_freecnt--;
236bad3ecd0Sotto	kbp->kb_totalfree--;
237bad3ecd0Sotto	ksp->ks_memuse += 1 << indx;
238bad3ecd0Sottoout:
239bad3ecd0Sotto	kbp->kb_calls++;
240bad3ecd0Sotto	ksp->ks_inuse++;
241bad3ecd0Sotto	ksp->ks_calls++;
242bad3ecd0Sotto	if (ksp->ks_memuse > ksp->ks_maxused)
243bad3ecd0Sotto		ksp->ks_maxused = ksp->ks_memuse;
244bad3ecd0Sotto#else
245bad3ecd0Sottoout:
246bad3ecd0Sotto#endif
247bad3ecd0Sotto	splx(s);
248bad3ecd0Sotto	return ((void *) va);
249bad3ecd0Sotto}
250bad3ecd0Sotto
251bad3ecd0Sotto/*
252bad3ecd0Sotto * Free a block of memory allocated by malloc.
253bad3ecd0Sotto */
254bad3ecd0Sottovoid
255bad3ecd0Sottofree(addr, type)
256bad3ecd0Sotto	void *addr;
257bad3ecd0Sotto	int type;
258bad3ecd0Sotto{
259bad3ecd0Sotto	register struct kmembuckets *kbp;
260bad3ecd0Sotto	register struct kmemusage *kup;
261bad3ecd0Sotto	register struct freelist *freep;
262bad3ecd0Sotto	long size;
263bad3ecd0Sotto	int s;
264bad3ecd0Sotto#ifdef DIAGNOSTIC
265bad3ecd0Sotto	caddr_t cp;
266bad3ecd0Sotto	int32_t *end, *lp;
267bad3ecd0Sotto	long alloc, copysize;
268bad3ecd0Sotto#endif
269bad3ecd0Sotto#ifdef KMEMSTATS
270bad3ecd0Sotto	register struct kmemstats *ksp = &kmemstats[type];
271bad3ecd0Sotto#endif
272bad3ecd0Sotto
273bad3ecd0Sotto	kup = btokup(addr);
274bad3ecd0Sotto	size = 1 << kup->ku_indx;
275bad3ecd0Sotto	kbp = &bucket[kup->ku_indx];
276bad3ecd0Sotto	s = splimp();
277bad3ecd0Sotto#ifdef DIAGNOSTIC
278bad3ecd0Sotto	/*
279bad3ecd0Sotto	 * Check for returns of data that do not point to the
280bad3ecd0Sotto	 * beginning of the allocation.
281bad3ecd0Sotto	 */
282bad3ecd0Sotto	if (size > NBPG * CLSIZE)
283bad3ecd0Sotto		alloc = addrmask[BUCKETINDX(NBPG * CLSIZE)];
284bad3ecd0Sotto	else
285bad3ecd0Sotto		alloc = addrmask[kup->ku_indx];
286bad3ecd0Sotto	if (((u_long)addr & alloc) != 0)
287bad3ecd0Sotto		panic("free: unaligned addr 0x%x, size %d, type %s, mask %d\n",
288bad3ecd0Sotto			addr, size, memname[type], alloc);
289bad3ecd0Sotto#endif /* DIAGNOSTIC */
290bad3ecd0Sotto	if (size > MAXALLOCSAVE) {
291bad3ecd0Sotto		kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt));
292bad3ecd0Sotto#ifdef KMEMSTATS
293bad3ecd0Sotto		size = kup->ku_pagecnt << PGSHIFT;
294bad3ecd0Sotto		ksp->ks_memuse -= size;
295bad3ecd0Sotto		kup->ku_indx = 0;
296bad3ecd0Sotto		kup->ku_pagecnt = 0;
297bad3ecd0Sotto		if (ksp->ks_memuse + size >= ksp->ks_limit &&
298bad3ecd0Sotto		    ksp->ks_memuse < ksp->ks_limit)
299bad3ecd0Sotto			wakeup((caddr_t)ksp);
300bad3ecd0Sotto		ksp->ks_inuse--;
301bad3ecd0Sotto		kbp->kb_total -= 1;
302bad3ecd0Sotto#endif
303bad3ecd0Sotto		splx(s);
304bad3ecd0Sotto		return;
305bad3ecd0Sotto	}
306bad3ecd0Sotto	freep = (struct freelist *)addr;
307bad3ecd0Sotto#ifdef DIAGNOSTIC
308bad3ecd0Sotto	/*
309bad3ecd0Sotto	 * Check for multiple frees. Use a quick check to see if
310bad3ecd0Sotto	 * it looks free before laboriously searching the freelist.
311bad3ecd0Sotto	 */
312bad3ecd0Sotto	if (freep->spare0 == WEIRD_ADDR) {
313bad3ecd0Sotto		for (cp = kbp->kb_next; cp; cp = *(caddr_t *)cp) {
314bad3ecd0Sotto			if (addr != cp)
315bad3ecd0Sotto				continue;
316bad3ecd0Sotto			printf("multiply freed item %p\n", addr);
317bad3ecd0Sotto			panic("free: duplicated free");
318bad3ecd0Sotto		}
319bad3ecd0Sotto	}
320bad3ecd0Sotto	/*
321bad3ecd0Sotto	 * Copy in known text to detect modification after freeing
322bad3ecd0Sotto	 * and to make it look free. Also, save the type being freed
323bad3ecd0Sotto	 * so we can list likely culprit if modification is detected
324bad3ecd0Sotto	 * when the object is reallocated.
325bad3ecd0Sotto	 */
326bad3ecd0Sotto	copysize = size < MAX_COPY ? size : MAX_COPY;
327bad3ecd0Sotto	end = (int32_t *)&((caddr_t)addr)[copysize];
328bad3ecd0Sotto	for (lp = (int32_t *)addr; lp < end; lp++)
329bad3ecd0Sotto		*lp = WEIRD_ADDR;
330bad3ecd0Sotto	freep->type = type;
331bad3ecd0Sotto#endif /* DIAGNOSTIC */
332bad3ecd0Sotto#ifdef KMEMSTATS
333bad3ecd0Sotto	kup->ku_freecnt++;
334bad3ecd0Sotto	if (kup->ku_freecnt >= kbp->kb_elmpercl)
335bad3ecd0Sotto		if (kup->ku_freecnt > kbp->kb_elmpercl)
336bad3ecd0Sotto			panic("free: multiple frees");
337bad3ecd0Sotto		else if (kbp->kb_totalfree > kbp->kb_highwat)
338bad3ecd0Sotto			kbp->kb_couldfree++;
339bad3ecd0Sotto	kbp->kb_totalfree++;
340bad3ecd0Sotto	ksp->ks_memuse -= size;
341bad3ecd0Sotto	if (ksp->ks_memuse + size >= ksp->ks_limit &&
342bad3ecd0Sotto	    ksp->ks_memuse < ksp->ks_limit)
343bad3ecd0Sotto		wakeup((caddr_t)ksp);
344bad3ecd0Sotto	ksp->ks_inuse--;
345bad3ecd0Sotto#endif
346bad3ecd0Sotto	if (kbp->kb_next == NULL)
347bad3ecd0Sotto		kbp->kb_next = addr;
348bad3ecd0Sotto	else
349bad3ecd0Sotto		((struct freelist *)kbp->kb_last)->next = addr;
350bad3ecd0Sotto	freep->next = NULL;
351bad3ecd0Sotto	kbp->kb_last = addr;
352bad3ecd0Sotto	splx(s);
353bad3ecd0Sotto}
354bad3ecd0Sotto
355bad3ecd0Sotto/*
356bad3ecd0Sotto * Initialize the kernel memory allocator
357bad3ecd0Sotto */
358bad3ecd0Sottokmeminit()
359bad3ecd0Sotto{
360bad3ecd0Sotto	register long indx;
361bad3ecd0Sotto	int npg;
362bad3ecd0Sotto
363bad3ecd0Sotto#if	((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
364bad3ecd0Sotto		ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2
365bad3ecd0Sotto#endif
366bad3ecd0Sotto#if	(MAXALLOCSAVE > MINALLOCSIZE * 32768)
367bad3ecd0Sotto		ERROR!_kmeminit:_MAXALLOCSAVE_too_big
368bad3ecd0Sotto#endif
369bad3ecd0Sotto#if	(MAXALLOCSAVE < CLBYTES)
370bad3ecd0Sotto		ERROR!_kmeminit:_MAXALLOCSAVE_too_small
371bad3ecd0Sotto#endif
372bad3ecd0Sotto
373bad3ecd0Sotto	if (sizeof(struct freelist) > (1 << MINBUCKET))
374bad3ecd0Sotto		panic("minbucket too small/struct freelist too big");
375bad3ecd0Sotto
376bad3ecd0Sotto	npg = VM_KMEM_SIZE/ NBPG;
377bad3ecd0Sotto	kmemusage = (struct kmemusage *) kmem_alloc(kernel_map,
378bad3ecd0Sotto		(vm_size_t)(npg * sizeof(struct kmemusage)));
379bad3ecd0Sotto	kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase,
380bad3ecd0Sotto		(vm_offset_t *)&kmemlimit, (vm_size_t)(npg * NBPG), FALSE);
381bad3ecd0Sotto#ifdef KMEMSTATS
382bad3ecd0Sotto	for (indx = 0; indx < MINBUCKET + 16; indx++) {
383bad3ecd0Sotto		if (1 << indx >= CLBYTES)
384bad3ecd0Sotto			bucket[indx].kb_elmpercl = 1;
385bad3ecd0Sotto		else
386bad3ecd0Sotto			bucket[indx].kb_elmpercl = CLBYTES / (1 << indx);
387bad3ecd0Sotto		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
388bad3ecd0Sotto	}
389bad3ecd0Sotto	for (indx = 0; indx < M_LAST; indx++)
390bad3ecd0Sotto		kmemstats[indx].ks_limit = npg * NBPG * 6 / 10;
391bad3ecd0Sotto#endif
392bad3ecd0Sotto}
393