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> 42fb919e4dSMark Murray #include <sys/lock.h> 43df8bae1dSRodney W. Grimes #include <sys/malloc.h> 4454e7152cSDavid Greenman #include <sys/mbuf.h> 45eec258d2SJohn Baldwin #include <sys/mutex.h> 46efeaf95aSDavid Greenman #include <sys/vmmeter.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 6044a8ff31SArchie Cobbs /* 6144a8ff31SArchie Cobbs * When realloc() is called, if the new size is sufficiently smaller than 6244a8ff31SArchie Cobbs * the old size, realloc() will allocate a new, smaller block to avoid 6344a8ff31SArchie Cobbs * wasting memory. 'Sufficiently smaller' is defined as: newsize <= 6444a8ff31SArchie Cobbs * oldsize / 2^n, where REALLOC_FRACTION defines the value of 'n'. 6544a8ff31SArchie Cobbs */ 6644a8ff31SArchie Cobbs #ifndef REALLOC_FRACTION 6744a8ff31SArchie Cobbs #define REALLOC_FRACTION 1 /* new block if <= half the size */ 6844a8ff31SArchie Cobbs #endif 6944a8ff31SArchie Cobbs 703b6fb885SPoul-Henning Kamp MALLOC_DEFINE(M_CACHE, "cache", "Various Dynamically allocated caches"); 719ef246c6SBruce Evans MALLOC_DEFINE(M_DEVBUF, "devbuf", "device driver memory"); 729ef246c6SBruce Evans MALLOC_DEFINE(M_TEMP, "temp", "misc temporary data buffers"); 739ef246c6SBruce Evans 7482cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6OPT, "ip6opt", "IPv6 options"); 7582cd038dSYoshinobu Inoue MALLOC_DEFINE(M_IP6NDP, "ip6ndp", "IPv6 Neighbor Discovery"); 7682cd038dSYoshinobu Inoue 774590fd3aSDavid Greenman static void kmeminit __P((void *)); 782b14f991SJulian Elischer SYSINIT(kmem, SI_SUB_KMEM, SI_ORDER_FIRST, kmeminit, NULL) 792b14f991SJulian Elischer 80a1c995b6SPoul-Henning Kamp static MALLOC_DEFINE(M_FREE, "free", "should be on free list"); 81a1c995b6SPoul-Henning Kamp 82db669378SPeter Wemm static struct malloc_type *kmemstatistics; 83254c6cb3SPoul-Henning Kamp static struct kmembuckets bucket[MINBUCKET + 16]; 84254c6cb3SPoul-Henning Kamp static struct kmemusage *kmemusage; 85254c6cb3SPoul-Henning Kamp static char *kmembase; 86043a2f3bSBruce Evans static char *kmemlimit; 871f6889a1SMatthew Dillon 88d1c1b841SJason Evans static struct mtx malloc_mtx; 8969ef67f9SJason Evans 901f6889a1SMatthew Dillon u_int vm_kmem_size; 91df8bae1dSRodney W. Grimes 92219cbf59SEivind Eklund #ifdef INVARIANTS 93df8bae1dSRodney W. Grimes /* 94df8bae1dSRodney W. Grimes * This structure provides a set of masks to catch unaligned frees. 95df8bae1dSRodney W. Grimes */ 9687b6de2bSPoul-Henning Kamp static long addrmask[] = { 0, 97df8bae1dSRodney W. Grimes 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 98df8bae1dSRodney W. Grimes 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff, 99df8bae1dSRodney W. Grimes 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 100df8bae1dSRodney W. Grimes 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, 101df8bae1dSRodney W. Grimes }; 102df8bae1dSRodney W. Grimes 103df8bae1dSRodney W. Grimes /* 104df8bae1dSRodney W. Grimes * The WEIRD_ADDR is used as known text to copy into free objects so 105df8bae1dSRodney W. Grimes * that modifications after frees can be detected. 106df8bae1dSRodney W. Grimes */ 1075124d598SDavid Greenman #define WEIRD_ADDR 0xdeadc0de 1085124d598SDavid Greenman #define MAX_COPY 64 109df8bae1dSRodney W. Grimes 110df8bae1dSRodney W. Grimes /* 111df8bae1dSRodney W. Grimes * Normally the first word of the structure is used to hold the list 112df8bae1dSRodney W. Grimes * pointer for free objects. However, when running with diagnostics, 113df8bae1dSRodney W. Grimes * we use the third and fourth fields, so as to catch modifications 114df8bae1dSRodney W. Grimes * in the most commonly trashed first two words. 115df8bae1dSRodney W. Grimes */ 116df8bae1dSRodney W. Grimes struct freelist { 117df8bae1dSRodney W. Grimes long spare0; 11860a513e9SPoul-Henning Kamp struct malloc_type *type; 119df8bae1dSRodney W. Grimes long spare1; 120df8bae1dSRodney W. Grimes caddr_t next; 121df8bae1dSRodney W. Grimes }; 1225526d2d9SEivind Eklund #else /* !INVARIANTS */ 123df8bae1dSRodney W. Grimes struct freelist { 124df8bae1dSRodney W. Grimes caddr_t next; 125df8bae1dSRodney W. Grimes }; 1265526d2d9SEivind Eklund #endif /* INVARIANTS */ 127df8bae1dSRodney W. Grimes 128df8bae1dSRodney W. Grimes /* 1291c7c3c6aSMatthew Dillon * malloc: 1301c7c3c6aSMatthew Dillon * 1311c7c3c6aSMatthew Dillon * Allocate a block of memory. 1321c7c3c6aSMatthew Dillon * 1331c7c3c6aSMatthew Dillon * If M_NOWAIT is set, this routine will not block and return NULL if 1341c7c3c6aSMatthew Dillon * the allocation fails. 135df8bae1dSRodney W. Grimes */ 136df8bae1dSRodney W. Grimes void * 137df8bae1dSRodney W. Grimes malloc(size, type, flags) 138df8bae1dSRodney W. Grimes unsigned long size; 13960a513e9SPoul-Henning Kamp struct malloc_type *type; 140254c6cb3SPoul-Henning Kamp int flags; 141df8bae1dSRodney W. Grimes { 142df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 143df8bae1dSRodney W. Grimes register struct kmemusage *kup; 144df8bae1dSRodney W. Grimes register struct freelist *freep; 145df8bae1dSRodney W. Grimes long indx, npg, allocsize; 146df8bae1dSRodney W. Grimes int s; 147df8bae1dSRodney W. Grimes caddr_t va, cp, savedlist; 1485526d2d9SEivind Eklund #ifdef INVARIANTS 149df8bae1dSRodney W. Grimes long *end, *lp; 150df8bae1dSRodney W. Grimes int copysize; 151d254af07SMatthew Dillon const char *savedtype; 152df8bae1dSRodney W. Grimes #endif 15360a513e9SPoul-Henning Kamp register struct malloc_type *ksp = type; 154df8bae1dSRodney W. Grimes 1550fee3d35SPeter Wemm #if defined(INVARIANTS) 156984982d6SPoul-Henning Kamp if (flags == M_WAITOK) 157b40ce416SJulian Elischer KASSERT(curthread->td_intr_nesting_level == 0, 158984982d6SPoul-Henning Kamp ("malloc(M_WAITOK) in interrupt context")); 159984982d6SPoul-Henning Kamp #endif 160df8bae1dSRodney W. Grimes indx = BUCKETINDX(size); 161df8bae1dSRodney W. Grimes kbp = &bucket[indx]; 1628e8cac55SBruce Evans s = splmem(); 1639ed346baSBosko Milekic mtx_lock(&malloc_mtx); 164df8bae1dSRodney W. Grimes while (ksp->ks_memuse >= ksp->ks_limit) { 165df8bae1dSRodney W. Grimes if (flags & M_NOWAIT) { 166df8bae1dSRodney W. Grimes splx(s); 1679ed346baSBosko Milekic mtx_unlock(&malloc_mtx); 1681707240dSBoris Popov return ((void *) NULL); 169df8bae1dSRodney W. Grimes } 170df8bae1dSRodney W. Grimes if (ksp->ks_limblocks < 65535) 171df8bae1dSRodney W. Grimes ksp->ks_limblocks++; 17269ef67f9SJason Evans msleep((caddr_t)ksp, &malloc_mtx, PSWP+2, type->ks_shortdesc, 17369ef67f9SJason Evans 0); 174df8bae1dSRodney W. Grimes } 175df8bae1dSRodney W. Grimes ksp->ks_size |= 1 << indx; 1765526d2d9SEivind Eklund #ifdef INVARIANTS 177df8bae1dSRodney W. Grimes copysize = 1 << indx < MAX_COPY ? 1 << indx : MAX_COPY; 178df8bae1dSRodney W. Grimes #endif 179df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) { 180df8bae1dSRodney W. Grimes kbp->kb_last = NULL; 181df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) 182f8845af0SPoul-Henning Kamp allocsize = roundup(size, PAGE_SIZE); 183df8bae1dSRodney W. Grimes else 184df8bae1dSRodney W. Grimes allocsize = 1 << indx; 185e911eafcSPoul-Henning Kamp npg = btoc(allocsize); 18669ef67f9SJason Evans 1879ed346baSBosko Milekic mtx_unlock(&malloc_mtx); 1889f518539SDavid Greenman va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg), flags); 18969ef67f9SJason Evans 190df8bae1dSRodney W. Grimes if (va == NULL) { 191df8bae1dSRodney W. Grimes splx(s); 1921707240dSBoris Popov return ((void *) NULL); 193df8bae1dSRodney W. Grimes } 19469ef67f9SJason Evans /* 19569ef67f9SJason Evans * Enter malloc_mtx after the error check to avoid having to 19669ef67f9SJason Evans * immediately exit it again if there is an error. 19769ef67f9SJason Evans */ 1989ed346baSBosko Milekic mtx_lock(&malloc_mtx); 19969ef67f9SJason Evans 200df8bae1dSRodney W. Grimes kbp->kb_total += kbp->kb_elmpercl; 201df8bae1dSRodney W. Grimes kup = btokup(va); 202df8bae1dSRodney W. Grimes kup->ku_indx = indx; 203df8bae1dSRodney W. Grimes if (allocsize > MAXALLOCSAVE) { 204df8bae1dSRodney W. Grimes if (npg > 65535) 205df8bae1dSRodney W. Grimes panic("malloc: allocation too large"); 206df8bae1dSRodney W. Grimes kup->ku_pagecnt = npg; 207df8bae1dSRodney W. Grimes ksp->ks_memuse += allocsize; 208df8bae1dSRodney W. Grimes goto out; 209df8bae1dSRodney W. Grimes } 210df8bae1dSRodney W. Grimes kup->ku_freecnt = kbp->kb_elmpercl; 211df8bae1dSRodney W. Grimes kbp->kb_totalfree += kbp->kb_elmpercl; 212df8bae1dSRodney W. Grimes /* 213df8bae1dSRodney W. Grimes * Just in case we blocked while allocating memory, 214df8bae1dSRodney W. Grimes * and someone else also allocated memory for this 215df8bae1dSRodney W. Grimes * bucket, don't assume the list is still empty. 216df8bae1dSRodney W. Grimes */ 217df8bae1dSRodney W. Grimes savedlist = kbp->kb_next; 218e911eafcSPoul-Henning Kamp kbp->kb_next = cp = va + (npg * PAGE_SIZE) - allocsize; 219df8bae1dSRodney W. Grimes for (;;) { 220df8bae1dSRodney W. Grimes freep = (struct freelist *)cp; 2215526d2d9SEivind Eklund #ifdef INVARIANTS 222df8bae1dSRodney W. Grimes /* 223df8bae1dSRodney W. Grimes * Copy in known text to detect modification 224df8bae1dSRodney W. Grimes * after freeing. 225df8bae1dSRodney W. Grimes */ 226df8bae1dSRodney W. Grimes end = (long *)&cp[copysize]; 227df8bae1dSRodney W. Grimes for (lp = (long *)cp; lp < end; lp++) 228df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 229df8bae1dSRodney W. Grimes freep->type = M_FREE; 2305526d2d9SEivind Eklund #endif /* INVARIANTS */ 231df8bae1dSRodney W. Grimes if (cp <= va) 232df8bae1dSRodney W. Grimes break; 233df8bae1dSRodney W. Grimes cp -= allocsize; 234df8bae1dSRodney W. Grimes freep->next = cp; 235df8bae1dSRodney W. Grimes } 236df8bae1dSRodney W. Grimes freep->next = savedlist; 237df8bae1dSRodney W. Grimes if (kbp->kb_last == NULL) 238df8bae1dSRodney W. Grimes kbp->kb_last = (caddr_t)freep; 239df8bae1dSRodney W. Grimes } 240df8bae1dSRodney W. Grimes va = kbp->kb_next; 241df8bae1dSRodney W. Grimes kbp->kb_next = ((struct freelist *)va)->next; 2425526d2d9SEivind Eklund #ifdef INVARIANTS 243df8bae1dSRodney W. Grimes freep = (struct freelist *)va; 244dc760634SJun Kuriyama savedtype = (const char *) freep->type->ks_shortdesc; 24560a513e9SPoul-Henning Kamp freep->type = (struct malloc_type *)WEIRD_ADDR; 24686a14a7aSBruce Evans if ((intptr_t)(void *)&freep->next & 0x2) 247df8bae1dSRodney W. Grimes freep->next = (caddr_t)((WEIRD_ADDR >> 16)|(WEIRD_ADDR << 16)); 248df8bae1dSRodney W. Grimes else 249df8bae1dSRodney W. Grimes freep->next = (caddr_t)WEIRD_ADDR; 250df8bae1dSRodney W. Grimes end = (long *)&va[copysize]; 251df8bae1dSRodney W. Grimes for (lp = (long *)va; lp < end; lp++) { 252df8bae1dSRodney W. Grimes if (*lp == WEIRD_ADDR) 253df8bae1dSRodney W. Grimes continue; 254d974cf4dSBruce Evans printf("%s %ld of object %p size %lu %s %s (0x%lx != 0x%lx)\n", 255d974cf4dSBruce Evans "Data modified on freelist: word", 256d974cf4dSBruce Evans (long)(lp - (long *)va), (void *)va, size, 257d974cf4dSBruce Evans "previous type", savedtype, *lp, (u_long)WEIRD_ADDR); 258df8bae1dSRodney W. Grimes break; 259df8bae1dSRodney W. Grimes } 260df8bae1dSRodney W. Grimes freep->spare0 = 0; 2615526d2d9SEivind Eklund #endif /* INVARIANTS */ 262df8bae1dSRodney W. Grimes kup = btokup(va); 263df8bae1dSRodney W. Grimes if (kup->ku_indx != indx) 264df8bae1dSRodney W. Grimes panic("malloc: wrong bucket"); 265df8bae1dSRodney W. Grimes if (kup->ku_freecnt == 0) 266df8bae1dSRodney W. Grimes panic("malloc: lost data"); 267df8bae1dSRodney W. Grimes kup->ku_freecnt--; 268df8bae1dSRodney W. Grimes kbp->kb_totalfree--; 269df8bae1dSRodney W. Grimes ksp->ks_memuse += 1 << indx; 270df8bae1dSRodney W. Grimes out: 271df8bae1dSRodney W. Grimes kbp->kb_calls++; 272df8bae1dSRodney W. Grimes ksp->ks_inuse++; 273df8bae1dSRodney W. Grimes ksp->ks_calls++; 274df8bae1dSRodney W. Grimes if (ksp->ks_memuse > ksp->ks_maxused) 275df8bae1dSRodney W. Grimes ksp->ks_maxused = ksp->ks_memuse; 276df8bae1dSRodney W. Grimes splx(s); 2779ed346baSBosko Milekic mtx_unlock(&malloc_mtx); 2781921a06dSPoul-Henning Kamp /* XXX: Do idle pre-zeroing. */ 2791921a06dSPoul-Henning Kamp if (va != NULL && (flags & M_ZERO)) 2801921a06dSPoul-Henning Kamp bzero(va, size); 281df8bae1dSRodney W. Grimes return ((void *) va); 282df8bae1dSRodney W. Grimes } 283df8bae1dSRodney W. Grimes 284df8bae1dSRodney W. Grimes /* 2851c7c3c6aSMatthew Dillon * free: 2861c7c3c6aSMatthew Dillon * 287df8bae1dSRodney W. Grimes * Free a block of memory allocated by malloc. 2881c7c3c6aSMatthew Dillon * 2891c7c3c6aSMatthew Dillon * This routine may not block. 290df8bae1dSRodney W. Grimes */ 291df8bae1dSRodney W. Grimes void 292df8bae1dSRodney W. Grimes free(addr, type) 293df8bae1dSRodney W. Grimes void *addr; 29460a513e9SPoul-Henning Kamp struct malloc_type *type; 295df8bae1dSRodney W. Grimes { 296df8bae1dSRodney W. Grimes register struct kmembuckets *kbp; 297df8bae1dSRodney W. Grimes register struct kmemusage *kup; 298df8bae1dSRodney W. Grimes register struct freelist *freep; 299df8bae1dSRodney W. Grimes long size; 300df8bae1dSRodney W. Grimes int s; 3015526d2d9SEivind Eklund #ifdef INVARIANTS 302ca67a4e4SPoul-Henning Kamp struct freelist *fp; 303df8bae1dSRodney W. Grimes long *end, *lp, alloc, copysize; 304df8bae1dSRodney W. Grimes #endif 30560a513e9SPoul-Henning Kamp register struct malloc_type *ksp = type; 306254c6cb3SPoul-Henning Kamp 30744a8ff31SArchie Cobbs /* free(NULL, ...) does nothing */ 30844a8ff31SArchie Cobbs if (addr == NULL) 30944a8ff31SArchie Cobbs return; 31044a8ff31SArchie Cobbs 3115526d2d9SEivind Eklund KASSERT(kmembase <= (char *)addr && (char *)addr < kmemlimit, 3125526d2d9SEivind Eklund ("free: address %p out of range", (void *)addr)); 313df8bae1dSRodney W. Grimes kup = btokup(addr); 314df8bae1dSRodney W. Grimes size = 1 << kup->ku_indx; 315df8bae1dSRodney W. Grimes kbp = &bucket[kup->ku_indx]; 316b1897c19SJulian Elischer s = splmem(); 3179ed346baSBosko Milekic mtx_lock(&malloc_mtx); 3185526d2d9SEivind Eklund #ifdef INVARIANTS 319df8bae1dSRodney W. Grimes /* 320df8bae1dSRodney W. Grimes * Check for returns of data that do not point to the 321df8bae1dSRodney W. Grimes * beginning of the allocation. 322df8bae1dSRodney W. Grimes */ 323f8845af0SPoul-Henning Kamp if (size > PAGE_SIZE) 324f8845af0SPoul-Henning Kamp alloc = addrmask[BUCKETINDX(PAGE_SIZE)]; 325df8bae1dSRodney W. Grimes else 326df8bae1dSRodney W. Grimes alloc = addrmask[kup->ku_indx]; 32786a14a7aSBruce Evans if (((uintptr_t)(void *)addr & alloc) != 0) 328d974cf4dSBruce Evans panic("free: unaligned addr %p, size %ld, type %s, mask %ld", 329d974cf4dSBruce Evans (void *)addr, size, type->ks_shortdesc, alloc); 3305526d2d9SEivind Eklund #endif /* INVARIANTS */ 331df8bae1dSRodney W. Grimes if (size > MAXALLOCSAVE) { 3329ed346baSBosko Milekic mtx_unlock(&malloc_mtx); 333df8bae1dSRodney W. Grimes kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt)); 3349ed346baSBosko Milekic mtx_lock(&malloc_mtx); 33569ef67f9SJason Evans 336e911eafcSPoul-Henning Kamp size = kup->ku_pagecnt << PAGE_SHIFT; 337df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 338df8bae1dSRodney W. Grimes kup->ku_indx = 0; 339df8bae1dSRodney W. Grimes kup->ku_pagecnt = 0; 340df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 341df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 342df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 343df8bae1dSRodney W. Grimes ksp->ks_inuse--; 344df8bae1dSRodney W. Grimes kbp->kb_total -= 1; 345df8bae1dSRodney W. Grimes splx(s); 3469ed346baSBosko Milekic mtx_unlock(&malloc_mtx); 347df8bae1dSRodney W. Grimes return; 348df8bae1dSRodney W. Grimes } 349df8bae1dSRodney W. Grimes freep = (struct freelist *)addr; 3505526d2d9SEivind Eklund #ifdef INVARIANTS 351df8bae1dSRodney W. Grimes /* 352df8bae1dSRodney W. Grimes * Check for multiple frees. Use a quick check to see if 353df8bae1dSRodney W. Grimes * it looks free before laboriously searching the freelist. 354df8bae1dSRodney W. Grimes */ 355df8bae1dSRodney W. Grimes if (freep->spare0 == WEIRD_ADDR) { 356ca67a4e4SPoul-Henning Kamp fp = (struct freelist *)kbp->kb_next; 357ca67a4e4SPoul-Henning Kamp while (fp) { 358219cbf59SEivind Eklund if (fp->spare0 != WEIRD_ADDR) 3595526d2d9SEivind Eklund panic("free: free item %p modified", fp); 360219cbf59SEivind Eklund else if (addr == (caddr_t)fp) 3615526d2d9SEivind Eklund panic("free: multiple freed item %p", addr); 362ca67a4e4SPoul-Henning Kamp fp = (struct freelist *)fp->next; 363df8bae1dSRodney W. Grimes } 364df8bae1dSRodney W. Grimes } 365df8bae1dSRodney W. Grimes /* 366df8bae1dSRodney W. Grimes * Copy in known text to detect modification after freeing 367df8bae1dSRodney W. Grimes * and to make it look free. Also, save the type being freed 368df8bae1dSRodney W. Grimes * so we can list likely culprit if modification is detected 369df8bae1dSRodney W. Grimes * when the object is reallocated. 370df8bae1dSRodney W. Grimes */ 371df8bae1dSRodney W. Grimes copysize = size < MAX_COPY ? size : MAX_COPY; 372df8bae1dSRodney W. Grimes end = (long *)&((caddr_t)addr)[copysize]; 373df8bae1dSRodney W. Grimes for (lp = (long *)addr; lp < end; lp++) 374df8bae1dSRodney W. Grimes *lp = WEIRD_ADDR; 375df8bae1dSRodney W. Grimes freep->type = type; 3765526d2d9SEivind Eklund #endif /* INVARIANTS */ 377df8bae1dSRodney W. Grimes kup->ku_freecnt++; 378dfd5dee1SPeter Wemm if (kup->ku_freecnt >= kbp->kb_elmpercl) { 379df8bae1dSRodney W. Grimes if (kup->ku_freecnt > kbp->kb_elmpercl) 380df8bae1dSRodney W. Grimes panic("free: multiple frees"); 381df8bae1dSRodney W. Grimes else if (kbp->kb_totalfree > kbp->kb_highwat) 382df8bae1dSRodney W. Grimes kbp->kb_couldfree++; 383dfd5dee1SPeter Wemm } 384df8bae1dSRodney W. Grimes kbp->kb_totalfree++; 385df8bae1dSRodney W. Grimes ksp->ks_memuse -= size; 386df8bae1dSRodney W. Grimes if (ksp->ks_memuse + size >= ksp->ks_limit && 387df8bae1dSRodney W. Grimes ksp->ks_memuse < ksp->ks_limit) 388df8bae1dSRodney W. Grimes wakeup((caddr_t)ksp); 389df8bae1dSRodney W. Grimes ksp->ks_inuse--; 39014bf02f8SJohn Dyson #ifdef OLD_MALLOC_MEMORY_POLICY 391df8bae1dSRodney W. Grimes if (kbp->kb_next == NULL) 392df8bae1dSRodney W. Grimes kbp->kb_next = addr; 393df8bae1dSRodney W. Grimes else 394df8bae1dSRodney W. Grimes ((struct freelist *)kbp->kb_last)->next = addr; 395df8bae1dSRodney W. Grimes freep->next = NULL; 396df8bae1dSRodney W. Grimes kbp->kb_last = addr; 39714bf02f8SJohn Dyson #else 39814bf02f8SJohn Dyson /* 39914bf02f8SJohn Dyson * Return memory to the head of the queue for quick reuse. This 40014bf02f8SJohn Dyson * can improve performance by improving the probability of the 40114bf02f8SJohn Dyson * item being in the cache when it is reused. 40214bf02f8SJohn Dyson */ 40314bf02f8SJohn Dyson if (kbp->kb_next == NULL) { 40414bf02f8SJohn Dyson kbp->kb_next = addr; 40514bf02f8SJohn Dyson kbp->kb_last = addr; 40614bf02f8SJohn Dyson freep->next = NULL; 40714bf02f8SJohn Dyson } else { 40814bf02f8SJohn Dyson freep->next = kbp->kb_next; 40914bf02f8SJohn Dyson kbp->kb_next = addr; 41014bf02f8SJohn Dyson } 41114bf02f8SJohn Dyson #endif 412df8bae1dSRodney W. Grimes splx(s); 4139ed346baSBosko Milekic mtx_unlock(&malloc_mtx); 414df8bae1dSRodney W. Grimes } 415df8bae1dSRodney W. Grimes 416df8bae1dSRodney W. Grimes /* 41744a8ff31SArchie Cobbs * realloc: change the size of a memory block 41844a8ff31SArchie Cobbs */ 41944a8ff31SArchie Cobbs void * 42044a8ff31SArchie Cobbs realloc(addr, size, type, flags) 42144a8ff31SArchie Cobbs void *addr; 42244a8ff31SArchie Cobbs unsigned long size; 42344a8ff31SArchie Cobbs struct malloc_type *type; 42444a8ff31SArchie Cobbs int flags; 42544a8ff31SArchie Cobbs { 42644a8ff31SArchie Cobbs struct kmemusage *kup; 42744a8ff31SArchie Cobbs unsigned long alloc; 42844a8ff31SArchie Cobbs void *newaddr; 42944a8ff31SArchie Cobbs 43044a8ff31SArchie Cobbs /* realloc(NULL, ...) is equivalent to malloc(...) */ 43144a8ff31SArchie Cobbs if (addr == NULL) 43244a8ff31SArchie Cobbs return (malloc(size, type, flags)); 43344a8ff31SArchie Cobbs 43444a8ff31SArchie Cobbs /* Sanity check */ 43544a8ff31SArchie Cobbs KASSERT(kmembase <= (char *)addr && (char *)addr < kmemlimit, 43644a8ff31SArchie Cobbs ("realloc: address %p out of range", (void *)addr)); 43744a8ff31SArchie Cobbs 43844a8ff31SArchie Cobbs /* Get the size of the original block */ 43944a8ff31SArchie Cobbs kup = btokup(addr); 44044a8ff31SArchie Cobbs alloc = 1 << kup->ku_indx; 44144a8ff31SArchie Cobbs if (alloc > MAXALLOCSAVE) 44244a8ff31SArchie Cobbs alloc = kup->ku_pagecnt << PAGE_SHIFT; 44344a8ff31SArchie Cobbs 44444a8ff31SArchie Cobbs /* Reuse the original block if appropriate */ 44544a8ff31SArchie Cobbs if (size <= alloc 44644a8ff31SArchie Cobbs && (size > (alloc >> REALLOC_FRACTION) || alloc == MINALLOCSIZE)) 44744a8ff31SArchie Cobbs return (addr); 44844a8ff31SArchie Cobbs 44944a8ff31SArchie Cobbs /* Allocate a new, bigger (or smaller) block */ 45044a8ff31SArchie Cobbs if ((newaddr = malloc(size, type, flags)) == NULL) 45144a8ff31SArchie Cobbs return (NULL); 45244a8ff31SArchie Cobbs 45344a8ff31SArchie Cobbs /* Copy over original contents */ 45444a8ff31SArchie Cobbs bcopy(addr, newaddr, min(size, alloc)); 45544a8ff31SArchie Cobbs free(addr, type); 45644a8ff31SArchie Cobbs return (newaddr); 45744a8ff31SArchie Cobbs } 45844a8ff31SArchie Cobbs 45944a8ff31SArchie Cobbs /* 46044a8ff31SArchie Cobbs * reallocf: same as realloc() but free memory on failure. 46144a8ff31SArchie Cobbs */ 46244a8ff31SArchie Cobbs void * 46344a8ff31SArchie Cobbs reallocf(addr, size, type, flags) 46444a8ff31SArchie Cobbs void *addr; 46544a8ff31SArchie Cobbs unsigned long size; 46644a8ff31SArchie Cobbs struct malloc_type *type; 46744a8ff31SArchie Cobbs int flags; 46844a8ff31SArchie Cobbs { 46944a8ff31SArchie Cobbs void *mem; 47044a8ff31SArchie Cobbs 47144a8ff31SArchie Cobbs if ((mem = realloc(addr, size, type, flags)) == NULL) 47244a8ff31SArchie Cobbs free(addr, type); 47344a8ff31SArchie Cobbs return (mem); 47444a8ff31SArchie Cobbs } 47544a8ff31SArchie Cobbs 47644a8ff31SArchie Cobbs /* 477df8bae1dSRodney W. Grimes * Initialize the kernel memory allocator 478df8bae1dSRodney W. Grimes */ 4792b14f991SJulian Elischer /* ARGSUSED*/ 4802b14f991SJulian Elischer static void 481d841aaa7SBruce Evans kmeminit(dummy) 482d841aaa7SBruce Evans void *dummy; 483df8bae1dSRodney W. Grimes { 484df8bae1dSRodney W. Grimes register long indx; 48527b8623fSDavid Greenman u_long npg; 48627b8623fSDavid Greenman u_long mem_size; 487df8bae1dSRodney W. Grimes 488df8bae1dSRodney W. Grimes #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) 489cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE not power of 2" 490df8bae1dSRodney W. Grimes #endif 491df8bae1dSRodney W. Grimes #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) 492cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too big" 493df8bae1dSRodney W. Grimes #endif 494f8845af0SPoul-Henning Kamp #if (MAXALLOCSAVE < PAGE_SIZE) 495cb7545a9SGarrett Wollman #error "kmeminit: MAXALLOCSAVE too small" 496df8bae1dSRodney W. Grimes #endif 4978a58a9f6SJohn Dyson 498d1c1b841SJason Evans mtx_init(&malloc_mtx, "malloc", MTX_DEF); 49969ef67f9SJason Evans 5008a58a9f6SJohn Dyson /* 5018a58a9f6SJohn Dyson * Try to auto-tune the kernel memory size, so that it is 5028a58a9f6SJohn Dyson * more applicable for a wider range of machine sizes. 5038a58a9f6SJohn Dyson * On an X86, a VM_KMEM_SIZE_SCALE value of 4 is good, while 5048a58a9f6SJohn Dyson * a VM_KMEM_SIZE of 12MB is a fair compromise. The 5058a58a9f6SJohn Dyson * VM_KMEM_SIZE_MAX is dependent on the maximum KVA space 5068a58a9f6SJohn Dyson * available, and on an X86 with a total KVA space of 256MB, 5078a58a9f6SJohn Dyson * try to keep VM_KMEM_SIZE_MAX at 80MB or below. 5088a58a9f6SJohn Dyson * 5098a58a9f6SJohn Dyson * Note that the kmem_map is also used by the zone allocator, 5108a58a9f6SJohn Dyson * so make sure that there is enough space. 5118a58a9f6SJohn Dyson */ 51281930014SPeter Wemm vm_kmem_size = VM_KMEM_SIZE; 5138a58a9f6SJohn Dyson mem_size = cnt.v_page_count * PAGE_SIZE; 5148a58a9f6SJohn Dyson 5158a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_SCALE) 51681930014SPeter Wemm if ((mem_size / VM_KMEM_SIZE_SCALE) > vm_kmem_size) 51781930014SPeter Wemm vm_kmem_size = mem_size / VM_KMEM_SIZE_SCALE; 5188a58a9f6SJohn Dyson #endif 5198a58a9f6SJohn Dyson 5208a58a9f6SJohn Dyson #if defined(VM_KMEM_SIZE_MAX) 52181930014SPeter Wemm if (vm_kmem_size >= VM_KMEM_SIZE_MAX) 52281930014SPeter Wemm vm_kmem_size = VM_KMEM_SIZE_MAX; 5238a58a9f6SJohn Dyson #endif 5248a58a9f6SJohn Dyson 5258de6e8e1SMike Smith /* Allow final override from the kernel environment */ 52609786698SPeter Wemm TUNABLE_INT_FETCH("kern.vm.kmem.size", &vm_kmem_size); 5278de6e8e1SMike Smith 52827b8623fSDavid Greenman /* 52927b8623fSDavid Greenman * Limit kmem virtual size to twice the physical memory. 53027b8623fSDavid Greenman * This allows for kmem map sparseness, but limits the size 53127b8623fSDavid Greenman * to something sane. Be careful to not overflow the 32bit 53227b8623fSDavid Greenman * ints while doing the check. 53327b8623fSDavid Greenman */ 53427b8623fSDavid Greenman if ((vm_kmem_size / 2) > (cnt.v_page_count * PAGE_SIZE)) 53527b8623fSDavid Greenman vm_kmem_size = 2 * cnt.v_page_count * PAGE_SIZE; 5368a58a9f6SJohn Dyson 53708442f8aSBosko Milekic /* 538ba3e8826SBosko Milekic * In mbuf_init(), we set up submaps for mbufs and clusters, in which 53908442f8aSBosko Milekic * case we rounddown() (nmbufs * MSIZE) and (nmbclusters * MCLBYTES), 54008442f8aSBosko Milekic * respectively. Mathematically, this means that what we do here may 54108442f8aSBosko Milekic * amount to slightly more address space than we need for the submaps, 54208442f8aSBosko Milekic * but it never hurts to have an extra page in kmem_map. 54308442f8aSBosko Milekic */ 544d04d50d1SBosko Milekic npg = (nmbufs * MSIZE + nmbclusters * MCLBYTES + nmbcnt * 54508442f8aSBosko Milekic sizeof(u_int) + vm_kmem_size) / PAGE_SIZE; 5460d94caffSDavid Greenman 547df8bae1dSRodney W. Grimes kmemusage = (struct kmemusage *) kmem_alloc(kernel_map, 548df8bae1dSRodney W. Grimes (vm_size_t)(npg * sizeof(struct kmemusage))); 549df8bae1dSRodney W. Grimes kmem_map = kmem_suballoc(kernel_map, (vm_offset_t *)&kmembase, 5502d8acc0fSJohn Dyson (vm_offset_t *)&kmemlimit, (vm_size_t)(npg * PAGE_SIZE)); 5513075778bSJohn Dyson kmem_map->system_map = 1; 552df8bae1dSRodney W. Grimes for (indx = 0; indx < MINBUCKET + 16; indx++) { 553f8845af0SPoul-Henning Kamp if (1 << indx >= PAGE_SIZE) 554df8bae1dSRodney W. Grimes bucket[indx].kb_elmpercl = 1; 555df8bae1dSRodney W. Grimes else 556f8845af0SPoul-Henning Kamp bucket[indx].kb_elmpercl = PAGE_SIZE / (1 << indx); 557df8bae1dSRodney W. Grimes bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; 558df8bae1dSRodney W. Grimes } 559254c6cb3SPoul-Henning Kamp } 560254c6cb3SPoul-Henning Kamp 561db669378SPeter Wemm void 562db669378SPeter Wemm malloc_init(data) 563db669378SPeter Wemm void *data; 564254c6cb3SPoul-Henning Kamp { 565db669378SPeter Wemm struct malloc_type *type = (struct malloc_type *)data; 566254c6cb3SPoul-Henning Kamp 567d1bbc7ecSPoul-Henning Kamp if (type->ks_magic != M_MAGIC) 568d1bbc7ecSPoul-Henning Kamp panic("malloc type lacks magic"); 569d1bbc7ecSPoul-Henning Kamp 570ce45b512SBruce Evans if (type->ks_limit != 0) 571db669378SPeter Wemm return; 572db669378SPeter Wemm 573d4060a87SJohn Dyson if (cnt.v_page_count == 0) 574d4060a87SJohn Dyson panic("malloc_init not allowed before vm init"); 575d4060a87SJohn Dyson 57607bbd7f1SDavid Greenman /* 5778a58a9f6SJohn Dyson * The default limits for each malloc region is 1/2 of the 5788a58a9f6SJohn Dyson * malloc portion of the kmem map size. 57907bbd7f1SDavid Greenman */ 5808a58a9f6SJohn Dyson type->ks_limit = vm_kmem_size / 2; 581254c6cb3SPoul-Henning Kamp type->ks_next = kmemstatistics; 582254c6cb3SPoul-Henning Kamp kmemstatistics = type; 583df8bae1dSRodney W. Grimes } 584db669378SPeter Wemm 585db669378SPeter Wemm void 586db669378SPeter Wemm malloc_uninit(data) 587db669378SPeter Wemm void *data; 588db669378SPeter Wemm { 589db669378SPeter Wemm struct malloc_type *type = (struct malloc_type *)data; 590db669378SPeter Wemm struct malloc_type *t; 5915badeabaSBoris Popov #ifdef INVARIANTS 59299063cf8SBoris Popov struct kmembuckets *kbp; 59399063cf8SBoris Popov struct freelist *freep; 59499063cf8SBoris Popov long indx; 59599063cf8SBoris Popov int s; 59699063cf8SBoris Popov #endif 597db669378SPeter Wemm 598db669378SPeter Wemm if (type->ks_magic != M_MAGIC) 599db669378SPeter Wemm panic("malloc type lacks magic"); 600db669378SPeter Wemm 601db669378SPeter Wemm if (cnt.v_page_count == 0) 602db669378SPeter Wemm panic("malloc_uninit not allowed before vm init"); 603db669378SPeter Wemm 604ce45b512SBruce Evans if (type->ks_limit == 0) 605ce45b512SBruce Evans panic("malloc_uninit on uninitialized type"); 606ce45b512SBruce Evans 60799063cf8SBoris Popov #ifdef INVARIANTS 60899063cf8SBoris Popov s = splmem(); 6099ed346baSBosko Milekic mtx_lock(&malloc_mtx); 61099063cf8SBoris Popov for (indx = 0; indx < MINBUCKET + 16; indx++) { 61199063cf8SBoris Popov kbp = bucket + indx; 61299063cf8SBoris Popov freep = (struct freelist*)kbp->kb_next; 61399063cf8SBoris Popov while (freep) { 61499063cf8SBoris Popov if (freep->type == type) 61599063cf8SBoris Popov freep->type = M_FREE; 61699063cf8SBoris Popov freep = (struct freelist*)freep->next; 61799063cf8SBoris Popov } 61899063cf8SBoris Popov } 61999063cf8SBoris Popov splx(s); 6209ed346baSBosko Milekic mtx_unlock(&malloc_mtx); 62199063cf8SBoris Popov 62299063cf8SBoris Popov if (type->ks_memuse != 0) 62399063cf8SBoris Popov printf("malloc_uninit: %ld bytes of '%s' still allocated\n", 62499063cf8SBoris Popov type->ks_memuse, type->ks_shortdesc); 62599063cf8SBoris Popov #endif 62699063cf8SBoris Popov 627db669378SPeter Wemm if (type == kmemstatistics) 628db669378SPeter Wemm kmemstatistics = type->ks_next; 629db669378SPeter Wemm else { 630db669378SPeter Wemm for (t = kmemstatistics; t->ks_next != NULL; t = t->ks_next) { 631db669378SPeter Wemm if (t->ks_next == type) { 632db669378SPeter Wemm t->ks_next = type->ks_next; 633db669378SPeter Wemm break; 634db669378SPeter Wemm } 635db669378SPeter Wemm } 636db669378SPeter Wemm } 637ce45b512SBruce Evans type->ks_next = NULL; 638ce45b512SBruce Evans type->ks_limit = 0; 639db669378SPeter Wemm } 640