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 136168404Spjdstatic int 137168404Spjdkmem_std_constructor(void *mem, int size __unused, void *private, int flags) 138168404Spjd{ 139168404Spjd struct kmem_cache *cache = private; 140168404Spjd 141168404Spjd return (cache->kc_constructor(mem, cache->kc_private, flags)); 142168404Spjd} 143168404Spjd 144168404Spjdstatic void 145168404Spjdkmem_std_destructor(void *mem, int size __unused, void *private) 146168404Spjd{ 147168404Spjd struct kmem_cache *cache = private; 148168404Spjd 149168404Spjd cache->kc_destructor(mem, cache->kc_private); 150168404Spjd} 151168404Spjd 152168404Spjdkmem_cache_t * 153168404Spjdkmem_cache_create(char *name, size_t bufsize, size_t align, 154168404Spjd int (*constructor)(void *, void *, int), void (*destructor)(void *, void *), 155168404Spjd void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags) 156168404Spjd{ 157168404Spjd kmem_cache_t *cache; 158168404Spjd 159168404Spjd ASSERT(vmp == NULL); 160168404Spjd 161168404Spjd cache = kmem_alloc(sizeof(*cache), KM_SLEEP); 162168404Spjd strlcpy(cache->kc_name, name, sizeof(cache->kc_name)); 163168404Spjd cache->kc_constructor = constructor; 164168404Spjd cache->kc_destructor = destructor; 165168404Spjd cache->kc_private = private; 166185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG) 167168404Spjd cache->kc_zone = uma_zcreate(cache->kc_name, bufsize, 168168404Spjd constructor != NULL ? kmem_std_constructor : NULL, 169168404Spjd destructor != NULL ? kmem_std_destructor : NULL, 170168404Spjd NULL, NULL, align > 0 ? align - 1 : 0, cflags); 171168404Spjd#else 172168404Spjd cache->kc_size = bufsize; 173168404Spjd#endif 174168404Spjd 175168404Spjd return (cache); 176168404Spjd} 177168404Spjd 178168404Spjdvoid 179168404Spjdkmem_cache_destroy(kmem_cache_t *cache) 180168404Spjd{ 181185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG) 182168404Spjd uma_zdestroy(cache->kc_zone); 183185029Spjd#endif 184168404Spjd kmem_free(cache, sizeof(*cache)); 185168404Spjd} 186168404Spjd 187168404Spjdvoid * 188168404Spjdkmem_cache_alloc(kmem_cache_t *cache, int flags) 189168404Spjd{ 190185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG) 191168404Spjd return (uma_zalloc_arg(cache->kc_zone, cache, flags)); 192168404Spjd#else 193168404Spjd void *p; 194168404Spjd 195168404Spjd p = kmem_alloc(cache->kc_size, flags); 196185029Spjd if (p != NULL && cache->kc_constructor != NULL) 197185029Spjd kmem_std_constructor(p, cache->kc_size, cache, flags); 198168404Spjd return (p); 199168404Spjd#endif 200168404Spjd} 201168404Spjd 202168404Spjdvoid 203168404Spjdkmem_cache_free(kmem_cache_t *cache, void *buf) 204168404Spjd{ 205185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG) 206168404Spjd uma_zfree_arg(cache->kc_zone, buf, cache); 207168404Spjd#else 208185029Spjd if (cache->kc_destructor != NULL) 209185029Spjd kmem_std_destructor(buf, cache->kc_size, cache); 210168404Spjd kmem_free(buf, cache->kc_size); 211168404Spjd#endif 212168404Spjd} 213168404Spjd 214168404Spjd#ifdef _KERNEL 215168404Spjdvoid 216168404Spjdkmem_cache_reap_now(kmem_cache_t *cache) 217168404Spjd{ 218185029Spjd#ifndef KMEM_DEBUG 219168404Spjd zone_drain(cache->kc_zone); 220185029Spjd#endif 221168404Spjd} 222168404Spjd 223168404Spjdvoid 224168404Spjdkmem_reap(void) 225168404Spjd{ 226168404Spjd uma_reclaim(); 227168404Spjd} 228168404Spjd#else 229168404Spjdvoid 230168404Spjdkmem_cache_reap_now(kmem_cache_t *cache __unused) 231168404Spjd{ 232168404Spjd} 233168404Spjd 234168404Spjdvoid 235168404Spjdkmem_reap(void) 236168404Spjd{ 237168404Spjd} 238168404Spjd#endif 239168404Spjd 240168404Spjdint 241168404Spjdkmem_debugging(void) 242168404Spjd{ 243168404Spjd return (0); 244168404Spjd} 245168404Spjd 246168404Spjdvoid * 247168404Spjdcalloc(size_t n, size_t s) 248168404Spjd{ 249168404Spjd return (kmem_zalloc(n * s, KM_NOSLEEP)); 250168404Spjd} 251168404Spjd 252168404Spjd#ifdef KMEM_DEBUG 253184698Srodrigcvoid kmem_show(void *); 254184698Srodrigcvoid 255168404Spjdkmem_show(void *dummy __unused) 256168404Spjd{ 257168404Spjd struct kmem_item *i; 258168404Spjd 259168404Spjd mtx_lock(&kmem_items_mtx); 260168404Spjd if (LIST_EMPTY(&kmem_items)) 261168404Spjd printf("KMEM_DEBUG: No leaked elements.\n"); 262168404Spjd else { 263168404Spjd printf("KMEM_DEBUG: Leaked elements:\n\n"); 264168404Spjd LIST_FOREACH(i, &kmem_items, next) { 265168404Spjd printf("address=%p\n", i); 266185029Spjd stack_print_ddb(&i->stack); 267185029Spjd printf("\n"); 268168404Spjd } 269168404Spjd } 270168404Spjd mtx_unlock(&kmem_items_mtx); 271168404Spjd} 272168404Spjd 273184698SrodrigcSYSUNINIT(sol_kmem, SI_SUB_CPU, SI_ORDER_FIRST, kmem_show, NULL); 274168404Spjd#endif /* KMEM_DEBUG */ 275