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 34df8bae1dSRodney W. Grimes */ 35df8bae1dSRodney W. Grimes 36df8bae1dSRodney W. Grimes #include <sys/param.h> 3726f9a767SRodney W. Grimes #include <sys/systm.h> 38df8bae1dSRodney W. Grimes #include <sys/proc.h> 39df8bae1dSRodney W. Grimes #include <sys/map.h> 40df8bae1dSRodney W. Grimes #include <sys/kernel.h> 41df8bae1dSRodney W. Grimes #include <sys/malloc.h> 42df8bae1dSRodney W. Grimes 43df8bae1dSRodney W. Grimes #include <vm/vm.h> 44df8bae1dSRodney W. Grimes #include <vm/vm_kern.h> 45df8bae1dSRodney W. Grimes 46df8bae1dSRodney W. Grimes struct kmembuckets bucket[MINBUCKET + 16]; 47df8bae1dSRodney W. Grimes struct kmemstats kmemstats[M_LAST]; 48df8bae1dSRodney W. Grimes struct kmemusage *kmemusage; 49df8bae1dSRodney W. Grimes char *kmembase, *kmemlimit; 50df8bae1dSRodney W. Grimes char *memname[] = INITKMEMNAMES; 51df8bae1dSRodney W. Grimes 52df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 53df8bae1dSRodney W. Grimes /* 54df8bae1dSRodney W. Grimes * This structure provides a set of masks to catch unaligned frees. 55df8bae1dSRodney W. Grimes */ 56df8bae1dSRodney W. Grimes long addrmask[] = { 0, 57df8bae1dSRodney W. Grimes 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 58df8bae1dSRodney W. Grimes 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 59df8bae1dSRodney W. Grimes 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 60df8bae1dSRodney W. Grimes 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 61df8bae1dSRodney W. Grimes }; 62df8bae1dSRodney W. Grimes 63df8bae1dSRodney W. Grimes /* 64df8bae1dSRodney W. Grimes * The WEIRD_ADDR is used as known text to copy into free objects so 65df8bae1dSRodney W. Grimes * that modifications after frees can be detected. 66df8bae1dSRodney W. Grimes */ 67df8bae1dSRodney W. Grimes #define WEIRD_ADDR 0xdeadbeef 68df8bae1dSRodney W. Grimes #define MAX_COPY 32 69df8bae1dSRodney W. Grimes 70df8bae1dSRodney W. Grimes /* 71df8bae1dSRodney W. Grimes * Normally the first word of the structure is used to hold the list 72df8bae1dSRodney W. Grimes * pointer for free objects. However, when running with diagnostics, 73df8bae1dSRodney W. Grimes * we use the third and fourth fields, so as to catch modifications 74df8bae1dSRodney W. Grimes * in the most commonly trashed first two words. 75df8bae1dSRodney W. Grimes */ 76df8bae1dSRodney W. Grimes struct freelist { 77df8bae1dSRodney W. Grimes long spare0; 78df8bae1dSRodney W. Grimes short type; 79df8bae1dSRodney W. Grimes long spare1; 80df8bae1dSRodney W. Grimes caddr_t next; 81df8bae1dSRodney W. Grimes }; 82df8bae1dSRodney W. Grimes #else /* !DIAGNOSTIC */ 83df8bae1dSRodney W. Grimes struct freelist { 84df8bae1dSRodney W. Grimes caddr_t next; 85df8bae1dSRodney W. Grimes }; 86df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 87df8bae1dSRodney W. Grimes 88df8bae1dSRodney W. Grimes /* 89df8bae1dSRodney W. Grimes * Allocate a block of memory 90df8bae1dSRodney W. Grimes */ 91df8bae1dSRodney W. Grimes void * 92df8bae1dSRodney W. Grimes malloc(size, type, flags) 93df8bae1dSRodney W. Grimes unsigned long size; 94df8bae1dSRodney W. Grimes int type, flags; 95df8bae1dSRodney W. Grimes { 96df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 97df8bae1dSRodney W. Grimes register struct kmemusage *kup; 98df8bae1dSRodney W. Grimes register struct freelist *freep; 99df8bae1dSRodney W. Grimes long indx, npg, allocsize; 100df8bae1dSRodney W. Grimes int s; 101df8bae1dSRodney W. Grimes caddr_t va, cp, savedlist; 102df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 103df8bae1dSRodney W. Grimes long *end, *lp; 104df8bae1dSRodney W. Grimes int copysize; 105df8bae1dSRodney W. Grimes char *savedtype; 106df8bae1dSRodney W. Grimes #endif 107df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 108df8bae1dSRodney W. Grimes register struct kmemstats *ksp = &kmemstats[type]; 109df8bae1dSRodney W. Grimes 110df8bae1dSRodney W. Grimes if (((unsigned long)type) > M_LAST) 111df8bae1dSRodney W. Grimes panic("malloc - bogus type"); 112df8bae1dSRodney W. Grimes #endif 113df8bae1dSRodney W. Grimes indx = BUCKETINDX(size); 114df8bae1dSRodney W. Grimes kbp = &bucket[indx]; 115df8bae1dSRodney W. Grimes s = splimp(); 116df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 117df8bae1dSRodney W. Grimes while (ksp->ks_memuse >= ksp->ks_limit) { 118df8bae1dSRodney W. Grimes if (flags & M_NOWAIT) { 119df8bae1dSRodney W. Grimes splx(s); 120df8bae1dSRodney W. Grimes return ((void *) NULL); 121df8bae1dSRodney W. Grimes } 122df8bae1dSRodney W. Grimes if (ksp->ks_limblocks < 65535) 123df8bae1dSRodney W. Grimes ksp->ks_limblocks++; 124df8bae1dSRodney W. Grimes tsleep((caddr_t)ksp, PSWP+2, memname[type], 0); 125df8bae1dSRodney W. Grimes } 126df8bae1dSRodney W. Grimes ksp->ks_size |= 1 << indx; 127df8bae1dSRodney W. Grimes #endif 128df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 129df8bae1dSRodney W. Grimes copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY; 130df8bae1dSRodney W. Grimes #endif 131df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) { 132df8bae1dSRodney W. Grimes kbp->kb_last = NULL; 133df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) 134df8bae1dSRodney W. Grimes allocsize = roundup(size, CLBYTES); 135df8bae1dSRodney W. Grimes else 136df8bae1dSRodney W. Grimes allocsize = 1 << indx; 137df8bae1dSRodney W. Grimes npg = clrnd(btoc(allocsize)); 138df8bae1dSRodney W. Grimes va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), 139df8bae1dSRodney W. Grimes !(flags & M_NOWAIT)); 140df8bae1dSRodney W. Grimes if (va == NULL) { 141df8bae1dSRodney W. Grimes splx(s); 142df8bae1dSRodney W. Grimes return ((void *) NULL); 143df8bae1dSRodney W. Grimes } 144df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 145df8bae1dSRodney W. Grimes kbp->kb_total += kbp->kb_elmpercl; 146df8bae1dSRodney W. Grimes #endif 147df8bae1dSRodney W. Grimes kup = btokup(va); 148df8bae1dSRodney W. Grimes kup->ku_indx = indx; 149df8bae1dSRodney W. Grimes if (allocsize > MAXALLOCSAVE) { 150df8bae1dSRodney W. Grimes if (npg > 65535) 151df8bae1dSRodney W. Grimes panic("malloc: allocation too large"); 152df8bae1dSRodney W. Grimes kup->ku_pagecnt = npg; 153df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 154df8bae1dSRodney W. Grimes ksp->ks_memuse += allocsize; 155df8bae1dSRodney W. Grimes #endif 156df8bae1dSRodney W. Grimes goto out; 157df8bae1dSRodney W. Grimes } 158df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 159df8bae1dSRodney W. Grimes kup->ku_freecnt = kbp->kb_elmpercl; 160df8bae1dSRodney W. Grimes kbp->kb_totalfree += kbp->kb_elmpercl; 161df8bae1dSRodney W. Grimes #endif 162df8bae1dSRodney W. Grimes /* 163df8bae1dSRodney W. Grimes * Just in case we blocked while allocating memory, 164df8bae1dSRodney W. Grimes * and someone else also allocated memory for this 165df8bae1dSRodney W. Grimes * bucket, don't assume the list is still empty. 166df8bae1dSRodney W. Grimes */ 167df8bae1dSRodney W. Grimes savedlist = kbp->kb_next; 168df8bae1dSRodney W. Grimes kbp->kb_next = cp = va + (npg * NBPG) - allocsize; 169df8bae1dSRodney W. Grimes for (;;) { 170df8bae1dSRodney W. Grimes freep = (struct freelist *)cp; 171df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 172df8bae1dSRodney W. Grimes /* 173df8bae1dSRodney W. Grimes * Copy in known text to detect modification 174df8bae1dSRodney W. Grimes * after freeing. 175df8bae1dSRodney W. Grimes */ 176df8bae1dSRodney W. Grimes end = (long *)&cp[copysize]; 177df8bae1dSRodney W. Grimes for (lp = (long *)cp; lp < end; lp++) 178df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 179df8bae1dSRodney W. Grimes freep->type = M_FREE; 180df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 181df8bae1dSRodney W. Grimes if (cp <= va) 182df8bae1dSRodney W. Grimes break; 183df8bae1dSRodney W. Grimes cp -= allocsize; 184df8bae1dSRodney W. Grimes freep->next = cp; 185df8bae1dSRodney W. Grimes } 186df8bae1dSRodney W. Grimes freep->next = savedlist; 187df8bae1dSRodney W. Grimes if (kbp->kb_last == NULL) 188df8bae1dSRodney W. Grimes kbp->kb_last = (caddr_t)freep; 189df8bae1dSRodney W. Grimes } 190df8bae1dSRodney W. Grimes va = kbp->kb_next; 191df8bae1dSRodney W. Grimes kbp->kb_next = ((struct freelist *)va)->next; 192df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 193df8bae1dSRodney W. Grimes freep = (struct freelist *)va; 194df8bae1dSRodney W. Grimes savedtype = (unsigned)freep->type < M_LAST ? 195df8bae1dSRodney W. Grimes memname[freep->type] : "???"; 196df8bae1dSRodney W. Grimes if (kbp->kb_next && 197df8bae1dSRodney W. Grimes !kernacc(kbp->kb_next, sizeof(struct freelist), 0)) { 198df8bae1dSRodney W. Grimes printf("%s of object 0x%x size %d %s %s (invalid addr 0x%x)\n", 199df8bae1dSRodney W. Grimes "Data modified on freelist: word 2.5", va, size, 200df8bae1dSRodney W. Grimes "previous type", savedtype, kbp->kb_next); 201df8bae1dSRodney W. Grimes kbp->kb_next = NULL; 202df8bae1dSRodney W. Grimes } 203df8bae1dSRodney W. Grimes #if BYTE_ORDER == BIG_ENDIAN 204df8bae1dSRodney W. Grimes freep->type = WEIRD_ADDR >> 16; 205df8bae1dSRodney W. Grimes #endif 206df8bae1dSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN 207df8bae1dSRodney W. Grimes freep->type = (short)WEIRD_ADDR; 208df8bae1dSRodney W. Grimes #endif 209df8bae1dSRodney W. Grimes if (((long)(&freep->next)) & 0x2) 210df8bae1dSRodney W. Grimes freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16)); 211df8bae1dSRodney W. Grimes else 212df8bae1dSRodney W. Grimes freep->next = (caddr_t)WEIRD_ADDR; 213df8bae1dSRodney W. Grimes end = (long *)&va[copysize]; 214df8bae1dSRodney W. Grimes for (lp = (long *)va; lp < end; lp++) { 215df8bae1dSRodney W. Grimes if (*lp == WEIRD_ADDR) 216df8bae1dSRodney W. Grimes continue; 217df8bae1dSRodney W. Grimes printf("%s %d of object 0x%x size %d %s %s (0x%x != 0x%x)\n", 218df8bae1dSRodney W. Grimes "Data modified on freelist: word", lp - (long *)va, 219df8bae1dSRodney W. Grimes va, size, "previous type", savedtype, *lp, WEIRD_ADDR); 220df8bae1dSRodney W. Grimes break; 221df8bae1dSRodney W. Grimes } 222df8bae1dSRodney W. Grimes freep->spare0 = 0; 223df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 224df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 225df8bae1dSRodney W. Grimes kup = btokup(va); 226df8bae1dSRodney W. Grimes if (kup->ku_indx != indx) 227df8bae1dSRodney W. Grimes panic("malloc: wrong bucket"); 228df8bae1dSRodney W. Grimes if (kup->ku_freecnt == 0) 229df8bae1dSRodney W. Grimes panic("malloc: lost data"); 230df8bae1dSRodney W. Grimes kup->ku_freecnt--; 231df8bae1dSRodney W. Grimes kbp->kb_totalfree--; 232df8bae1dSRodney W. Grimes ksp->ks_memuse += 1 << indx; 233df8bae1dSRodney W. Grimes out: 234df8bae1dSRodney W. Grimes kbp->kb_calls++; 235df8bae1dSRodney W. Grimes ksp->ks_inuse++; 236df8bae1dSRodney W. Grimes ksp->ks_calls++; 237df8bae1dSRodney W. Grimes if (ksp->ks_memuse > ksp->ks_maxused) 238df8bae1dSRodney W. Grimes ksp->ks_maxused = ksp->ks_memuse; 239df8bae1dSRodney W. Grimes #else 240df8bae1dSRodney W. Grimes out: 241df8bae1dSRodney W. Grimes #endif 242df8bae1dSRodney W. Grimes splx(s); 243df8bae1dSRodney W. Grimes return ((void *) va); 244df8bae1dSRodney W. Grimes } 245df8bae1dSRodney W. Grimes 246df8bae1dSRodney W. Grimes /* 247df8bae1dSRodney W. Grimes * Free a block of memory allocated by malloc. 248df8bae1dSRodney W. Grimes */ 249df8bae1dSRodney W. Grimes void 250df8bae1dSRodney W. Grimes free(addr, type) 251df8bae1dSRodney W. Grimes void *addr; 252df8bae1dSRodney W. Grimes int type; 253df8bae1dSRodney W. Grimes { 254df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 255df8bae1dSRodney W. Grimes register struct kmemusage *kup; 256df8bae1dSRodney W. Grimes register struct freelist *freep; 257df8bae1dSRodney W. Grimes long size; 258df8bae1dSRodney W. Grimes int s; 259df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 260df8bae1dSRodney W. Grimes caddr_t cp; 261df8bae1dSRodney W. Grimes long *end, *lp, alloc, copysize; 262df8bae1dSRodney W. Grimes #endif 263df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 264df8bae1dSRodney W. Grimes register struct kmemstats *ksp = &kmemstats[type]; 265df8bae1dSRodney W. Grimes #endif 266df8bae1dSRodney W. Grimes 267df8bae1dSRodney W. Grimes kup = btokup(addr); 268df8bae1dSRodney W. Grimes size = 1 << kup->ku_indx; 269df8bae1dSRodney W. Grimes kbp = &bucket[kup->ku_indx]; 270df8bae1dSRodney W. Grimes s = splimp(); 271df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 272df8bae1dSRodney W. Grimes /* 273df8bae1dSRodney W. Grimes * Check for returns of data that do not point to the 274df8bae1dSRodney W. Grimes * beginning of the allocation. 275df8bae1dSRodney W. Grimes */ 276df8bae1dSRodney W. Grimes if (size > NBPG * CLSIZE) 277df8bae1dSRodney W. Grimes alloc = addrmask[BUCKETINDX(NBPG * CLSIZE)]; 278df8bae1dSRodney W. Grimes else 279df8bae1dSRodney W. Grimes alloc = addrmask[kup->ku_indx]; 280df8bae1dSRodney W. Grimes if (((u_long)addr & alloc) != 0) 281df8bae1dSRodney W. Grimes panic("free: unaligned addr 0x%x, size %d, type %s, mask %d\n", 282df8bae1dSRodney W. Grimes addr, size, memname[type], alloc); 283df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 284df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) { 285df8bae1dSRodney W. Grimes kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt)); 286df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 287df8bae1dSRodney W. Grimes size = kup->ku_pagecnt << PGSHIFT; 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 #endif 297df8bae1dSRodney W. Grimes splx(s); 298df8bae1dSRodney W. Grimes return; 299df8bae1dSRodney W. Grimes } 300df8bae1dSRodney W. Grimes freep = (struct freelist *)addr; 301df8bae1dSRodney W. Grimes #ifdef DIAGNOSTIC 302df8bae1dSRodney W. Grimes /* 303df8bae1dSRodney W. Grimes * Check for multiple frees. Use a quick check to see if 304df8bae1dSRodney W. Grimes * it looks free before laboriously searching the freelist. 305df8bae1dSRodney W. Grimes */ 306df8bae1dSRodney W. Grimes if (freep->spare0 == WEIRD_ADDR) { 307df8bae1dSRodney W. Grimes for (cp = kbp->kb_next; cp; cp = *(caddr_t *)cp) { 308df8bae1dSRodney W. Grimes if (addr != cp) 309df8bae1dSRodney W. Grimes continue; 310df8bae1dSRodney W. Grimes printf("multiply freed item 0x%x\n", addr); 311df8bae1dSRodney W. Grimes panic("free: duplicated free"); 312df8bae1dSRodney W. Grimes } 313df8bae1dSRodney W. Grimes } 314df8bae1dSRodney W. Grimes /* 315df8bae1dSRodney W. Grimes * Copy in known text to detect modification after freeing 316df8bae1dSRodney W. Grimes * and to make it look free. Also, save the type being freed 317df8bae1dSRodney W. Grimes * so we can list likely culprit if modification is detected 318df8bae1dSRodney W. Grimes * when the object is reallocated. 319df8bae1dSRodney W. Grimes */ 320df8bae1dSRodney W. Grimes copysize = size < MAX_COPY ? size : MAX_COPY; 321df8bae1dSRodney W. Grimes end = (long *)&((caddr_t)addr)[copysize]; 322df8bae1dSRodney W. Grimes for (lp = (long *)addr; lp < end; lp++) 323df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 324df8bae1dSRodney W. Grimes freep->type = type; 325df8bae1dSRodney W. Grimes #endif /* DIAGNOSTIC */ 326df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 327df8bae1dSRodney W. Grimes kup->ku_freecnt++; 328df8bae1dSRodney W. Grimes if (kup->ku_freecnt >= kbp->kb_elmpercl) 329df8bae1dSRodney W. Grimes if (kup->ku_freecnt > kbp->kb_elmpercl) 330df8bae1dSRodney W. Grimes panic("free: multiple frees"); 331df8bae1dSRodney W. Grimes else if (kbp->kb_totalfree > kbp->kb_highwat) 332df8bae1dSRodney W. Grimes kbp->kb_couldfree++; 333df8bae1dSRodney W. Grimes kbp->kb_totalfree++; 334df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 335df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 336df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 337df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 338df8bae1dSRodney W. Grimes ksp->ks_inuse--; 339df8bae1dSRodney W. Grimes #endif 340df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) 341df8bae1dSRodney W. Grimes kbp->kb_next = addr; 342df8bae1dSRodney W. Grimes else 343df8bae1dSRodney W. Grimes ((struct freelist *)kbp->kb_last)->next = addr; 344df8bae1dSRodney W. Grimes freep->next = NULL; 345df8bae1dSRodney W. Grimes kbp->kb_last = addr; 346df8bae1dSRodney W. Grimes splx(s); 347df8bae1dSRodney W. Grimes } 348df8bae1dSRodney W. Grimes 349df8bae1dSRodney W. Grimes /* 350df8bae1dSRodney W. Grimes * Initialize the kernel memory allocator 351df8bae1dSRodney W. Grimes */ 35226f9a767SRodney W. Grimes void 353df8bae1dSRodney W. Grimes kmeminit() 354df8bae1dSRodney W. Grimes { 355df8bae1dSRodney W. Grimes register long indx; 356df8bae1dSRodney W. Grimes int npg; 357df8bae1dSRodney W. Grimes 358df8bae1dSRodney W. Grimes #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) 359df8bae1dSRodney W. Grimes ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2 360df8bae1dSRodney W. Grimes #endif 361df8bae1dSRodney W. Grimes #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 362df8bae1dSRodney W. Grimes ERROR!_kmeminit:_MAXALLOCSAVE_too_big 363df8bae1dSRodney W. Grimes #endif 364df8bae1dSRodney W. Grimes #if (MAXALLOCSAVE < CLBYTES) 365df8bae1dSRodney W. Grimes ERROR!_kmeminit:_MAXALLOCSAVE_too_small 366df8bae1dSRodney W. Grimes #endif 367df8bae1dSRodney W. Grimes npg = VM_KMEM_SIZE/ NBPG; 368df8bae1dSRodney W. Grimes kmemusage = (struct kmemusage *) kmem_alloc(kernel_map, 369df8bae1dSRodney W. Grimes (vm_size_t)(npg * sizeof(struct kmemusage))); 370df8bae1dSRodney W. Grimes kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase, 371df8bae1dSRodney W. Grimes (vm_offset_t *)&kmemlimit, (vm_size_t)(npg * NBPG), FALSE); 372df8bae1dSRodney W. Grimes #ifdef KMEMSTATS 373df8bae1dSRodney W. Grimes for (indx = 0; indx < MINBUCKET + 16; indx++) { 374df8bae1dSRodney W. Grimes if (1 << indx >= CLBYTES) 375df8bae1dSRodney W. Grimes bucket[indx].kb_elmpercl = 1; 376df8bae1dSRodney W. Grimes else 377df8bae1dSRodney W. Grimes bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); 378df8bae1dSRodney W. Grimes bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 379df8bae1dSRodney W. Grimes } 380df8bae1dSRodney W. Grimes for (indx = 0; indx < M_LAST; indx++) 381df8bae1dSRodney W. Grimes kmemstats[indx].ks_limit = npg * NBPG * 6 / 10; 382df8bae1dSRodney W. Grimes #endif 383df8bae1dSRodney W. Grimes } 384