opensolaris_kmem.c revision 179293
1/*- 2 * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c 179293 2008-05-24 19:30:38Z bz $"); 29 30#include <sys/param.h> 31#include <sys/kernel.h> 32#include <sys/systm.h> 33#include <sys/malloc.h> 34#include <sys/kmem.h> 35#include <sys/debug.h> 36#include <sys/mutex.h> 37 38#include <vm/vm_page.h> 39#include <vm/vm_object.h> 40#include <vm/vm_kern.h> 41#include <vm/vm_map.h> 42 43#ifdef KMEM_DEBUG 44#include <sys/queue.h> 45#include <sys/stack.h> 46#endif 47 48#ifdef _KERNEL 49static MALLOC_DEFINE(M_SOLARIS, "solaris", "Solaris"); 50#else 51#define malloc(size, type, flags) malloc(size) 52#define free(addr, type) free(addr) 53#endif 54 55#ifdef KMEM_DEBUG 56struct kmem_item { 57 struct stack stack; 58 LIST_ENTRY(kmem_item) next; 59}; 60static LIST_HEAD(, kmem_item) kmem_items; 61static struct mtx kmem_items_mtx; 62MTX_SYSINIT(kmem_items_mtx, &kmem_items_mtx, "kmem_items", MTX_DEF); 63#endif /* KMEM_DEBUG */ 64 65void * 66zfs_kmem_alloc(size_t size, int kmflags) 67{ 68 void *p; 69#ifdef KMEM_DEBUG 70 struct kmem_item *i; 71 72 size += sizeof(struct kmem_item); 73#endif 74 p = malloc(size, M_SOLARIS, kmflags); 75#ifndef _KERNEL 76 if (kmflags & KM_SLEEP) 77 assert(p != NULL); 78#endif 79#ifdef KMEM_DEBUG 80 if (p != NULL) { 81 i = p; 82 p = (u_char *)p + sizeof(struct kmem_item); 83 stack_save(&i->stack); 84 mtx_lock(&kmem_items_mtx); 85 LIST_INSERT_HEAD(&kmem_items, i, next); 86 mtx_unlock(&kmem_items_mtx); 87 } 88#endif 89 return (p); 90} 91 92void 93zfs_kmem_free(void *buf, size_t size __unused) 94{ 95#ifdef KMEM_DEBUG 96 struct kmem_item *i; 97 98 buf = (u_char *)buf - sizeof(struct kmem_item); 99 mtx_lock(&kmem_items_mtx); 100 LIST_FOREACH(i, &kmem_items, next) { 101 if (i == buf) 102 break; 103 } 104 ASSERT(i != NULL); 105 LIST_REMOVE(i, next); 106 mtx_unlock(&kmem_items_mtx); 107#endif 108 free(buf, M_SOLARIS); 109} 110 111uint64_t 112kmem_size(void) 113{ 114 115 return ((uint64_t)vm_kmem_size); 116} 117 118uint64_t 119kmem_used(void) 120{ 121 122 return ((uint64_t)kmem_map->size); 123} 124 125static int 126kmem_std_constructor(void *mem, int size __unused, void *private, int flags) 127{ 128 struct kmem_cache *cache = private; 129 130 return (cache->kc_constructor(mem, cache->kc_private, flags)); 131} 132 133static void 134kmem_std_destructor(void *mem, int size __unused, void *private) 135{ 136 struct kmem_cache *cache = private; 137 138 cache->kc_destructor(mem, cache->kc_private); 139} 140 141kmem_cache_t * 142kmem_cache_create(char *name, size_t bufsize, size_t align, 143 int (*constructor)(void *, void *, int), void (*destructor)(void *, void *), 144 void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags) 145{ 146 kmem_cache_t *cache; 147 148 ASSERT(vmp == NULL); 149 150 cache = kmem_alloc(sizeof(*cache), KM_SLEEP); 151 strlcpy(cache->kc_name, name, sizeof(cache->kc_name)); 152 cache->kc_constructor = constructor; 153 cache->kc_destructor = destructor; 154 cache->kc_private = private; 155#ifdef _KERNEL 156 cache->kc_zone = uma_zcreate(cache->kc_name, bufsize, 157 constructor != NULL ? kmem_std_constructor : NULL, 158 destructor != NULL ? kmem_std_destructor : NULL, 159 NULL, NULL, align > 0 ? align - 1 : 0, cflags); 160#else 161 cache->kc_size = bufsize; 162#endif 163 164 return (cache); 165} 166 167void 168kmem_cache_destroy(kmem_cache_t *cache) 169{ 170 uma_zdestroy(cache->kc_zone); 171 kmem_free(cache, sizeof(*cache)); 172} 173 174void * 175kmem_cache_alloc(kmem_cache_t *cache, int flags) 176{ 177#ifdef _KERNEL 178 return (uma_zalloc_arg(cache->kc_zone, cache, flags)); 179#else 180 void *p; 181 182 p = kmem_alloc(cache->kc_size, flags); 183 if (p != NULL) { 184 kmem_std_constructor(p, cache->kc_size, cache->kc_private, 185 flags); 186 } 187 return (p); 188#endif 189} 190 191void 192kmem_cache_free(kmem_cache_t *cache, void *buf) 193{ 194#ifdef _KERNEL 195 uma_zfree_arg(cache->kc_zone, buf, cache); 196#else 197 kmem_std_destructor(buf, cache->kc_size, cache->kc_private); 198 kmem_free(buf, cache->kc_size); 199#endif 200} 201 202#ifdef _KERNEL 203void 204kmem_cache_reap_now(kmem_cache_t *cache) 205{ 206 zone_drain(cache->kc_zone); 207} 208 209void 210kmem_reap(void) 211{ 212 uma_reclaim(); 213} 214#else 215void 216kmem_cache_reap_now(kmem_cache_t *cache __unused) 217{ 218} 219 220void 221kmem_reap(void) 222{ 223} 224#endif 225 226int 227kmem_debugging(void) 228{ 229 return (0); 230} 231 232void * 233calloc(size_t n, size_t s) 234{ 235 return (kmem_zalloc(n * s, KM_NOSLEEP)); 236} 237 238#ifdef KMEM_DEBUG 239static void 240kmem_show(void *dummy __unused) 241{ 242 struct kmem_item *i; 243 244 mtx_lock(&kmem_items_mtx); 245 if (LIST_EMPTY(&kmem_items)) 246 printf("KMEM_DEBUG: No leaked elements.\n"); 247 else { 248 printf("KMEM_DEBUG: Leaked elements:\n\n"); 249 LIST_FOREACH(i, &kmem_items, next) { 250 printf("address=%p\n", i); 251 stack_print(&i->stack); 252 printf("\n"); 253 } 254 } 255 mtx_unlock(&kmem_items_mtx); 256} 257 258SYSUNINIT(sol_kmem, SI_SUB_DRIVERS, SI_ORDER_FIRST, kmem_show, NULL); 259#endif /* KMEM_DEBUG */ 260