1168404Spjd/*- 2168404Spjd * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3168404Spjd * All rights reserved. 4168404Spjd * 5168404Spjd * Redistribution and use in source and binary forms, with or without 6168404Spjd * modification, are permitted provided that the following conditions 7168404Spjd * are met: 8168404Spjd * 1. Redistributions of source code must retain the above copyright 9168404Spjd * notice, this list of conditions and the following disclaimer. 10168404Spjd * 2. Redistributions in binary form must reproduce the above copyright 11168404Spjd * notice, this list of conditions and the following disclaimer in the 12168404Spjd * documentation and/or other materials provided with the distribution. 13168404Spjd * 14168404Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15168404Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16168404Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17168404Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18168404Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19168404Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20168404Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21168404Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22168404Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23168404Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24168404Spjd * SUCH DAMAGE. 25168404Spjd */ 26168404Spjd 27168404Spjd#include <sys/cdefs.h> 28168404Spjd__FBSDID("$FreeBSD$"); 29168404Spjd 30168404Spjd#include <sys/param.h> 31168404Spjd#include <sys/kernel.h> 32168404Spjd#include <sys/systm.h> 33168404Spjd#include <sys/malloc.h> 34168404Spjd#include <sys/kmem.h> 35168404Spjd#include <sys/debug.h> 36168404Spjd#include <sys/mutex.h> 37168566Spjd 38168566Spjd#include <vm/vm_page.h> 39168566Spjd#include <vm/vm_object.h> 40168566Spjd#include <vm/vm_kern.h> 41168566Spjd#include <vm/vm_map.h> 42168566Spjd 43168566Spjd#ifdef KMEM_DEBUG 44168404Spjd#include <sys/queue.h> 45168404Spjd#include <sys/stack.h> 46168566Spjd#endif 47168404Spjd 48168404Spjd#ifdef _KERNEL 49219089SpjdMALLOC_DEFINE(M_SOLARIS, "solaris", "Solaris"); 50168404Spjd#else 51168404Spjd#define malloc(size, type, flags) malloc(size) 52168404Spjd#define free(addr, type) free(addr) 53168404Spjd#endif 54168404Spjd 55168404Spjd#ifdef KMEM_DEBUG 56168404Spjdstruct kmem_item { 57168404Spjd struct stack stack; 58168404Spjd LIST_ENTRY(kmem_item) next; 59168404Spjd}; 60168404Spjdstatic LIST_HEAD(, kmem_item) kmem_items; 61168404Spjdstatic struct mtx kmem_items_mtx; 62168404SpjdMTX_SYSINIT(kmem_items_mtx, &kmem_items_mtx, "kmem_items", MTX_DEF); 63168404Spjd#endif /* KMEM_DEBUG */ 64168404Spjd 65254025Sjeff#include <sys/vmem.h> 66254025Sjeff 67168404Spjdvoid * 68168404Spjdzfs_kmem_alloc(size_t size, int kmflags) 69168404Spjd{ 70168404Spjd void *p; 71168404Spjd#ifdef KMEM_DEBUG 72168404Spjd struct kmem_item *i; 73168404Spjd 74168404Spjd size += sizeof(struct kmem_item); 75168404Spjd#endif 76168404Spjd p = malloc(size, M_SOLARIS, kmflags); 77168404Spjd#ifndef _KERNEL 78168404Spjd if (kmflags & KM_SLEEP) 79168404Spjd assert(p != NULL); 80168404Spjd#endif 81168404Spjd#ifdef KMEM_DEBUG 82168404Spjd if (p != NULL) { 83168404Spjd i = p; 84168404Spjd p = (u_char *)p + sizeof(struct kmem_item); 85168404Spjd stack_save(&i->stack); 86168404Spjd mtx_lock(&kmem_items_mtx); 87168404Spjd LIST_INSERT_HEAD(&kmem_items, i, next); 88168404Spjd mtx_unlock(&kmem_items_mtx); 89168404Spjd } 90168404Spjd#endif 91168404Spjd return (p); 92168404Spjd} 93168404Spjd 94168404Spjdvoid 95168404Spjdzfs_kmem_free(void *buf, size_t size __unused) 96168404Spjd{ 97168404Spjd#ifdef KMEM_DEBUG 98184698Srodrigc if (buf == NULL) { 99185029Spjd printf("%s: attempt to free NULL\n", __func__); 100184698Srodrigc return; 101184698Srodrigc } 102168404Spjd struct kmem_item *i; 103168404Spjd 104168404Spjd buf = (u_char *)buf - sizeof(struct kmem_item); 105168404Spjd mtx_lock(&kmem_items_mtx); 106168404Spjd LIST_FOREACH(i, &kmem_items, next) { 107168404Spjd if (i == buf) 108168404Spjd break; 109168404Spjd } 110168404Spjd ASSERT(i != NULL); 111168404Spjd LIST_REMOVE(i, next); 112168404Spjd mtx_unlock(&kmem_items_mtx); 113168404Spjd#endif 114168404Spjd free(buf, M_SOLARIS); 115168404Spjd} 116168404Spjd 117213528Savgstatic uint64_t kmem_size_val; 118213528Savg 119213528Savgstatic void 120213528Savgkmem_size_init(void *unused __unused) 121213528Savg{ 122213528Savg 123213528Savg kmem_size_val = (uint64_t)cnt.v_page_count * PAGE_SIZE; 124213528Savg if (kmem_size_val > vm_kmem_size) 125213528Savg kmem_size_val = vm_kmem_size; 126213528Savg} 127213528SavgSYSINIT(kmem_size_init, SI_SUB_KMEM, SI_ORDER_ANY, kmem_size_init, NULL); 128213528Savg 129175632Spjduint64_t 130168566Spjdkmem_size(void) 131168566Spjd{ 132168566Spjd 133213528Savg return (kmem_size_val); 134168566Spjd} 135168566Spjd 136175632Spjduint64_t 137168566Spjdkmem_used(void) 138168566Spjd{ 139168566Spjd 140254025Sjeff return (vmem_size(kmem_arena, VMEM_ALLOC)); 141168566Spjd} 142168566Spjd 143168404Spjdstatic int 144168404Spjdkmem_std_constructor(void *mem, int size __unused, void *private, int flags) 145168404Spjd{ 146168404Spjd struct kmem_cache *cache = private; 147168404Spjd 148168404Spjd return (cache->kc_constructor(mem, cache->kc_private, flags)); 149168404Spjd} 150168404Spjd 151168404Spjdstatic void 152168404Spjdkmem_std_destructor(void *mem, int size __unused, void *private) 153168404Spjd{ 154168404Spjd struct kmem_cache *cache = private; 155168404Spjd 156168404Spjd cache->kc_destructor(mem, cache->kc_private); 157168404Spjd} 158168404Spjd 159168404Spjdkmem_cache_t * 160168404Spjdkmem_cache_create(char *name, size_t bufsize, size_t align, 161168404Spjd int (*constructor)(void *, void *, int), void (*destructor)(void *, void *), 162168404Spjd void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags) 163168404Spjd{ 164168404Spjd kmem_cache_t *cache; 165168404Spjd 166168404Spjd ASSERT(vmp == NULL); 167168404Spjd 168168404Spjd cache = kmem_alloc(sizeof(*cache), KM_SLEEP); 169168404Spjd strlcpy(cache->kc_name, name, sizeof(cache->kc_name)); 170168404Spjd cache->kc_constructor = constructor; 171168404Spjd cache->kc_destructor = destructor; 172168404Spjd cache->kc_private = private; 173185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG) 174168404Spjd cache->kc_zone = uma_zcreate(cache->kc_name, bufsize, 175168404Spjd constructor != NULL ? kmem_std_constructor : NULL, 176168404Spjd destructor != NULL ? kmem_std_destructor : NULL, 177168404Spjd NULL, NULL, align > 0 ? align - 1 : 0, cflags); 178168404Spjd#else 179168404Spjd cache->kc_size = bufsize; 180168404Spjd#endif 181168404Spjd 182168404Spjd return (cache); 183168404Spjd} 184168404Spjd 185168404Spjdvoid 186168404Spjdkmem_cache_destroy(kmem_cache_t *cache) 187168404Spjd{ 188185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG) 189168404Spjd uma_zdestroy(cache->kc_zone); 190185029Spjd#endif 191168404Spjd kmem_free(cache, sizeof(*cache)); 192168404Spjd} 193168404Spjd 194168404Spjdvoid * 195168404Spjdkmem_cache_alloc(kmem_cache_t *cache, int flags) 196168404Spjd{ 197185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG) 198168404Spjd return (uma_zalloc_arg(cache->kc_zone, cache, flags)); 199168404Spjd#else 200168404Spjd void *p; 201168404Spjd 202168404Spjd p = kmem_alloc(cache->kc_size, flags); 203185029Spjd if (p != NULL && cache->kc_constructor != NULL) 204185029Spjd kmem_std_constructor(p, cache->kc_size, cache, flags); 205168404Spjd return (p); 206168404Spjd#endif 207168404Spjd} 208168404Spjd 209168404Spjdvoid 210168404Spjdkmem_cache_free(kmem_cache_t *cache, void *buf) 211168404Spjd{ 212185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG) 213168404Spjd uma_zfree_arg(cache->kc_zone, buf, cache); 214168404Spjd#else 215185029Spjd if (cache->kc_destructor != NULL) 216185029Spjd kmem_std_destructor(buf, cache->kc_size, cache); 217168404Spjd kmem_free(buf, cache->kc_size); 218168404Spjd#endif 219168404Spjd} 220168404Spjd 221168404Spjd#ifdef _KERNEL 222168404Spjdvoid 223168404Spjdkmem_cache_reap_now(kmem_cache_t *cache) 224168404Spjd{ 225185029Spjd#ifndef KMEM_DEBUG 226168404Spjd zone_drain(cache->kc_zone); 227185029Spjd#endif 228168404Spjd} 229168404Spjd 230168404Spjdvoid 231168404Spjdkmem_reap(void) 232168404Spjd{ 233168404Spjd uma_reclaim(); 234168404Spjd} 235168404Spjd#else 236168404Spjdvoid 237168404Spjdkmem_cache_reap_now(kmem_cache_t *cache __unused) 238168404Spjd{ 239168404Spjd} 240168404Spjd 241168404Spjdvoid 242168404Spjdkmem_reap(void) 243168404Spjd{ 244168404Spjd} 245168404Spjd#endif 246168404Spjd 247168404Spjdint 248168404Spjdkmem_debugging(void) 249168404Spjd{ 250168404Spjd return (0); 251168404Spjd} 252168404Spjd 253168404Spjdvoid * 254168404Spjdcalloc(size_t n, size_t s) 255168404Spjd{ 256168404Spjd return (kmem_zalloc(n * s, KM_NOSLEEP)); 257168404Spjd} 258168404Spjd 259168404Spjd#ifdef KMEM_DEBUG 260184698Srodrigcvoid kmem_show(void *); 261184698Srodrigcvoid 262168404Spjdkmem_show(void *dummy __unused) 263168404Spjd{ 264168404Spjd struct kmem_item *i; 265168404Spjd 266168404Spjd mtx_lock(&kmem_items_mtx); 267168404Spjd if (LIST_EMPTY(&kmem_items)) 268168404Spjd printf("KMEM_DEBUG: No leaked elements.\n"); 269168404Spjd else { 270168404Spjd printf("KMEM_DEBUG: Leaked elements:\n\n"); 271168404Spjd LIST_FOREACH(i, &kmem_items, next) { 272168404Spjd printf("address=%p\n", i); 273185029Spjd stack_print_ddb(&i->stack); 274185029Spjd printf("\n"); 275168404Spjd } 276168404Spjd } 277168404Spjd mtx_unlock(&kmem_items_mtx); 278168404Spjd} 279168404Spjd 280184698SrodrigcSYSUNINIT(sol_kmem, SI_SUB_CPU, SI_ORDER_FIRST, kmem_show, NULL); 281168404Spjd#endif /* KMEM_DEBUG */ 282