opensolaris_kmem.c revision 175632
1191665Sbms/*-
2191665Sbms * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3191665Sbms * All rights reserved.
4191665Sbms *
5191665Sbms * Redistribution and use in source and binary forms, with or without
6191665Sbms * modification, are permitted provided that the following conditions
7191665Sbms * are met:
8191665Sbms * 1. Redistributions of source code must retain the above copyright
9191665Sbms *    notice, this list of conditions and the following disclaimer.
10191665Sbms * 2. Redistributions in binary form must reproduce the above copyright
11191665Sbms *    notice, this list of conditions and the following disclaimer in the
12191665Sbms *    documentation and/or other materials provided with the distribution.
13191665Sbms *
14191665Sbms * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15191665Sbms * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16191665Sbms * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17191665Sbms * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18191665Sbms * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19191665Sbms * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20191665Sbms * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21191665Sbms * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22191665Sbms * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23191665Sbms * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24191665Sbms * SUCH DAMAGE.
25191665Sbms */
26191665Sbms
27191665Sbms#include <sys/cdefs.h>
28191665Sbms__FBSDID("$FreeBSD: head/sys/cddl/compat/opensolaris/kern/opensolaris_kmem.c 175632 2008-01-24 11:21:54Z pjd $");
29191665Sbms
30191665Sbms#include <sys/param.h>
31191665Sbms#include <sys/kernel.h>
32191672Sbms#include <sys/systm.h>
33191665Sbms#include <sys/malloc.h>
34191665Sbms#include <sys/kmem.h>
35191665Sbms#include <sys/debug.h>
36191665Sbms#include <sys/mutex.h>
37191665Sbms
38191665Sbms#include <vm/vm_page.h>
39191665Sbms#include <vm/vm_object.h>
40191665Sbms#include <vm/vm_kern.h>
41191665Sbms#include <vm/vm_map.h>
42191665Sbms
43191665Sbms#ifdef KMEM_DEBUG
44191665Sbms#include <sys/queue.h>
45191665Sbms#include <sys/stack.h>
46191665Sbms#endif
47191665Sbms
48191665Sbms#ifdef _KERNEL
49191665Sbmsstatic MALLOC_DEFINE(M_SOLARIS, "solaris", "Solaris");
50191665Sbms#else
51191665Sbms#define	malloc(size, type, flags)	malloc(size)
52191665Sbms#define	free(addr, type)		free(addr)
53191665Sbms#endif
54191665Sbms
55191665Sbms#ifdef KMEM_DEBUG
56191665Sbmsstruct kmem_item {
57191665Sbms	struct stack	stack;
58191665Sbms	LIST_ENTRY(kmem_item) next;
59191665Sbms};
60191665Sbmsstatic LIST_HEAD(, kmem_item) kmem_items;
61191665Sbmsstatic struct mtx kmem_items_mtx;
62191665SbmsMTX_SYSINIT(kmem_items_mtx, &kmem_items_mtx, "kmem_items", MTX_DEF);
63191665Sbms#endif	/* KMEM_DEBUG */
64191665Sbms
65191665Sbmsvoid *
66191665Sbmszfs_kmem_alloc(size_t size, int kmflags)
67191665Sbms{
68191665Sbms	void *p;
69195699Srwatson#ifdef KMEM_DEBUG
70191665Sbms	struct kmem_item *i;
71191665Sbms
72191665Sbms	size += sizeof(struct kmem_item);
73191665Sbms#endif
74191665Sbms	p = malloc(size, M_SOLARIS, kmflags);
75191665Sbms#ifndef _KERNEL
76191665Sbms	if (kmflags & KM_SLEEP)
77191665Sbms		assert(p != NULL);
78191665Sbms#endif
79191665Sbms#ifdef KMEM_DEBUG
80191665Sbms	if (p != NULL) {
81191665Sbms		i = p;
82191665Sbms		p = (u_char *)p + sizeof(struct kmem_item);
83191665Sbms		stack_save(&i->stack);
84191665Sbms		mtx_lock(&kmem_items_mtx);
85191665Sbms		LIST_INSERT_HEAD(&kmem_items, i, next);
86191665Sbms		mtx_unlock(&kmem_items_mtx);
87191665Sbms	}
88191665Sbms#endif
89191665Sbms	return (p);
90191665Sbms}
91191665Sbms
92191665Sbmsvoid
93191665Sbmszfs_kmem_free(void *buf, size_t size __unused)
94191665Sbms{
95191665Sbms#ifdef KMEM_DEBUG
96191665Sbms	struct kmem_item *i;
97191665Sbms
98191665Sbms	buf = (u_char *)buf - sizeof(struct kmem_item);
99191665Sbms	mtx_lock(&kmem_items_mtx);
100191665Sbms	LIST_FOREACH(i, &kmem_items, next) {
101191665Sbms		if (i == buf)
102191665Sbms			break;
103191665Sbms	}
104191665Sbms	ASSERT(i != NULL);
105191665Sbms	LIST_REMOVE(i, next);
106191665Sbms	mtx_unlock(&kmem_items_mtx);
107191665Sbms#endif
108191665Sbms	free(buf, M_SOLARIS);
109191665Sbms}
110191665Sbms
111191665Sbmsuint64_t
112191665Sbmskmem_size(void)
113191665Sbms{
114191665Sbms
115191665Sbms	return ((uint64_t)vm_kmem_size);
116191665Sbms}
117191665Sbms
118191665Sbmsuint64_t
119191665Sbmskmem_used(void)
120191665Sbms{
121191665Sbms
122191665Sbms	return ((uint64_t)kmem_map->size);
123191665Sbms}
124191665Sbms
125191665Sbmsstatic int
126191665Sbmskmem_std_constructor(void *mem, int size __unused, void *private, int flags)
127191665Sbms{
128191665Sbms	struct kmem_cache *cache = private;
129191665Sbms
130191665Sbms	return (cache->kc_constructor(mem, cache->kc_private, flags));
131191665Sbms}
132191665Sbms
133191665Sbmsstatic void
134191665Sbmskmem_std_destructor(void *mem, int size __unused, void *private)
135191665Sbms{
136191665Sbms	struct kmem_cache *cache = private;
137191665Sbms
138191665Sbms	cache->kc_destructor(mem, cache->kc_private);
139191665Sbms}
140191665Sbms
141191665Sbmskmem_cache_t *
142191665Sbmskmem_cache_create(char *name, size_t bufsize, size_t align,
143191672Sbms    int (*constructor)(void *, void *, int), void (*destructor)(void *, void *),
144191672Sbms    void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags)
145191672Sbms{
146191665Sbms	kmem_cache_t *cache;
147191665Sbms
148191665Sbms	ASSERT(vmp == NULL);
149191665Sbms
150191665Sbms	cache = kmem_alloc(sizeof(*cache), KM_SLEEP);
151191665Sbms	strlcpy(cache->kc_name, name, sizeof(cache->kc_name));
152191665Sbms	cache->kc_constructor = constructor;
153227309Sed	cache->kc_destructor = destructor;
154227309Sed	cache->kc_private = private;
155191665Sbms#ifdef _KERNEL
156191665Sbms	cache->kc_zone = uma_zcreate(cache->kc_name, bufsize,
157191665Sbms	    constructor != NULL ? kmem_std_constructor : NULL,
158191665Sbms	    destructor != NULL ? kmem_std_destructor : NULL,
159191665Sbms	    NULL, NULL, align > 0 ? align - 1 : 0, cflags);
160191665Sbms#else
161191665Sbms	cache->kc_size = bufsize;
162191665Sbms#endif
163191665Sbms
164191665Sbms	return (cache);
165191665Sbms}
166191665Sbms
167191665Sbmsvoid
168191665Sbmskmem_cache_destroy(kmem_cache_t *cache)
169191665Sbms{
170191665Sbms	uma_zdestroy(cache->kc_zone);
171191665Sbms	kmem_free(cache, sizeof(*cache));
172191665Sbms}
173191665Sbms
174227309Sedvoid *
175191665Sbmskmem_cache_alloc(kmem_cache_t *cache, int flags)
176191665Sbms{
177191665Sbms#ifdef _KERNEL
178191665Sbms	return (uma_zalloc_arg(cache->kc_zone, cache, flags));
179191665Sbms#else
180191665Sbms	void *p;
181191665Sbms
182191665Sbms	p = kmem_alloc(cache->kc_size, flags);
183191665Sbms	if (p != NULL) {
184191665Sbms		kmem_std_constructor(p, cache->kc_size, cache->kc_private,
185191665Sbms		    flags);
186191665Sbms	}
187191665Sbms	return (p);
188191665Sbms#endif
189191665Sbms}
190191665Sbms
191191665Sbmsvoid
192191665Sbmskmem_cache_free(kmem_cache_t *cache, void *buf)
193191665Sbms{
194191665Sbms#ifdef _KERNEL
195191665Sbms	uma_zfree_arg(cache->kc_zone, buf, cache);
196191665Sbms#else
197191665Sbms	kmem_std_destructor(buf, cache->kc_size, cache->kc_private);
198191665Sbms	kmem_free(buf, cache->kc_size);
199191665Sbms#endif
200191665Sbms}
201191665Sbms
202191665Sbms#ifdef _KERNEL
203191665Sbmsextern void zone_drain(uma_zone_t zone);
204191665Sbmsvoid
205191665Sbmskmem_cache_reap_now(kmem_cache_t *cache)
206191665Sbms{
207191665Sbms	zone_drain(cache->kc_zone);
208191665Sbms}
209191665Sbms
210191665Sbmsvoid
211191665Sbmskmem_reap(void)
212191665Sbms{
213191665Sbms	uma_reclaim();
214191665Sbms}
215191665Sbms#else
216191665Sbmsvoid
217191665Sbmskmem_cache_reap_now(kmem_cache_t *cache __unused)
218191665Sbms{
219191665Sbms}
220191665Sbms
221191665Sbmsvoid
222191665Sbmskmem_reap(void)
223191665Sbms{
224191665Sbms}
225191665Sbms#endif
226191665Sbms
227191665Sbmsint
228191665Sbmskmem_debugging(void)
229191665Sbms{
230191665Sbms	return (0);
231191665Sbms}
232191665Sbms
233191665Sbmsvoid *
234191665Sbmscalloc(size_t n, size_t s)
235191665Sbms{
236191665Sbms	return (kmem_zalloc(n * s, KM_NOSLEEP));
237191665Sbms}
238191665Sbms
239191665Sbms#ifdef KMEM_DEBUG
240191665Sbmsstatic void
241191665Sbmskmem_show(void *dummy __unused)
242191665Sbms{
243191665Sbms	struct kmem_item *i;
244191665Sbms
245191665Sbms	mtx_lock(&kmem_items_mtx);
246191665Sbms	if (LIST_EMPTY(&kmem_items))
247191665Sbms		printf("KMEM_DEBUG: No leaked elements.\n");
248191665Sbms	else {
249191665Sbms		printf("KMEM_DEBUG: Leaked elements:\n\n");
250191665Sbms		LIST_FOREACH(i, &kmem_items, next) {
251191665Sbms			printf("address=%p\n", i);
252191665Sbms			stack_print(&i->stack);
253191665Sbms			printf("\n");
254191665Sbms		}
255191665Sbms	}
256191665Sbms	mtx_unlock(&kmem_items_mtx);
257191665Sbms}
258191665Sbms
259191665SbmsSYSUNINIT(sol_kmem, SI_SUB_DRIVERS, SI_ORDER_FIRST, kmem_show, NULL);
260191665Sbms#endif	/* KMEM_DEBUG */
261191665Sbms