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 34254c6cb3SPoul-Henning Kamp * $Id: kern_malloc.c,v 1.30 1997/09/16 13:51:58 bde 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/kernel.h> 40254c6cb3SPoul-Henning Kamp #define MALLOC_INSTANTIATE 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 *)); 54254c6cb3SPoul-Henning Kamp static void malloc_init __P((struct kmemstats *)); 552b14f991SJulian Elischer SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL) 562b14f991SJulian Elischer 57254c6cb3SPoul-Henning Kamp struct kmemstats *kmemstatistics = M_FREE; 58254c6cb3SPoul-Henning Kamp static struct kmembuckets bucket[MINBUCKET + 16]; 59254c6cb3SPoul-Henning Kamp static struct kmemusage *kmemusage; 60254c6cb3SPoul-Henning Kamp static char *kmembase; 61043a2f3bSBruce Evans static char *kmemlimit; 62df8bae1dSRodney W. Grimes 63df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 64df8bae1dSRodney W. Grimes /* 65df8bae1dSRodney W. Grimes * This structure provides a set of masks to catch unaligned frees. 66df8bae1dSRodney W. Grimes */ 6787b6de2bSPoul-Henning Kamp static long addrmask[] = { 0, 68df8bae1dSRodney W. Grimes 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 69df8bae1dSRodney W. Grimes 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 70df8bae1dSRodney W. Grimes 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 71df8bae1dSRodney W. Grimes 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 72df8bae1dSRodney W. Grimes }; 73df8bae1dSRodney W. Grimes 74df8bae1dSRodney W. Grimes /* 75df8bae1dSRodney W. Grimes * The WEIRD_ADDR is used as known text to copy into free objects so 76df8bae1dSRodney W. Grimes * that modifications after frees can be detected. 77df8bae1dSRodney W. Grimes */ 785124d598SDavid Greenman #define WEIRD_ADDR 0xdeadc0de 795124d598SDavid Greenman #define MAX_COPY 64 80df8bae1dSRodney W. Grimes 81df8bae1dSRodney W. Grimes /* 82df8bae1dSRodney W. Grimes * Normally the first word of the structure is used to hold the list 83df8bae1dSRodney W. Grimes * pointer for free objects. However, when running with diagnostics, 84df8bae1dSRodney W. Grimes * we use the third and fourth fields, so as to catch modifications 85df8bae1dSRodney W. Grimes * in the most commonly trashed first two words. 86df8bae1dSRodney W. Grimes */ 87df8bae1dSRodney W. Grimes struct freelist { 88df8bae1dSRodney W. Grimes long spare0; 89254c6cb3SPoul-Henning Kamp struct kmemstats *type; 90df8bae1dSRodney W. Grimes long spare1; 91df8bae1dSRodney W. Grimes caddr_t next; 92df8bae1dSRodney W. Grimes }; 93df8bae1dSRodney W. Grimes #else /* !DIAGNOSTIC */ 94df8bae1dSRodney W. Grimes struct freelist { 95df8bae1dSRodney W. Grimes caddr_t next; 96df8bae1dSRodney W. Grimes }; 97df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 98df8bae1dSRodney W. Grimes 99df8bae1dSRodney W. Grimes /* 100df8bae1dSRodney W. Grimes * Allocate a block of memory 101df8bae1dSRodney W. Grimes */ 102df8bae1dSRodney W. Grimes void * 103df8bae1dSRodney W. Grimes malloc(size, type, flags) 104df8bae1dSRodney W. Grimes unsigned long size; 105254c6cb3SPoul-Henning Kamp struct kmemstats *type; 106254c6cb3SPoul-Henning Kamp int flags; 107df8bae1dSRodney W. Grimes { 108df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 109df8bae1dSRodney W. Grimes register struct kmemusage *kup; 110df8bae1dSRodney W. Grimes register struct freelist *freep; 111df8bae1dSRodney W. Grimes long indx, npg, allocsize; 112df8bae1dSRodney W. Grimes int s; 113df8bae1dSRodney W. Grimes caddr_t va, cp, savedlist; 114df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 115df8bae1dSRodney W. Grimes long *end, *lp; 116df8bae1dSRodney W. Grimes int copysize; 117df8bae1dSRodney W. Grimes char *savedtype; 118df8bae1dSRodney W. Grimes #endif 119254c6cb3SPoul-Henning Kamp register struct kmemstats *ksp = type; 120df8bae1dSRodney W. Grimes 121254c6cb3SPoul-Henning Kamp if (!type->ks_next) 122254c6cb3SPoul-Henning Kamp malloc_init(type); 123254c6cb3SPoul-Henning Kamp 124df8bae1dSRodney W. Grimes indx = BUCKETINDX(size); 125df8bae1dSRodney W. Grimes kbp = &bucket[indx]; 126763424fcSDavid Greenman s = splhigh(); 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++; 134254c6cb3SPoul-Henning Kamp tsleep((caddr_t)ksp, PSWP+2, type->ks_shortdesc, 0); 135df8bae1dSRodney W. Grimes } 136df8bae1dSRodney W. Grimes ksp->ks_size |= 1 << indx; 137df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 138df8bae1dSRodney W. Grimes copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY; 139df8bae1dSRodney W. Grimes #endif 140df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) { 141df8bae1dSRodney W. Grimes kbp->kb_last = NULL; 142df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) 143f8845af0SPoul-Henning Kamp allocsize = roundup(size, PAGE_SIZE); 144df8bae1dSRodney W. Grimes else 145df8bae1dSRodney W. Grimes allocsize = 1 << indx; 146e911eafcSPoul-Henning Kamp npg = btoc(allocsize); 1479f518539SDavid Greenman va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags); 148df8bae1dSRodney W. Grimes if (va == NULL) { 149df8bae1dSRodney W. Grimes splx(s); 150df8bae1dSRodney W. Grimes return ((void *) NULL); 151df8bae1dSRodney W. Grimes } 152df8bae1dSRodney W. Grimes kbp->kb_total += kbp->kb_elmpercl; 153df8bae1dSRodney W. Grimes kup = btokup(va); 154df8bae1dSRodney W. Grimes kup->ku_indx = indx; 155df8bae1dSRodney W. Grimes if (allocsize > MAXALLOCSAVE) { 156df8bae1dSRodney W. Grimes if (npg > 65535) 157df8bae1dSRodney W. Grimes panic("malloc: allocation too large"); 158df8bae1dSRodney W. Grimes kup->ku_pagecnt = npg; 159df8bae1dSRodney W. Grimes ksp->ks_memuse += allocsize; 160df8bae1dSRodney W. Grimes goto out; 161df8bae1dSRodney W. Grimes } 162df8bae1dSRodney W. Grimes kup->ku_freecnt = kbp->kb_elmpercl; 163df8bae1dSRodney W. Grimes kbp->kb_totalfree += kbp->kb_elmpercl; 164df8bae1dSRodney W. Grimes /* 165df8bae1dSRodney W. Grimes * Just in case we blocked while allocating memory, 166df8bae1dSRodney W. Grimes * and someone else also allocated memory for this 167df8bae1dSRodney W. Grimes * bucket, don't assume the list is still empty. 168df8bae1dSRodney W. Grimes */ 169df8bae1dSRodney W. Grimes savedlist = kbp->kb_next; 170e911eafcSPoul-Henning Kamp kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize; 171df8bae1dSRodney W. Grimes for (;;) { 172df8bae1dSRodney W. Grimes freep = (struct freelist *)cp; 173df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 174df8bae1dSRodney W. Grimes /* 175df8bae1dSRodney W. Grimes * Copy in known text to detect modification 176df8bae1dSRodney W. Grimes * after freeing. 177df8bae1dSRodney W. Grimes */ 178df8bae1dSRodney W. Grimes end = (long *)&cp[copysize]; 179df8bae1dSRodney W. Grimes for (lp = (long *)cp; lp < end; lp++) 180df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 181df8bae1dSRodney W. Grimes freep->type = M_FREE; 182df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 183df8bae1dSRodney W. Grimes if (cp <= va) 184df8bae1dSRodney W. Grimes break; 185df8bae1dSRodney W. Grimes cp -= allocsize; 186df8bae1dSRodney W. Grimes freep->next = cp; 187df8bae1dSRodney W. Grimes } 188df8bae1dSRodney W. Grimes freep->next = savedlist; 189df8bae1dSRodney W. Grimes if (kbp->kb_last == NULL) 190df8bae1dSRodney W. Grimes kbp->kb_last = (caddr_t)freep; 191df8bae1dSRodney W. Grimes } 192df8bae1dSRodney W. Grimes va = kbp->kb_next; 193df8bae1dSRodney W. Grimes kbp->kb_next = ((struct freelist *)va)->next; 194df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 195df8bae1dSRodney W. Grimes freep = (struct freelist *)va; 196254c6cb3SPoul-Henning Kamp savedtype = type->ks_shortdesc; 197df8bae1dSRodney W. Grimes #if BYTE_ORDER == BIG_ENDIAN 198254c6cb3SPoul-Henning Kamp freep->type = (struct kmemstats *)WEIRD_ADDR >> 16; 199df8bae1dSRodney W. Grimes #endif 200df8bae1dSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN 201254c6cb3SPoul-Henning Kamp freep->type = (struct kmemstats *)WEIRD_ADDR; 202df8bae1dSRodney W. Grimes #endif 203df8bae1dSRodney W. Grimes if (((long)(&freep->next)) & 0x2) 204df8bae1dSRodney W. Grimes freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16)); 205df8bae1dSRodney W. Grimes else 206df8bae1dSRodney W. Grimes freep->next = (caddr_t)WEIRD_ADDR; 207df8bae1dSRodney W. Grimes end = (long *)&va[copysize]; 208df8bae1dSRodney W. Grimes for (lp = (long *)va; lp < end; lp++) { 209df8bae1dSRodney W. Grimes if (*lp == WEIRD_ADDR) 210df8bae1dSRodney W. Grimes continue; 211797f2d22SPoul-Henning Kamp printf("%s %d of object %p size %ld %s %s (0x%lx != 0x%x)\n", 212df8bae1dSRodney W. Grimes "Data modified on freelist: word", lp - (long *)va, 213df8bae1dSRodney W. Grimes va, size, "previous type", savedtype, *lp, WEIRD_ADDR); 214df8bae1dSRodney W. Grimes break; 215df8bae1dSRodney W. Grimes } 216df8bae1dSRodney W. Grimes freep->spare0 = 0; 217df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 218df8bae1dSRodney W. Grimes kup = btokup(va); 219df8bae1dSRodney W. Grimes if (kup->ku_indx != indx) 220df8bae1dSRodney W. Grimes panic("malloc: wrong bucket"); 221df8bae1dSRodney W. Grimes if (kup->ku_freecnt == 0) 222df8bae1dSRodney W. Grimes panic("malloc: lost data"); 223df8bae1dSRodney W. Grimes kup->ku_freecnt--; 224df8bae1dSRodney W. Grimes kbp->kb_totalfree--; 225df8bae1dSRodney W. Grimes ksp->ks_memuse += 1 << indx; 226df8bae1dSRodney W. Grimes out: 227df8bae1dSRodney W. Grimes kbp->kb_calls++; 228df8bae1dSRodney W. Grimes ksp->ks_inuse++; 229df8bae1dSRodney W. Grimes ksp->ks_calls++; 230df8bae1dSRodney W. Grimes if (ksp->ks_memuse > ksp->ks_maxused) 231df8bae1dSRodney W. Grimes ksp->ks_maxused = ksp->ks_memuse; 232df8bae1dSRodney W. Grimes splx(s); 233df8bae1dSRodney W. Grimes return ((void *) va); 234df8bae1dSRodney W. Grimes } 235df8bae1dSRodney W. Grimes 236df8bae1dSRodney W. Grimes /* 237df8bae1dSRodney W. Grimes * Free a block of memory allocated by malloc. 238df8bae1dSRodney W. Grimes */ 239df8bae1dSRodney W. Grimes void 240df8bae1dSRodney W. Grimes free(addr, type) 241df8bae1dSRodney W. Grimes void *addr; 242254c6cb3SPoul-Henning Kamp struct kmemstats *type; 243df8bae1dSRodney W. Grimes { 244df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 245df8bae1dSRodney W. Grimes register struct kmemusage *kup; 246df8bae1dSRodney W. Grimes register struct freelist *freep; 247df8bae1dSRodney W. Grimes long size; 248df8bae1dSRodney W. Grimes int s; 249df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 250ca67a4e4SPoul-Henning Kamp struct freelist *fp; 251df8bae1dSRodney W. Grimes long *end, *lp, alloc, copysize; 252df8bae1dSRodney W. Grimes #endif 253254c6cb3SPoul-Henning Kamp register struct kmemstats *ksp = type; 254254c6cb3SPoul-Henning Kamp 255254c6cb3SPoul-Henning Kamp if (!type->ks_next) 256254c6cb3SPoul-Henning Kamp malloc_init(type); 257df8bae1dSRodney W. Grimes 25817dda4c9SDavid Greenman #ifdef DIAGNOSTIC 25917dda4c9SDavid Greenman if ((char *)addr < kmembase || (char *)addr >= kmemlimit) { 260edf8a815SDavid Greenman panic("free: address 0x%x out of range", addr); 26117dda4c9SDavid Greenman } 26217dda4c9SDavid Greenman #endif 263df8bae1dSRodney W. Grimes kup = btokup(addr); 264df8bae1dSRodney W. Grimes size = 1 << kup->ku_indx; 265df8bae1dSRodney W. Grimes kbp = &bucket[kup->ku_indx]; 266763424fcSDavid Greenman s = splhigh(); 267df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 268df8bae1dSRodney W. Grimes /* 269df8bae1dSRodney W. Grimes * Check for returns of data that do not point to the 270df8bae1dSRodney W. Grimes * beginning of the allocation. 271df8bae1dSRodney W. Grimes */ 272f8845af0SPoul-Henning Kamp if (size > PAGE_SIZE) 273f8845af0SPoul-Henning Kamp alloc = addrmask[BUCKETINDX(PAGE_SIZE)]; 274df8bae1dSRodney W. Grimes else 275df8bae1dSRodney W. Grimes alloc = addrmask[kup->ku_indx]; 276df8bae1dSRodney W. Grimes if (((u_long)addr & alloc) != 0) 277edf8a815SDavid Greenman panic("free: unaligned addr 0x%x, size %d, type %s, mask %d", 278254c6cb3SPoul-Henning Kamp addr, size, type->ks_shortdesc, alloc); 279df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 280df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) { 281df8bae1dSRodney W. Grimes kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt)); 282e911eafcSPoul-Henning Kamp size = kup->ku_pagecnt << PAGE_SHIFT; 283df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 284df8bae1dSRodney W. Grimes kup->ku_indx = 0; 285df8bae1dSRodney W. Grimes kup->ku_pagecnt = 0; 286df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 287df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 288df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 289df8bae1dSRodney W. Grimes ksp->ks_inuse--; 290df8bae1dSRodney W. Grimes kbp->kb_total -= 1; 291df8bae1dSRodney W. Grimes splx(s); 292df8bae1dSRodney W. Grimes return; 293df8bae1dSRodney W. Grimes } 294df8bae1dSRodney W. Grimes freep = (struct freelist *)addr; 295df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 296df8bae1dSRodney W. Grimes /* 297df8bae1dSRodney W. Grimes * Check for multiple frees. Use a quick check to see if 298df8bae1dSRodney W. Grimes * it looks free before laboriously searching the freelist. 299df8bae1dSRodney W. Grimes */ 300df8bae1dSRodney W. Grimes if (freep->spare0 == WEIRD_ADDR) { 301ca67a4e4SPoul-Henning Kamp fp = (struct freelist *)kbp->kb_next; 302ca67a4e4SPoul-Henning Kamp while (fp) { 303ca67a4e4SPoul-Henning Kamp if (fp->spare0 != WEIRD_ADDR) { 304ca67a4e4SPoul-Henning Kamp printf("trashed free item %p\n", fp); 305ca67a4e4SPoul-Henning Kamp panic("free: free item modified"); 306ca67a4e4SPoul-Henning Kamp } else if (addr == (caddr_t)fp) { 307ca67a4e4SPoul-Henning Kamp printf("multiple freed item %p\n", addr); 308ca67a4e4SPoul-Henning Kamp panic("free: multiple free"); 309ca67a4e4SPoul-Henning Kamp } 310ca67a4e4SPoul-Henning Kamp fp = (struct freelist *)fp->next; 311df8bae1dSRodney W. Grimes } 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes /* 314df8bae1dSRodney W. Grimes * Copy in known text to detect modification after freeing 315df8bae1dSRodney W. Grimes * and to make it look free. Also, save the type being freed 316df8bae1dSRodney W. Grimes * so we can list likely culprit if modification is detected 317df8bae1dSRodney W. Grimes * when the object is reallocated. 318df8bae1dSRodney W. Grimes */ 319df8bae1dSRodney W. Grimes copysize = size < MAX_COPY ? size : MAX_COPY; 320df8bae1dSRodney W. Grimes end = (long *)&((caddr_t)addr)[copysize]; 321df8bae1dSRodney W. Grimes for (lp = (long *)addr; lp < end; lp++) 322df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 323df8bae1dSRodney W. Grimes freep->type = type; 324df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 325df8bae1dSRodney W. Grimes kup->ku_freecnt++; 326df8bae1dSRodney W. Grimes if (kup->ku_freecnt >= kbp->kb_elmpercl) 327df8bae1dSRodney W. Grimes if (kup->ku_freecnt > kbp->kb_elmpercl) 328df8bae1dSRodney W. Grimes panic("free: multiple frees"); 329df8bae1dSRodney W. Grimes else if (kbp->kb_totalfree > kbp->kb_highwat) 330df8bae1dSRodney W. Grimes kbp->kb_couldfree++; 331df8bae1dSRodney W. Grimes kbp->kb_totalfree++; 332df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 333df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 334df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 335df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 336df8bae1dSRodney W. Grimes ksp->ks_inuse--; 33714bf02f8SJohn Dyson #ifdef OLD_MALLOC_MEMORY_POLICY 338df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) 339df8bae1dSRodney W. Grimes kbp->kb_next = addr; 340df8bae1dSRodney W. Grimes else 341df8bae1dSRodney W. Grimes ((struct freelist *)kbp->kb_last)->next = addr; 342df8bae1dSRodney W. Grimes freep->next = NULL; 343df8bae1dSRodney W. Grimes kbp->kb_last = addr; 34414bf02f8SJohn Dyson #else 34514bf02f8SJohn Dyson /* 34614bf02f8SJohn Dyson * Return memory to the head of the queue for quick reuse. This 34714bf02f8SJohn Dyson * can improve performance by improving the probability of the 34814bf02f8SJohn Dyson * item being in the cache when it is reused. 34914bf02f8SJohn Dyson */ 35014bf02f8SJohn Dyson if (kbp->kb_next == NULL) { 35114bf02f8SJohn Dyson kbp->kb_next = addr; 35214bf02f8SJohn Dyson kbp->kb_last = addr; 35314bf02f8SJohn Dyson freep->next = NULL; 35414bf02f8SJohn Dyson } else { 35514bf02f8SJohn Dyson freep->next = kbp->kb_next; 35614bf02f8SJohn Dyson kbp->kb_next = addr; 35714bf02f8SJohn Dyson } 35814bf02f8SJohn Dyson #endif 359df8bae1dSRodney W. Grimes splx(s); 360df8bae1dSRodney W. Grimes } 361df8bae1dSRodney W. Grimes 362df8bae1dSRodney W. Grimes /* 363df8bae1dSRodney W. Grimes * Initialize the kernel memory allocator 364df8bae1dSRodney W. Grimes */ 3652b14f991SJulian Elischer /* ARGSUSED*/ 3662b14f991SJulian Elischer static void 367d841aaa7SBruce Evans kmeminit(dummy) 368d841aaa7SBruce Evans void *dummy; 369df8bae1dSRodney W. Grimes { 370df8bae1dSRodney W. Grimes register long indx; 371df8bae1dSRodney W. Grimes int npg; 372df8bae1dSRodney W. Grimes 373df8bae1dSRodney W. Grimes #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) 374cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE not power of 2" 375df8bae1dSRodney W. Grimes #endif 376df8bae1dSRodney W. Grimes #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 377cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too big" 378df8bae1dSRodney W. Grimes #endif 379f8845af0SPoul-Henning Kamp #if (MAXALLOCSAVE < PAGE_SIZE) 380cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too small" 381df8bae1dSRodney W. Grimes #endif 382cb7545a9SGarrett Wollman npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + VM_KMEM_SIZE) 383cb7545a9SGarrett Wollman / PAGE_SIZE; 3840d94caffSDavid Greenman 385df8bae1dSRodney W. Grimes kmemusage = (struct kmemusage *) kmem_alloc(kernel_map, 386df8bae1dSRodney W. Grimes (vm_size_t)(npg * sizeof(struct kmemusage))); 387df8bae1dSRodney W. Grimes kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase, 38854e7152cSDavid Greenman (vm_offset_t *)&kmemlimit, (vm_size_t)(npg * PAGE_SIZE), 38954e7152cSDavid Greenman FALSE); 3903075778bSJohn Dyson kmem_map->system_map = 1; 391df8bae1dSRodney W. Grimes for (indx = 0; indx < MINBUCKET + 16; indx++) { 392f8845af0SPoul-Henning Kamp if (1 << indx >= PAGE_SIZE) 393df8bae1dSRodney W. Grimes bucket[indx].kb_elmpercl = 1; 394df8bae1dSRodney W. Grimes else 395f8845af0SPoul-Henning Kamp bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx); 396df8bae1dSRodney W. Grimes bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 397df8bae1dSRodney W. Grimes } 398254c6cb3SPoul-Henning Kamp } 399254c6cb3SPoul-Henning Kamp 400254c6cb3SPoul-Henning Kamp static void 401254c6cb3SPoul-Henning Kamp malloc_init(type) 402254c6cb3SPoul-Henning Kamp struct kmemstats *type; 403254c6cb3SPoul-Henning Kamp { 404254c6cb3SPoul-Henning Kamp int npg; 405254c6cb3SPoul-Henning Kamp 406254c6cb3SPoul-Henning Kamp printf("%p [%s]", type, type->ks_shortdesc); 40707bbd7f1SDavid Greenman /* 40807bbd7f1SDavid Greenman * Limit maximum memory for each type to 60% of malloc area size or 40907bbd7f1SDavid Greenman * 60% of physical memory, whichever is smaller. 41007bbd7f1SDavid Greenman */ 411254c6cb3SPoul-Henning Kamp npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + VM_KMEM_SIZE) 412254c6cb3SPoul-Henning Kamp / PAGE_SIZE; 413254c6cb3SPoul-Henning Kamp 414254c6cb3SPoul-Henning Kamp type->ks_limit = min(cnt.v_page_count * PAGE_SIZE, 415cb7545a9SGarrett Wollman (npg * PAGE_SIZE - nmbclusters * MCLBYTES 416cb7545a9SGarrett Wollman - nmbufs * MSIZE)) * 6 / 10; 417254c6cb3SPoul-Henning Kamp type->ks_next = kmemstatistics; 418254c6cb3SPoul-Henning Kamp kmemstatistics = type; 419df8bae1dSRodney W. Grimes } 420