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 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 378a58a9f6SJohn Dyson #include "opt_vm.h" 388a58a9f6SJohn Dyson 39df8bae1dSRodney W. Grimes #include <sys/param.h> 4026f9a767SRodney W. Grimes #include <sys/systm.h> 41df8bae1dSRodney W. Grimes #include <sys/kernel.h> 42df8bae1dSRodney W. Grimes #include <sys/malloc.h> 4354e7152cSDavid Greenman #include <sys/mbuf.h> 44eec258d2SJohn Baldwin #include <sys/mutex.h> 45efeaf95aSDavid Greenman #include <sys/vmmeter.h> 463075778bSJohn Dyson #include <sys/lock.h> 47a448b62aSJake Burkholder #include <sys/proc.h> 489a02e8c6SJason Evans 49df8bae1dSRodney W. Grimes #include <vm/vm.h> 50efeaf95aSDavid Greenman #include <vm/vm_param.h> 51df8bae1dSRodney W. Grimes #include <vm/vm_kern.h> 52efeaf95aSDavid Greenman #include <vm/vm_extern.h> 533075778bSJohn Dyson #include <vm/pmap.h> 543075778bSJohn Dyson #include <vm/vm_map.h> 55df8bae1dSRodney W. Grimes 56984982d6SPoul-Henning Kamp #if defined(INVARIANTS) && defined(__i386__) 57984982d6SPoul-Henning Kamp #include <machine/cpu.h> 58984982d6SPoul-Henning Kamp #endif 59984982d6SPoul-Henning Kamp 603b6fb885SPoul-Henning Kamp MALLOC_DEFINE(M_CACHE, "cache", "Various Dynamically allocated caches"); 619ef246c6SBruce Evans MALLOC_DEFINE(M_DEVBUF, "devbuf", "device driver memory"); 629ef246c6SBruce Evans MALLOC_DEFINE(M_TEMP, "temp", "misc temporary data buffers"); 639ef246c6SBruce Evans 6482cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6OPT, "ip6opt", "IPv6 options"); 6582cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6NDP, "ip6ndp", "IPv6 Neighbor Discovery"); 6682cd038dSYoshinobu Inoue 674590fd3aSDavid Greenman static void kmeminit __P((void *)); 682b14f991SJulian Elischer SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL) 692b14f991SJulian Elischer 70a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FREE, "free", "should be on free list"); 71a1c995b6SPoul-Henning Kamp 72db669378SPeter Wemm static struct malloc_type *kmemstatistics; 73254c6cb3SPoul-Henning Kamp static struct kmembuckets bucket[MINBUCKET + 16]; 74254c6cb3SPoul-Henning Kamp static struct kmemusage *kmemusage; 75254c6cb3SPoul-Henning Kamp static char *kmembase; 76043a2f3bSBruce Evans static char *kmemlimit; 771f6889a1SMatthew Dillon 78d1c1b841SJason Evans static struct mtx malloc_mtx; 7969ef67f9SJason Evans 801f6889a1SMatthew Dillon u_int vm_kmem_size; 81df8bae1dSRodney W. Grimes 82219cbf59SEivind Eklund #ifdef INVARIANTS 83df8bae1dSRodney W. Grimes /* 84df8bae1dSRodney W. Grimes * This structure provides a set of masks to catch unaligned frees. 85df8bae1dSRodney W. Grimes */ 8687b6de2bSPoul-Henning Kamp static long addrmask[] = { 0, 87df8bae1dSRodney W. Grimes 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 88df8bae1dSRodney W. Grimes 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 89df8bae1dSRodney W. Grimes 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 90df8bae1dSRodney W. Grimes 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 91df8bae1dSRodney W. Grimes }; 92df8bae1dSRodney W. Grimes 93df8bae1dSRodney W. Grimes /* 94df8bae1dSRodney W. Grimes * The WEIRD_ADDR is used as known text to copy into free objects so 95df8bae1dSRodney W. Grimes * that modifications after frees can be detected. 96df8bae1dSRodney W. Grimes */ 975124d598SDavid Greenman #define WEIRD_ADDR 0xdeadc0de 985124d598SDavid Greenman #define MAX_COPY 64 99df8bae1dSRodney W. Grimes 100df8bae1dSRodney W. Grimes /* 101df8bae1dSRodney W. Grimes * Normally the first word of the structure is used to hold the list 102df8bae1dSRodney W. Grimes * pointer for free objects. However, when running with diagnostics, 103df8bae1dSRodney W. Grimes * we use the third and fourth fields, so as to catch modifications 104df8bae1dSRodney W. Grimes * in the most commonly trashed first two words. 105df8bae1dSRodney W. Grimes */ 106df8bae1dSRodney W. Grimes struct freelist { 107df8bae1dSRodney W. Grimes long spare0; 10860a513e9SPoul-Henning Kamp struct malloc_type *type; 109df8bae1dSRodney W. Grimes long spare1; 110df8bae1dSRodney W. Grimes caddr_t next; 111df8bae1dSRodney W. Grimes }; 1125526d2d9SEivind Eklund #else /* !INVARIANTS */ 113df8bae1dSRodney W. Grimes struct freelist { 114df8bae1dSRodney W. Grimes caddr_t next; 115df8bae1dSRodney W. Grimes }; 1165526d2d9SEivind Eklund #endif /* INVARIANTS */ 117df8bae1dSRodney W. Grimes 118df8bae1dSRodney W. Grimes /* 1191c7c3c6aSMatthew Dillon * malloc: 1201c7c3c6aSMatthew Dillon * 1211c7c3c6aSMatthew Dillon * Allocate a block of memory. 1221c7c3c6aSMatthew Dillon * 1231c7c3c6aSMatthew Dillon * If M_NOWAIT is set, this routine will not block and return NULL if 1241c7c3c6aSMatthew Dillon * the allocation fails. 1251c7c3c6aSMatthew Dillon * 1261c7c3c6aSMatthew Dillon * If M_ASLEEP is set (M_NOWAIT must also be set), this routine 1271c7c3c6aSMatthew Dillon * will have the side effect of calling asleep() if it returns NULL, 1281c7c3c6aSMatthew Dillon * allowing the parent to await() at some future time. 129df8bae1dSRodney W. Grimes */ 130df8bae1dSRodney W. Grimes void * 131df8bae1dSRodney W. Grimes malloc(size, type, flags) 132df8bae1dSRodney W. Grimes unsigned long size; 13360a513e9SPoul-Henning Kamp struct malloc_type *type; 134254c6cb3SPoul-Henning Kamp int flags; 135df8bae1dSRodney W. Grimes { 136df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 137df8bae1dSRodney W. Grimes register struct kmemusage *kup; 138df8bae1dSRodney W. Grimes register struct freelist *freep; 139df8bae1dSRodney W. Grimes long indx, npg, allocsize; 140df8bae1dSRodney W. Grimes int s; 141df8bae1dSRodney W. Grimes caddr_t va, cp, savedlist; 1425526d2d9SEivind Eklund #ifdef INVARIANTS 143df8bae1dSRodney W. Grimes long *end, *lp; 144df8bae1dSRodney W. Grimes int copysize; 145d254af07SMatthew Dillon const char *savedtype; 146df8bae1dSRodney W. Grimes #endif 14760a513e9SPoul-Henning Kamp register struct malloc_type *ksp = type; 148df8bae1dSRodney W. Grimes 149984982d6SPoul-Henning Kamp #if defined(INVARIANTS) && defined(__i386__) 150984982d6SPoul-Henning Kamp if (flags == M_WAITOK) 151a448b62aSJake Burkholder KASSERT(curproc->p_intr_nesting_level == 0, 152984982d6SPoul-Henning Kamp ("malloc(M_WAITOK) in interrupt context")); 153984982d6SPoul-Henning Kamp #endif 154df8bae1dSRodney W. Grimes indx = BUCKETINDX(size); 155df8bae1dSRodney W. Grimes kbp = &bucket[indx]; 1568e8cac55SBruce Evans s = splmem(); 15769ef67f9SJason Evans mtx_enter(&malloc_mtx, MTX_DEF); 158df8bae1dSRodney W. Grimes while (ksp->ks_memuse >= ksp->ks_limit) { 1591c7c3c6aSMatthew Dillon if (flags & M_ASLEEP) { 1601c7c3c6aSMatthew Dillon if (ksp->ks_limblocks < 65535) 1611c7c3c6aSMatthew Dillon ksp->ks_limblocks++; 1621c7c3c6aSMatthew Dillon asleep((caddr_t)ksp, PSWP+2, type->ks_shortdesc, 0); 1631c7c3c6aSMatthew Dillon } 164df8bae1dSRodney W. Grimes if (flags & M_NOWAIT) { 165df8bae1dSRodney W. Grimes splx(s); 16669ef67f9SJason Evans mtx_exit(&malloc_mtx, MTX_DEF); 167df8bae1dSRodney W. Grimes return ((void *) NULL); 168df8bae1dSRodney W. Grimes } 169df8bae1dSRodney W. Grimes if (ksp->ks_limblocks < 65535) 170df8bae1dSRodney W. Grimes ksp->ks_limblocks++; 17169ef67f9SJason Evans msleep((caddr_t)ksp, &malloc_mtx, PSWP+2, type->ks_shortdesc, 17269ef67f9SJason Evans 0); 173df8bae1dSRodney W. Grimes } 174df8bae1dSRodney W. Grimes ksp->ks_size |= 1 << indx; 1755526d2d9SEivind Eklund #ifdef INVARIANTS 176df8bae1dSRodney W. Grimes copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY; 177df8bae1dSRodney W. Grimes #endif 178df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) { 179df8bae1dSRodney W. Grimes kbp->kb_last = NULL; 180df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) 181f8845af0SPoul-Henning Kamp allocsize = roundup(size, PAGE_SIZE); 182df8bae1dSRodney W. Grimes else 183df8bae1dSRodney W. Grimes allocsize = 1 << indx; 184e911eafcSPoul-Henning Kamp npg = btoc(allocsize); 18569ef67f9SJason Evans 18669ef67f9SJason Evans mtx_exit(&malloc_mtx, MTX_DEF); 18769ef67f9SJason Evans mtx_enter(&Giant, MTX_DEF); 1889f518539SDavid Greenman va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags); 18969ef67f9SJason Evans mtx_exit(&Giant, MTX_DEF); 19069ef67f9SJason Evans 191df8bae1dSRodney W. Grimes if (va == NULL) { 192df8bae1dSRodney W. Grimes splx(s); 193df8bae1dSRodney W. Grimes return ((void *) NULL); 194df8bae1dSRodney W. Grimes } 19569ef67f9SJason Evans /* 19669ef67f9SJason Evans * Enter malloc_mtx after the error check to avoid having to 19769ef67f9SJason Evans * immediately exit it again if there is an error. 19869ef67f9SJason Evans */ 19969ef67f9SJason Evans mtx_enter(&malloc_mtx, MTX_DEF); 20069ef67f9SJason Evans 201df8bae1dSRodney W. Grimes kbp->kb_total += kbp->kb_elmpercl; 202df8bae1dSRodney W. Grimes kup = btokup(va); 203df8bae1dSRodney W. Grimes kup->ku_indx = indx; 204df8bae1dSRodney W. Grimes if (allocsize > MAXALLOCSAVE) { 205df8bae1dSRodney W. Grimes if (npg > 65535) 206df8bae1dSRodney W. Grimes panic("malloc: allocation too large"); 207df8bae1dSRodney W. Grimes kup->ku_pagecnt = npg; 208df8bae1dSRodney W. Grimes ksp->ks_memuse += allocsize; 209df8bae1dSRodney W. Grimes goto out; 210df8bae1dSRodney W. Grimes } 211df8bae1dSRodney W. Grimes kup->ku_freecnt = kbp->kb_elmpercl; 212df8bae1dSRodney W. Grimes kbp->kb_totalfree += kbp->kb_elmpercl; 213df8bae1dSRodney W. Grimes /* 214df8bae1dSRodney W. Grimes * Just in case we blocked while allocating memory, 215df8bae1dSRodney W. Grimes * and someone else also allocated memory for this 216df8bae1dSRodney W. Grimes * bucket, don't assume the list is still empty. 217df8bae1dSRodney W. Grimes */ 218df8bae1dSRodney W. Grimes savedlist = kbp->kb_next; 219e911eafcSPoul-Henning Kamp kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize; 220df8bae1dSRodney W. Grimes for (;;) { 221df8bae1dSRodney W. Grimes freep = (struct freelist *)cp; 2225526d2d9SEivind Eklund #ifdef INVARIANTS 223df8bae1dSRodney W. Grimes /* 224df8bae1dSRodney W. Grimes * Copy in known text to detect modification 225df8bae1dSRodney W. Grimes * after freeing. 226df8bae1dSRodney W. Grimes */ 227df8bae1dSRodney W. Grimes end = (long *)&cp[copysize]; 228df8bae1dSRodney W. Grimes for (lp = (long *)cp; lp < end; lp++) 229df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 230df8bae1dSRodney W. Grimes freep->type = M_FREE; 2315526d2d9SEivind Eklund #endif /* INVARIANTS */ 232df8bae1dSRodney W. Grimes if (cp <= va) 233df8bae1dSRodney W. Grimes break; 234df8bae1dSRodney W. Grimes cp -= allocsize; 235df8bae1dSRodney W. Grimes freep->next = cp; 236df8bae1dSRodney W. Grimes } 237df8bae1dSRodney W. Grimes freep->next = savedlist; 238df8bae1dSRodney W. Grimes if (kbp->kb_last == NULL) 239df8bae1dSRodney W. Grimes kbp->kb_last = (caddr_t)freep; 240df8bae1dSRodney W. Grimes } 241df8bae1dSRodney W. Grimes va = kbp->kb_next; 242df8bae1dSRodney W. Grimes kbp->kb_next = ((struct freelist *)va)->next; 2435526d2d9SEivind Eklund #ifdef INVARIANTS 244df8bae1dSRodney W. Grimes freep = (struct freelist *)va; 245dc760634SJun Kuriyama savedtype = (const char *) freep->type->ks_shortdesc; 246df8bae1dSRodney W. Grimes #if BYTE_ORDER == BIG_ENDIAN 24760a513e9SPoul-Henning Kamp freep->type = (struct malloc_type *)WEIRD_ADDR >> 16; 248df8bae1dSRodney W. Grimes #endif 249df8bae1dSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN 25060a513e9SPoul-Henning Kamp freep->type = (struct malloc_type *)WEIRD_ADDR; 251df8bae1dSRodney W. Grimes #endif 25286a14a7aSBruce Evans if ((intptr_t)(void *)&freep->next & 0x2) 253df8bae1dSRodney W. Grimes freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16)); 254df8bae1dSRodney W. Grimes else 255df8bae1dSRodney W. Grimes freep->next = (caddr_t)WEIRD_ADDR; 256df8bae1dSRodney W. Grimes end = (long *)&va[copysize]; 257df8bae1dSRodney W. Grimes for (lp = (long *)va; lp < end; lp++) { 258df8bae1dSRodney W. Grimes if (*lp == WEIRD_ADDR) 259df8bae1dSRodney W. Grimes continue; 260d974cf4dSBruce Evans printf("%s %ld of object %p size %lu %s %s (0x%lx != 0x%lx)\n", 261d974cf4dSBruce Evans "Data modified on freelist: word", 262d974cf4dSBruce Evans (long)(lp - (long *)va), (void *)va, size, 263d974cf4dSBruce Evans "previous type", savedtype, *lp, (u_long)WEIRD_ADDR); 264df8bae1dSRodney W. Grimes break; 265df8bae1dSRodney W. Grimes } 266df8bae1dSRodney W. Grimes freep->spare0 = 0; 2675526d2d9SEivind Eklund #endif /* INVARIANTS */ 268df8bae1dSRodney W. Grimes kup = btokup(va); 269df8bae1dSRodney W. Grimes if (kup->ku_indx != indx) 270df8bae1dSRodney W. Grimes panic("malloc: wrong bucket"); 271df8bae1dSRodney W. Grimes if (kup->ku_freecnt == 0) 272df8bae1dSRodney W. Grimes panic("malloc: lost data"); 273df8bae1dSRodney W. Grimes kup->ku_freecnt--; 274df8bae1dSRodney W. Grimes kbp->kb_totalfree--; 275df8bae1dSRodney W. Grimes ksp->ks_memuse += 1 << indx; 276df8bae1dSRodney W. Grimes out: 277df8bae1dSRodney W. Grimes kbp->kb_calls++; 278df8bae1dSRodney W. Grimes ksp->ks_inuse++; 279df8bae1dSRodney W. Grimes ksp->ks_calls++; 280df8bae1dSRodney W. Grimes if (ksp->ks_memuse > ksp->ks_maxused) 281df8bae1dSRodney W. Grimes ksp->ks_maxused = ksp->ks_memuse; 282df8bae1dSRodney W. Grimes splx(s); 28369ef67f9SJason Evans mtx_exit(&malloc_mtx, MTX_DEF); 2841921a06dSPoul-Henning Kamp /* XXX: Do idle pre-zeroing. */ 2851921a06dSPoul-Henning Kamp if (va != NULL && (flags & M_ZERO)) 2861921a06dSPoul-Henning Kamp bzero(va, size); 287df8bae1dSRodney W. Grimes return ((void *) va); 288df8bae1dSRodney W. Grimes } 289df8bae1dSRodney W. Grimes 290df8bae1dSRodney W. Grimes /* 2911c7c3c6aSMatthew Dillon * free: 2921c7c3c6aSMatthew Dillon * 293df8bae1dSRodney W. Grimes * Free a block of memory allocated by malloc. 2941c7c3c6aSMatthew Dillon * 2951c7c3c6aSMatthew Dillon * This routine may not block. 296df8bae1dSRodney W. Grimes */ 297df8bae1dSRodney W. Grimes void 298df8bae1dSRodney W. Grimes free(addr, type) 299df8bae1dSRodney W. Grimes void *addr; 30060a513e9SPoul-Henning Kamp struct malloc_type *type; 301df8bae1dSRodney W. Grimes { 302df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 303df8bae1dSRodney W. Grimes register struct kmemusage *kup; 304df8bae1dSRodney W. Grimes register struct freelist *freep; 305df8bae1dSRodney W. Grimes long size; 306df8bae1dSRodney W. Grimes int s; 3075526d2d9SEivind Eklund #ifdef INVARIANTS 308ca67a4e4SPoul-Henning Kamp struct freelist *fp; 309df8bae1dSRodney W. Grimes long *end, *lp, alloc, copysize; 310df8bae1dSRodney W. Grimes #endif 31160a513e9SPoul-Henning Kamp register struct malloc_type *ksp = type; 312254c6cb3SPoul-Henning Kamp 3135526d2d9SEivind Eklund KASSERT(kmembase <= (char *)addr && (char *)addr < kmemlimit, 3145526d2d9SEivind Eklund ("free: address %p out of range", (void *)addr)); 315df8bae1dSRodney W. Grimes kup = btokup(addr); 316df8bae1dSRodney W. Grimes size = 1 << kup->ku_indx; 317df8bae1dSRodney W. Grimes kbp = &bucket[kup->ku_indx]; 318b1897c19SJulian Elischer s = splmem(); 31969ef67f9SJason Evans mtx_enter(&malloc_mtx, MTX_DEF); 3205526d2d9SEivind Eklund #ifdef INVARIANTS 321df8bae1dSRodney W. Grimes /* 322df8bae1dSRodney W. Grimes * Check for returns of data that do not point to the 323df8bae1dSRodney W. Grimes * beginning of the allocation. 324df8bae1dSRodney W. Grimes */ 325f8845af0SPoul-Henning Kamp if (size > PAGE_SIZE) 326f8845af0SPoul-Henning Kamp alloc = addrmask[BUCKETINDX(PAGE_SIZE)]; 327df8bae1dSRodney W. Grimes else 328df8bae1dSRodney W. Grimes alloc = addrmask[kup->ku_indx]; 32986a14a7aSBruce Evans if (((uintptr_t)(void *)addr & alloc) != 0) 330d974cf4dSBruce Evans panic("free: unaligned addr %p, size %ld, type %s, mask %ld", 331d974cf4dSBruce Evans (void *)addr, size, type->ks_shortdesc, alloc); 3325526d2d9SEivind Eklund #endif /* INVARIANTS */ 333df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) { 33469ef67f9SJason Evans mtx_exit(&malloc_mtx, MTX_DEF); 33569ef67f9SJason Evans mtx_enter(&Giant, MTX_DEF); 336df8bae1dSRodney W. Grimes kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt)); 33769ef67f9SJason Evans mtx_exit(&Giant, MTX_DEF); 33869ef67f9SJason Evans mtx_enter(&malloc_mtx, MTX_DEF); 33969ef67f9SJason Evans 340e911eafcSPoul-Henning Kamp size = kup->ku_pagecnt << PAGE_SHIFT; 341df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 342df8bae1dSRodney W. Grimes kup->ku_indx = 0; 343df8bae1dSRodney W. Grimes kup->ku_pagecnt = 0; 344df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 345df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 346df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 347df8bae1dSRodney W. Grimes ksp->ks_inuse--; 348df8bae1dSRodney W. Grimes kbp->kb_total -= 1; 349df8bae1dSRodney W. Grimes splx(s); 35069ef67f9SJason Evans mtx_exit(&malloc_mtx, MTX_DEF); 351df8bae1dSRodney W. Grimes return; 352df8bae1dSRodney W. Grimes } 353df8bae1dSRodney W. Grimes freep = (struct freelist *)addr; 3545526d2d9SEivind Eklund #ifdef INVARIANTS 355df8bae1dSRodney W. Grimes /* 356df8bae1dSRodney W. Grimes * Check for multiple frees. Use a quick check to see if 357df8bae1dSRodney W. Grimes * it looks free before laboriously searching the freelist. 358df8bae1dSRodney W. Grimes */ 359df8bae1dSRodney W. Grimes if (freep->spare0 == WEIRD_ADDR) { 360ca67a4e4SPoul-Henning Kamp fp = (struct freelist *)kbp->kb_next; 361ca67a4e4SPoul-Henning Kamp while (fp) { 362219cbf59SEivind Eklund if (fp->spare0 != WEIRD_ADDR) 3635526d2d9SEivind Eklund panic("free: free item %p modified", fp); 364219cbf59SEivind Eklund else if (addr == (caddr_t)fp) 3655526d2d9SEivind Eklund panic("free: multiple freed item %p", addr); 366ca67a4e4SPoul-Henning Kamp fp = (struct freelist *)fp->next; 367df8bae1dSRodney W. Grimes } 368df8bae1dSRodney W. Grimes } 369df8bae1dSRodney W. Grimes /* 370df8bae1dSRodney W. Grimes * Copy in known text to detect modification after freeing 371df8bae1dSRodney W. Grimes * and to make it look free. Also, save the type being freed 372df8bae1dSRodney W. Grimes * so we can list likely culprit if modification is detected 373df8bae1dSRodney W. Grimes * when the object is reallocated. 374df8bae1dSRodney W. Grimes */ 375df8bae1dSRodney W. Grimes copysize = size < MAX_COPY ? size : MAX_COPY; 376df8bae1dSRodney W. Grimes end = (long *)&((caddr_t)addr)[copysize]; 377df8bae1dSRodney W. Grimes for (lp = (long *)addr; lp < end; lp++) 378df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 379df8bae1dSRodney W. Grimes freep->type = type; 3805526d2d9SEivind Eklund #endif /* INVARIANTS */ 381df8bae1dSRodney W. Grimes kup->ku_freecnt++; 382dfd5dee1SPeter Wemm if (kup->ku_freecnt >= kbp->kb_elmpercl) { 383df8bae1dSRodney W. Grimes if (kup->ku_freecnt > kbp->kb_elmpercl) 384df8bae1dSRodney W. Grimes panic("free: multiple frees"); 385df8bae1dSRodney W. Grimes else if (kbp->kb_totalfree > kbp->kb_highwat) 386df8bae1dSRodney W. Grimes kbp->kb_couldfree++; 387dfd5dee1SPeter Wemm } 388df8bae1dSRodney W. Grimes kbp->kb_totalfree++; 389df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 390df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 391df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 392df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 393df8bae1dSRodney W. Grimes ksp->ks_inuse--; 39414bf02f8SJohn Dyson #ifdef OLD_MALLOC_MEMORY_POLICY 395df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) 396df8bae1dSRodney W. Grimes kbp->kb_next = addr; 397df8bae1dSRodney W. Grimes else 398df8bae1dSRodney W. Grimes ((struct freelist *)kbp->kb_last)->next = addr; 399df8bae1dSRodney W. Grimes freep->next = NULL; 400df8bae1dSRodney W. Grimes kbp->kb_last = addr; 40114bf02f8SJohn Dyson #else 40214bf02f8SJohn Dyson /* 40314bf02f8SJohn Dyson * Return memory to the head of the queue for quick reuse. This 40414bf02f8SJohn Dyson * can improve performance by improving the probability of the 40514bf02f8SJohn Dyson * item being in the cache when it is reused. 40614bf02f8SJohn Dyson */ 40714bf02f8SJohn Dyson if (kbp->kb_next == NULL) { 40814bf02f8SJohn Dyson kbp->kb_next = addr; 40914bf02f8SJohn Dyson kbp->kb_last = addr; 41014bf02f8SJohn Dyson freep->next = NULL; 41114bf02f8SJohn Dyson } else { 41214bf02f8SJohn Dyson freep->next = kbp->kb_next; 41314bf02f8SJohn Dyson kbp->kb_next = addr; 41414bf02f8SJohn Dyson } 41514bf02f8SJohn Dyson #endif 416df8bae1dSRodney W. Grimes splx(s); 41769ef67f9SJason Evans mtx_exit(&malloc_mtx, MTX_DEF); 418df8bae1dSRodney W. Grimes } 419df8bae1dSRodney W. Grimes 420df8bae1dSRodney W. Grimes /* 421df8bae1dSRodney W. Grimes * Initialize the kernel memory allocator 422df8bae1dSRodney W. Grimes */ 4232b14f991SJulian Elischer /* ARGSUSED*/ 4242b14f991SJulian Elischer static void 425d841aaa7SBruce Evans kmeminit(dummy) 426d841aaa7SBruce Evans void *dummy; 427df8bae1dSRodney W. Grimes { 428df8bae1dSRodney W. Grimes register long indx; 42927b8623fSDavid Greenman u_long npg; 43027b8623fSDavid Greenman u_long mem_size; 43127b8623fSDavid Greenman u_long xvm_kmem_size; 432df8bae1dSRodney W. Grimes 433df8bae1dSRodney W. Grimes #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) 434cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE not power of 2" 435df8bae1dSRodney W. Grimes #endif 436df8bae1dSRodney W. Grimes #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 437cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too big" 438df8bae1dSRodney W. Grimes #endif 439f8845af0SPoul-Henning Kamp #if (MAXALLOCSAVE < PAGE_SIZE) 440cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too small" 441df8bae1dSRodney W. Grimes #endif 4428a58a9f6SJohn Dyson 443d1c1b841SJason Evans mtx_init(&malloc_mtx, "malloc", MTX_DEF); 44469ef67f9SJason Evans 4458a58a9f6SJohn Dyson /* 4468a58a9f6SJohn Dyson * Try to auto-tune the kernel memory size, so that it is 4478a58a9f6SJohn Dyson * more applicable for a wider range of machine sizes. 4488a58a9f6SJohn Dyson * On an X86, a VM_KMEM_SIZE_SCALE value of 4 is good, while 4498a58a9f6SJohn Dyson * a VM_KMEM_SIZE of 12MB is a fair compromise. The 4508a58a9f6SJohn Dyson * VM_KMEM_SIZE_MAX is dependent on the maximum KVA space 4518a58a9f6SJohn Dyson * available, and on an X86 with a total KVA space of 256MB, 4528a58a9f6SJohn Dyson * try to keep VM_KMEM_SIZE_MAX at 80MB or below. 4538a58a9f6SJohn Dyson * 4548a58a9f6SJohn Dyson * Note that the kmem_map is also used by the zone allocator, 4558a58a9f6SJohn Dyson * so make sure that there is enough space. 4568a58a9f6SJohn Dyson */ 457134c934cSMike Smith xvm_kmem_size = VM_KMEM_SIZE; 4588a58a9f6SJohn Dyson mem_size = cnt.v_page_count * PAGE_SIZE; 4598a58a9f6SJohn Dyson 4608a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_SCALE) 461134c934cSMike Smith if ((mem_size / VM_KMEM_SIZE_SCALE) > xvm_kmem_size) 462134c934cSMike Smith xvm_kmem_size = mem_size / VM_KMEM_SIZE_SCALE; 4638a58a9f6SJohn Dyson #endif 4648a58a9f6SJohn Dyson 4658a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_MAX) 466134c934cSMike Smith if (xvm_kmem_size >= VM_KMEM_SIZE_MAX) 467134c934cSMike Smith xvm_kmem_size = VM_KMEM_SIZE_MAX; 4688a58a9f6SJohn Dyson #endif 4698a58a9f6SJohn Dyson 4708de6e8e1SMike Smith /* Allow final override from the kernel environment */ 471134c934cSMike Smith TUNABLE_INT_FETCH("kern.vm.kmem.size", xvm_kmem_size, vm_kmem_size); 4728de6e8e1SMike Smith 47327b8623fSDavid Greenman /* 47427b8623fSDavid Greenman * Limit kmem virtual size to twice the physical memory. 47527b8623fSDavid Greenman * This allows for kmem map sparseness, but limits the size 47627b8623fSDavid Greenman * to something sane. Be careful to not overflow the 32bit 47727b8623fSDavid Greenman * ints while doing the check. 47827b8623fSDavid Greenman */ 47927b8623fSDavid Greenman if ((vm_kmem_size / 2) > (cnt.v_page_count * PAGE_SIZE)) 48027b8623fSDavid Greenman vm_kmem_size = 2 * cnt.v_page_count * PAGE_SIZE; 4818a58a9f6SJohn Dyson 4828a58a9f6SJohn Dyson npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + vm_kmem_size) 483cb7545a9SGarrett Wollman / PAGE_SIZE; 4840d94caffSDavid Greenman 485df8bae1dSRodney W. Grimes kmemusage = (struct kmemusage *) kmem_alloc(kernel_map, 486df8bae1dSRodney W. Grimes (vm_size_t)(npg * sizeof(struct kmemusage))); 487df8bae1dSRodney W. Grimes kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase, 4882d8acc0fSJohn Dyson (vm_offset_t *)&kmemlimit, (vm_size_t)(npg * PAGE_SIZE)); 4893075778bSJohn Dyson kmem_map->system_map = 1; 490df8bae1dSRodney W. Grimes for (indx = 0; indx < MINBUCKET + 16; indx++) { 491f8845af0SPoul-Henning Kamp if (1 << indx >= PAGE_SIZE) 492df8bae1dSRodney W. Grimes bucket[indx].kb_elmpercl = 1; 493df8bae1dSRodney W. Grimes else 494f8845af0SPoul-Henning Kamp bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx); 495df8bae1dSRodney W. Grimes bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 496df8bae1dSRodney W. Grimes } 497254c6cb3SPoul-Henning Kamp } 498254c6cb3SPoul-Henning Kamp 499db669378SPeter Wemm void 500db669378SPeter Wemm malloc_init(data) 501db669378SPeter Wemm void *data; 502254c6cb3SPoul-Henning Kamp { 503db669378SPeter Wemm struct malloc_type *type = (struct malloc_type *)data; 504254c6cb3SPoul-Henning Kamp 505d1bbc7ecSPoul-Henning Kamp if (type->ks_magic != M_MAGIC) 506d1bbc7ecSPoul-Henning Kamp panic("malloc type lacks magic"); 507d1bbc7ecSPoul-Henning Kamp 508ce45b512SBruce Evans if (type->ks_limit != 0) 509db669378SPeter Wemm return; 510db669378SPeter Wemm 511d4060a87SJohn Dyson if (cnt.v_page_count == 0) 512d4060a87SJohn Dyson panic("malloc_init not allowed before vm init"); 513d4060a87SJohn Dyson 51407bbd7f1SDavid Greenman /* 5158a58a9f6SJohn Dyson * The default limits for each malloc region is 1/2 of the 5168a58a9f6SJohn Dyson * malloc portion of the kmem map size. 51707bbd7f1SDavid Greenman */ 5188a58a9f6SJohn Dyson type->ks_limit = vm_kmem_size / 2; 519254c6cb3SPoul-Henning Kamp type->ks_next = kmemstatistics; 520254c6cb3SPoul-Henning Kamp kmemstatistics = type; 521df8bae1dSRodney W. Grimes } 522db669378SPeter Wemm 523db669378SPeter Wemm void 524db669378SPeter Wemm malloc_uninit(data) 525db669378SPeter Wemm void *data; 526db669378SPeter Wemm { 527db669378SPeter Wemm struct malloc_type *type = (struct malloc_type *)data; 528db669378SPeter Wemm struct malloc_type *t; 5295badeabaSBoris Popov #ifdef INVARIANTS 53099063cf8SBoris Popov struct kmembuckets *kbp; 53199063cf8SBoris Popov struct freelist *freep; 53299063cf8SBoris Popov long indx; 53399063cf8SBoris Popov int s; 53499063cf8SBoris Popov #endif 535db669378SPeter Wemm 536db669378SPeter Wemm if (type->ks_magic != M_MAGIC) 537db669378SPeter Wemm panic("malloc type lacks magic"); 538db669378SPeter Wemm 539db669378SPeter Wemm if (cnt.v_page_count == 0) 540db669378SPeter Wemm panic("malloc_uninit not allowed before vm init"); 541db669378SPeter Wemm 542ce45b512SBruce Evans if (type->ks_limit == 0) 543ce45b512SBruce Evans panic("malloc_uninit on uninitialized type"); 544ce45b512SBruce Evans 54599063cf8SBoris Popov #ifdef INVARIANTS 54699063cf8SBoris Popov s = splmem(); 54769ef67f9SJason Evans mtx_enter(&malloc_mtx, MTX_DEF); 54899063cf8SBoris Popov for (indx = 0; indx < MINBUCKET + 16; indx++) { 54999063cf8SBoris Popov kbp = bucket + indx; 55099063cf8SBoris Popov freep = (struct freelist*)kbp->kb_next; 55199063cf8SBoris Popov while (freep) { 55299063cf8SBoris Popov if (freep->type == type) 55399063cf8SBoris Popov freep->type = M_FREE; 55499063cf8SBoris Popov freep = (struct freelist*)freep->next; 55599063cf8SBoris Popov } 55699063cf8SBoris Popov } 55799063cf8SBoris Popov splx(s); 55869ef67f9SJason Evans mtx_exit(&malloc_mtx, MTX_DEF); 55999063cf8SBoris Popov 56099063cf8SBoris Popov if (type->ks_memuse != 0) 56199063cf8SBoris Popov printf("malloc_uninit: %ld bytes of '%s' still allocated\n", 56299063cf8SBoris Popov type->ks_memuse, type->ks_shortdesc); 56399063cf8SBoris Popov #endif 56499063cf8SBoris Popov 565db669378SPeter Wemm if (type == kmemstatistics) 566db669378SPeter Wemm kmemstatistics = type->ks_next; 567db669378SPeter Wemm else { 568db669378SPeter Wemm for (t = kmemstatistics; t->ks_next != NULL; t = t->ks_next) { 569db669378SPeter Wemm if (t->ks_next == type) { 570db669378SPeter Wemm t->ks_next = type->ks_next; 571db669378SPeter Wemm break; 572db669378SPeter Wemm } 573db669378SPeter Wemm } 574db669378SPeter Wemm } 575ce45b512SBruce Evans type->ks_next = NULL; 576ce45b512SBruce Evans type->ks_limit = 0; 577db669378SPeter Wemm } 578