opensolaris_kmem.c revision 168566
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: head/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c 168566 2007-04-10 02:35:57Z pjd $");
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
49168404Spjdstatic MALLOC_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
65168404Spjdvoid *
66168404Spjdzfs_kmem_alloc(size_t size, int kmflags)
67168404Spjd{
68168404Spjd	void *p;
69168404Spjd#ifdef KMEM_DEBUG
70168404Spjd	struct kmem_item *i;
71168404Spjd
72168404Spjd	size += sizeof(struct kmem_item);
73168404Spjd#endif
74168404Spjd	p = malloc(size, M_SOLARIS, kmflags);
75168404Spjd#ifndef _KERNEL
76168404Spjd	if (kmflags & KM_SLEEP)
77168404Spjd		assert(p != NULL);
78168404Spjd#endif
79168404Spjd#ifdef KMEM_DEBUG
80168404Spjd	if (p != NULL) {
81168404Spjd		i = p;
82168404Spjd		p = (u_char *)p + sizeof(struct kmem_item);
83168404Spjd		stack_save(&i->stack);
84168404Spjd		mtx_lock(&kmem_items_mtx);
85168404Spjd		LIST_INSERT_HEAD(&kmem_items, i, next);
86168404Spjd		mtx_unlock(&kmem_items_mtx);
87168404Spjd	}
88168404Spjd#endif
89168404Spjd	return (p);
90168404Spjd}
91168404Spjd
92168404Spjdvoid
93168404Spjdzfs_kmem_free(void *buf, size_t size __unused)
94168404Spjd{
95168404Spjd#ifdef KMEM_DEBUG
96168404Spjd	struct kmem_item *i;
97168404Spjd
98168404Spjd	buf = (u_char *)buf - sizeof(struct kmem_item);
99168404Spjd	mtx_lock(&kmem_items_mtx);
100168404Spjd	LIST_FOREACH(i, &kmem_items, next) {
101168404Spjd		if (i == buf)
102168404Spjd			break;
103168404Spjd	}
104168404Spjd	ASSERT(i != NULL);
105168404Spjd	LIST_REMOVE(i, next);
106168404Spjd	mtx_unlock(&kmem_items_mtx);
107168404Spjd#endif
108168404Spjd	free(buf, M_SOLARIS);
109168404Spjd}
110168404Spjd
111168566Spjdu_long
112168566Spjdkmem_size(void)
113168566Spjd{
114168566Spjd
115168566Spjd	return ((u_long)vm_kmem_size);
116168566Spjd}
117168566Spjd
118168566Spjdu_long
119168566Spjdkmem_used(void)
120168566Spjd{
121168566Spjd
122168566Spjd	return ((u_long)kmem_map->size);
123168566Spjd}
124168566Spjd
125168404Spjdstatic int
126168404Spjdkmem_std_constructor(void *mem, int size __unused, void *private, int flags)
127168404Spjd{
128168404Spjd	struct kmem_cache *cache = private;
129168404Spjd
130168404Spjd	return (cache->kc_constructor(mem, cache->kc_private, flags));
131168404Spjd}
132168404Spjd
133168404Spjdstatic void
134168404Spjdkmem_std_destructor(void *mem, int size __unused, void *private)
135168404Spjd{
136168404Spjd	struct kmem_cache *cache = private;
137168404Spjd
138168404Spjd	cache->kc_destructor(mem, cache->kc_private);
139168404Spjd}
140168404Spjd
141168404Spjdkmem_cache_t *
142168404Spjdkmem_cache_create(char *name, size_t bufsize, size_t align,
143168404Spjd    int (*constructor)(void *, void *, int), void (*destructor)(void *, void *),
144168404Spjd    void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags)
145168404Spjd{
146168404Spjd	kmem_cache_t *cache;
147168404Spjd
148168404Spjd	ASSERT(vmp == NULL);
149168404Spjd
150168404Spjd	cache = kmem_alloc(sizeof(*cache), KM_SLEEP);
151168404Spjd	strlcpy(cache->kc_name, name, sizeof(cache->kc_name));
152168404Spjd	cache->kc_constructor = constructor;
153168404Spjd	cache->kc_destructor = destructor;
154168404Spjd	cache->kc_private = private;
155168404Spjd#ifdef _KERNEL
156168404Spjd	cache->kc_zone = uma_zcreate(cache->kc_name, bufsize,
157168404Spjd	    constructor != NULL ? kmem_std_constructor : NULL,
158168404Spjd	    destructor != NULL ? kmem_std_destructor : NULL,
159168404Spjd	    NULL, NULL, align > 0 ? align - 1 : 0, cflags);
160168404Spjd#else
161168404Spjd	cache->kc_size = bufsize;
162168404Spjd#endif
163168404Spjd
164168404Spjd	return (cache);
165168404Spjd}
166168404Spjd
167168404Spjdvoid
168168404Spjdkmem_cache_destroy(kmem_cache_t *cache)
169168404Spjd{
170168404Spjd	uma_zdestroy(cache->kc_zone);
171168404Spjd	kmem_free(cache, sizeof(*cache));
172168404Spjd}
173168404Spjd
174168404Spjdvoid *
175168404Spjdkmem_cache_alloc(kmem_cache_t *cache, int flags)
176168404Spjd{
177168404Spjd#ifdef _KERNEL
178168404Spjd	return (uma_zalloc_arg(cache->kc_zone, cache, flags));
179168404Spjd#else
180168404Spjd	void *p;
181168404Spjd
182168404Spjd	p = kmem_alloc(cache->kc_size, flags);
183168404Spjd	if (p != NULL) {
184168404Spjd		kmem_std_constructor(p, cache->kc_size, cache->kc_private,
185168404Spjd		    flags);
186168404Spjd	}
187168404Spjd	return (p);
188168404Spjd#endif
189168404Spjd}
190168404Spjd
191168404Spjdvoid
192168404Spjdkmem_cache_free(kmem_cache_t *cache, void *buf)
193168404Spjd{
194168404Spjd#ifdef _KERNEL
195168404Spjd	uma_zfree_arg(cache->kc_zone, buf, cache);
196168404Spjd#else
197168404Spjd	kmem_std_destructor(buf, cache->kc_size, cache->kc_private);
198168404Spjd	kmem_free(buf, cache->kc_size);
199168404Spjd#endif
200168404Spjd}
201168404Spjd
202168404Spjd#ifdef _KERNEL
203168404Spjdextern void zone_drain(uma_zone_t zone);
204168404Spjdvoid
205168404Spjdkmem_cache_reap_now(kmem_cache_t *cache)
206168404Spjd{
207168404Spjd	zone_drain(cache->kc_zone);
208168404Spjd}
209168404Spjd
210168404Spjdvoid
211168404Spjdkmem_reap(void)
212168404Spjd{
213168404Spjd	uma_reclaim();
214168404Spjd}
215168404Spjd#else
216168404Spjdvoid
217168404Spjdkmem_cache_reap_now(kmem_cache_t *cache __unused)
218168404Spjd{
219168404Spjd}
220168404Spjd
221168404Spjdvoid
222168404Spjdkmem_reap(void)
223168404Spjd{
224168404Spjd}
225168404Spjd#endif
226168404Spjd
227168404Spjdint
228168404Spjdkmem_debugging(void)
229168404Spjd{
230168404Spjd	return (0);
231168404Spjd}
232168404Spjd
233168404Spjdvoid *
234168404Spjdcalloc(size_t n, size_t s)
235168404Spjd{
236168404Spjd	return (kmem_zalloc(n * s, KM_NOSLEEP));
237168404Spjd}
238168404Spjd
239168404Spjd#ifdef KMEM_DEBUG
240168404Spjdstatic void
241168404Spjdkmem_show(void *dummy __unused)
242168404Spjd{
243168404Spjd	struct kmem_item *i;
244168404Spjd
245168404Spjd	mtx_lock(&kmem_items_mtx);
246168404Spjd	if (LIST_EMPTY(&kmem_items))
247168404Spjd		printf("KMEM_DEBUG: No leaked elements.\n");
248168404Spjd	else {
249168404Spjd		printf("KMEM_DEBUG: Leaked elements:\n\n");
250168404Spjd		LIST_FOREACH(i, &kmem_items, next) {
251168404Spjd			printf("address=%p\n", i);
252168404Spjd			stack_print(&i->stack);
253168404Spjd			printf("\n");
254168404Spjd		}
255168404Spjd	}
256168404Spjd	mtx_unlock(&kmem_items_mtx);
257168404Spjd}
258168404Spjd
259168404SpjdSYSUNINIT(sol_kmem, SI_SUB_DRIVERS, SI_ORDER_FIRST, kmem_show, NULL);
260168404Spjd#endif	/* KMEM_DEBUG */
261