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