opensolaris_kmem.c revision 254025
135388Smjacob/*- 235388Smjacob * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 335388Smjacob * All rights reserved. 435388Smjacob * 535388Smjacob * Redistribution and use in source and binary forms, with or without 635388Smjacob * modification, are permitted provided that the following conditions 735388Smjacob * are met: 835388Smjacob * 1. Redistributions of source code must retain the above copyright 935388Smjacob * notice, this list of conditions and the following disclaimer. 1035388Smjacob * 2. Redistributions in binary form must reproduce the above copyright 1135388Smjacob * notice, this list of conditions and the following disclaimer in the 1235388Smjacob * documentation and/or other materials provided with the distribution. 1335388Smjacob * 1435388Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1535388Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1635388Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1735388Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 1835388Smjacob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1935388Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2035388Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2135388Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2235388Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2335388Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2435388Smjacob * SUCH DAMAGE. 2535388Smjacob */ 2635388Smjacob 2735388Smjacob#include <sys/cdefs.h> 2835388Smjacob__FBSDID("$FreeBSD: head/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c 254025 2013-08-07 06:21:20Z jeff $"); 2935388Smjacob 3035388Smjacob#include <sys/param.h> 3135388Smjacob#include <sys/kernel.h> 3235388Smjacob#include <sys/systm.h> 3335388Smjacob#include <sys/malloc.h> 3435388Smjacob#include <sys/kmem.h> 3535388Smjacob#include <sys/debug.h> 3635388Smjacob#include <sys/mutex.h> 3735388Smjacob 3835388Smjacob#include <vm/vm_page.h> 3935388Smjacob#include <vm/vm_object.h> 4035388Smjacob#include <vm/vm_kern.h> 4135388Smjacob#include <vm/vm_map.h> 4235388Smjacob 4335388Smjacob#ifdef KMEM_DEBUG 4435388Smjacob#include <sys/queue.h> 4535388Smjacob#include <sys/stack.h> 4635388Smjacob#endif 4735388Smjacob 4835388Smjacob#ifdef _KERNEL 4935388SmjacobMALLOC_DEFINE(M_SOLARIS, "solaris", "Solaris"); 5035388Smjacob#else 5135388Smjacob#define malloc(size, type, flags) malloc(size) 5235388Smjacob#define free(addr, type) free(addr) 5335388Smjacob#endif 5435388Smjacob 5535388Smjacob#ifdef KMEM_DEBUG 5635388Smjacobstruct kmem_item { 5735388Smjacob struct stack stack; 5835388Smjacob LIST_ENTRY(kmem_item) next; 5935388Smjacob}; 6035388Smjacobstatic LIST_HEAD(, kmem_item) kmem_items; 6135388Smjacobstatic struct mtx kmem_items_mtx; 6235388SmjacobMTX_SYSINIT(kmem_items_mtx, &kmem_items_mtx, "kmem_items", MTX_DEF); 6335388Smjacob#endif /* KMEM_DEBUG */ 6435388Smjacob 6535388Smjacob#include <sys/vmem.h> 6635388Smjacob 6735388Smjacobvoid * 6835388Smjacobzfs_kmem_alloc(size_t size, int kmflags) 6935388Smjacob{ 7035388Smjacob void *p; 7135388Smjacob#ifdef KMEM_DEBUG 7235388Smjacob struct kmem_item *i; 7335388Smjacob 7435388Smjacob size += sizeof(struct kmem_item); 7535388Smjacob#endif 7635388Smjacob p = malloc(size, M_SOLARIS, kmflags); 7735388Smjacob#ifndef _KERNEL 7835388Smjacob if (kmflags & KM_SLEEP) 7935388Smjacob assert(p != NULL); 8035388Smjacob#endif 8135388Smjacob#ifdef KMEM_DEBUG 8235388Smjacob if (p != NULL) { 8335388Smjacob i = p; 8435388Smjacob p = (u_char *)p + sizeof(struct kmem_item); 8535388Smjacob stack_save(&i->stack); 8635388Smjacob mtx_lock(&kmem_items_mtx); 8735388Smjacob LIST_INSERT_HEAD(&kmem_items, i, next); 8835388Smjacob mtx_unlock(&kmem_items_mtx); 8935388Smjacob } 9035388Smjacob#endif 9135388Smjacob return (p); 9235388Smjacob} 9335388Smjacob 9435388Smjacobvoid 9535388Smjacobzfs_kmem_free(void *buf, size_t size __unused) 9635388Smjacob{ 9735388Smjacob#ifdef KMEM_DEBUG 9835388Smjacob if (buf == NULL) { 9935388Smjacob printf("%s: attempt to free NULL\n", __func__); 10035388Smjacob return; 10135388Smjacob } 10235388Smjacob struct kmem_item *i; 10335388Smjacob 10435388Smjacob buf = (u_char *)buf - sizeof(struct kmem_item); 10535388Smjacob mtx_lock(&kmem_items_mtx); 10635388Smjacob LIST_FOREACH(i, &kmem_items, next) { 10735388Smjacob if (i == buf) 10835388Smjacob break; 10935388Smjacob } 11035388Smjacob ASSERT(i != NULL); 11135388Smjacob LIST_REMOVE(i, next); 11235388Smjacob mtx_unlock(&kmem_items_mtx); 11335388Smjacob#endif 11435388Smjacob free(buf, M_SOLARIS); 11535388Smjacob} 11635388Smjacob 11735388Smjacobstatic uint64_t kmem_size_val; 11835388Smjacob 11935388Smjacobstatic void 12035388Smjacobkmem_size_init(void *unused __unused) 12135388Smjacob{ 12235388Smjacob 12335388Smjacob kmem_size_val = (uint64_t)cnt.v_page_count * PAGE_SIZE; 12435388Smjacob if (kmem_size_val > vm_kmem_size) 12535388Smjacob kmem_size_val = vm_kmem_size; 12635388Smjacob} 12735388SmjacobSYSINIT(kmem_size_init, SI_SUB_KMEM, SI_ORDER_ANY, kmem_size_init, NULL); 12835388Smjacob 12935388Smjacobuint64_t 13035388Smjacobkmem_size(void) 13135388Smjacob{ 13235388Smjacob 13335388Smjacob return (kmem_size_val); 13435388Smjacob} 13535388Smjacob 13635388Smjacobuint64_t 13735388Smjacobkmem_used(void) 13835388Smjacob{ 13935388Smjacob 14035388Smjacob return (vmem_size(kmem_arena, VMEM_ALLOC)); 14135388Smjacob} 14235388Smjacob 14335388Smjacobstatic int 14435388Smjacobkmem_std_constructor(void *mem, int size __unused, void *private, int flags) 14535388Smjacob{ 14635388Smjacob struct kmem_cache *cache = private; 14735388Smjacob 14835388Smjacob return (cache->kc_constructor(mem, cache->kc_private, flags)); 14935388Smjacob} 15035388Smjacob 15135388Smjacobstatic void 15235388Smjacobkmem_std_destructor(void *mem, int size __unused, void *private) 15335388Smjacob{ 15435388Smjacob struct kmem_cache *cache = private; 155 156 cache->kc_destructor(mem, cache->kc_private); 157} 158 159kmem_cache_t * 160kmem_cache_create(char *name, size_t bufsize, size_t align, 161 int (*constructor)(void *, void *, int), void (*destructor)(void *, void *), 162 void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags) 163{ 164 kmem_cache_t *cache; 165 166 ASSERT(vmp == NULL); 167 168 cache = kmem_alloc(sizeof(*cache), KM_SLEEP); 169 strlcpy(cache->kc_name, name, sizeof(cache->kc_name)); 170 cache->kc_constructor = constructor; 171 cache->kc_destructor = destructor; 172 cache->kc_private = private; 173#if defined(_KERNEL) && !defined(KMEM_DEBUG) 174 cache->kc_zone = uma_zcreate(cache->kc_name, bufsize, 175 constructor != NULL ? kmem_std_constructor : NULL, 176 destructor != NULL ? kmem_std_destructor : NULL, 177 NULL, NULL, align > 0 ? align - 1 : 0, cflags); 178#else 179 cache->kc_size = bufsize; 180#endif 181 182 return (cache); 183} 184 185void 186kmem_cache_destroy(kmem_cache_t *cache) 187{ 188#if defined(_KERNEL) && !defined(KMEM_DEBUG) 189 uma_zdestroy(cache->kc_zone); 190#endif 191 kmem_free(cache, sizeof(*cache)); 192} 193 194void * 195kmem_cache_alloc(kmem_cache_t *cache, int flags) 196{ 197#if defined(_KERNEL) && !defined(KMEM_DEBUG) 198 return (uma_zalloc_arg(cache->kc_zone, cache, flags)); 199#else 200 void *p; 201 202 p = kmem_alloc(cache->kc_size, flags); 203 if (p != NULL && cache->kc_constructor != NULL) 204 kmem_std_constructor(p, cache->kc_size, cache, flags); 205 return (p); 206#endif 207} 208 209void 210kmem_cache_free(kmem_cache_t *cache, void *buf) 211{ 212#if defined(_KERNEL) && !defined(KMEM_DEBUG) 213 uma_zfree_arg(cache->kc_zone, buf, cache); 214#else 215 if (cache->kc_destructor != NULL) 216 kmem_std_destructor(buf, cache->kc_size, cache); 217 kmem_free(buf, cache->kc_size); 218#endif 219} 220 221#ifdef _KERNEL 222void 223kmem_cache_reap_now(kmem_cache_t *cache) 224{ 225#ifndef KMEM_DEBUG 226 zone_drain(cache->kc_zone); 227#endif 228} 229 230void 231kmem_reap(void) 232{ 233 uma_reclaim(); 234} 235#else 236void 237kmem_cache_reap_now(kmem_cache_t *cache __unused) 238{ 239} 240 241void 242kmem_reap(void) 243{ 244} 245#endif 246 247int 248kmem_debugging(void) 249{ 250 return (0); 251} 252 253void * 254calloc(size_t n, size_t s) 255{ 256 return (kmem_zalloc(n * s, KM_NOSLEEP)); 257} 258 259#ifdef KMEM_DEBUG 260void kmem_show(void *); 261void 262kmem_show(void *dummy __unused) 263{ 264 struct kmem_item *i; 265 266 mtx_lock(&kmem_items_mtx); 267 if (LIST_EMPTY(&kmem_items)) 268 printf("KMEM_DEBUG: No leaked elements.\n"); 269 else { 270 printf("KMEM_DEBUG: Leaked elements:\n\n"); 271 LIST_FOREACH(i, &kmem_items, next) { 272 printf("address=%p\n", i); 273 stack_print_ddb(&i->stack); 274 printf("\n"); 275 } 276 } 277 mtx_unlock(&kmem_items_mtx); 278} 279 280SYSUNINIT(sol_kmem, SI_SUB_CPU, SI_ORDER_FIRST, kmem_show, NULL); 281#endif /* KMEM_DEBUG */ 282