1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy  * Copyright (c) 2006-2007 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3eda14cbcSMatt Macy  * All rights reserved.
4eda14cbcSMatt Macy  *
5eda14cbcSMatt Macy  * Redistribution and use in source and binary forms, with or without
6eda14cbcSMatt Macy  * modification, are permitted provided that the following conditions
7eda14cbcSMatt Macy  * are met:
8eda14cbcSMatt Macy  * 1. Redistributions of source code must retain the above copyright
9eda14cbcSMatt Macy  *    notice, this list of conditions and the following disclaimer.
10eda14cbcSMatt Macy  * 2. Redistributions in binary form must reproduce the above copyright
11eda14cbcSMatt Macy  *    notice, this list of conditions and the following disclaimer in the
12eda14cbcSMatt Macy  *    documentation and/or other materials provided with the distribution.
13eda14cbcSMatt Macy  *
14eda14cbcSMatt Macy  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15eda14cbcSMatt Macy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16eda14cbcSMatt Macy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17eda14cbcSMatt Macy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18eda14cbcSMatt Macy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19eda14cbcSMatt Macy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20eda14cbcSMatt Macy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21eda14cbcSMatt Macy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22eda14cbcSMatt Macy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23eda14cbcSMatt Macy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24eda14cbcSMatt Macy  * SUCH DAMAGE.
25eda14cbcSMatt Macy  */
26eda14cbcSMatt Macy 
27eda14cbcSMatt Macy #include <sys/types.h>
28eda14cbcSMatt Macy #include <sys/param.h>
29eda14cbcSMatt Macy #include <sys/byteorder.h>
30eda14cbcSMatt Macy #include <sys/kernel.h>
31eda14cbcSMatt Macy #include <sys/systm.h>
32eda14cbcSMatt Macy #include <sys/malloc.h>
33eda14cbcSMatt Macy #include <sys/kmem.h>
34eda14cbcSMatt Macy #include <sys/kmem_cache.h>
35eda14cbcSMatt Macy #include <sys/debug.h>
36eda14cbcSMatt Macy #include <sys/mutex.h>
37eda14cbcSMatt Macy #include <sys/vmmeter.h>
38eda14cbcSMatt Macy 
39eda14cbcSMatt Macy 
40eda14cbcSMatt Macy #include <vm/vm_page.h>
41eda14cbcSMatt Macy #include <vm/vm_object.h>
42eda14cbcSMatt Macy #include <vm/vm_kern.h>
43eda14cbcSMatt Macy #include <vm/vm_map.h>
44eda14cbcSMatt Macy 
45eda14cbcSMatt Macy #ifdef KMEM_DEBUG
46eda14cbcSMatt Macy #include <sys/queue.h>
47eda14cbcSMatt Macy #include <sys/stack.h>
48eda14cbcSMatt Macy #endif
49eda14cbcSMatt Macy 
50eda14cbcSMatt Macy #ifdef _KERNEL
51eda14cbcSMatt Macy MALLOC_DEFINE(M_SOLARIS, "solaris", "Solaris");
52eda14cbcSMatt Macy #else
53eda14cbcSMatt Macy #define	malloc(size, type, flags)	malloc(size)
54eda14cbcSMatt Macy #define	free(addr, type)		free(addr)
55eda14cbcSMatt Macy #endif
56eda14cbcSMatt Macy 
57eda14cbcSMatt Macy #ifdef KMEM_DEBUG
58eda14cbcSMatt Macy struct kmem_item {
59eda14cbcSMatt Macy 	struct stack	stack;
60eda14cbcSMatt Macy 	LIST_ENTRY(kmem_item) next;
61eda14cbcSMatt Macy };
62eda14cbcSMatt Macy static LIST_HEAD(, kmem_item) kmem_items;
63eda14cbcSMatt Macy static struct mtx kmem_items_mtx;
64eda14cbcSMatt Macy MTX_SYSINIT(kmem_items_mtx, &kmem_items_mtx, "kmem_items", MTX_DEF);
65eda14cbcSMatt Macy #endif	/* KMEM_DEBUG */
66eda14cbcSMatt Macy 
67eda14cbcSMatt Macy #include <sys/vmem.h>
68eda14cbcSMatt Macy 
69eda14cbcSMatt Macy void *
zfs_kmem_alloc(size_t size,int kmflags)70eda14cbcSMatt Macy zfs_kmem_alloc(size_t size, int kmflags)
71eda14cbcSMatt Macy {
72eda14cbcSMatt Macy 	void *p;
73eda14cbcSMatt Macy #ifdef KMEM_DEBUG
74eda14cbcSMatt Macy 	struct kmem_item *i;
75eda14cbcSMatt Macy 
76eda14cbcSMatt Macy 	size += sizeof (struct kmem_item);
77eda14cbcSMatt Macy #endif
78eda14cbcSMatt Macy 	p = malloc(MAX(size, 16), M_SOLARIS, kmflags);
79eda14cbcSMatt Macy #ifndef _KERNEL
80eda14cbcSMatt Macy 	if (kmflags & KM_SLEEP)
81eda14cbcSMatt Macy 		assert(p != NULL);
82eda14cbcSMatt Macy #endif
83eda14cbcSMatt Macy #ifdef KMEM_DEBUG
84eda14cbcSMatt Macy 	if (p != NULL) {
85eda14cbcSMatt Macy 		i = p;
86eda14cbcSMatt Macy 		p = (uint8_t *)p + sizeof (struct kmem_item);
87eda14cbcSMatt Macy 		stack_save(&i->stack);
88eda14cbcSMatt Macy 		mtx_lock(&kmem_items_mtx);
89eda14cbcSMatt Macy 		LIST_INSERT_HEAD(&kmem_items, i, next);
90eda14cbcSMatt Macy 		mtx_unlock(&kmem_items_mtx);
91eda14cbcSMatt Macy 	}
92eda14cbcSMatt Macy #endif
93eda14cbcSMatt Macy 	return (p);
94eda14cbcSMatt Macy }
95eda14cbcSMatt Macy 
96eda14cbcSMatt Macy void
zfs_kmem_free(void * buf,size_t size __unused)97eda14cbcSMatt Macy zfs_kmem_free(void *buf, size_t size __unused)
98eda14cbcSMatt Macy {
99eda14cbcSMatt Macy #ifdef KMEM_DEBUG
100eda14cbcSMatt Macy 	if (buf == NULL) {
101eda14cbcSMatt Macy 		printf("%s: attempt to free NULL\n", __func__);
102eda14cbcSMatt Macy 		return;
103eda14cbcSMatt Macy 	}
104eda14cbcSMatt Macy 	struct kmem_item *i;
105eda14cbcSMatt Macy 
106eda14cbcSMatt Macy 	buf = (uint8_t *)buf - sizeof (struct kmem_item);
107eda14cbcSMatt Macy 	mtx_lock(&kmem_items_mtx);
108eda14cbcSMatt Macy 	LIST_FOREACH(i, &kmem_items, next) {
109eda14cbcSMatt Macy 		if (i == buf)
110eda14cbcSMatt Macy 			break;
111eda14cbcSMatt Macy 	}
11216038816SMartin Matuska 	ASSERT3P(i, !=, NULL);
113eda14cbcSMatt Macy 	LIST_REMOVE(i, next);
114eda14cbcSMatt Macy 	mtx_unlock(&kmem_items_mtx);
115eda14cbcSMatt Macy 	memset(buf, 0xDC, MAX(size, 16));
116eda14cbcSMatt Macy #endif
117eda14cbcSMatt Macy 	free(buf, M_SOLARIS);
118eda14cbcSMatt Macy }
119eda14cbcSMatt Macy 
120eda14cbcSMatt Macy static uint64_t kmem_size_val;
121eda14cbcSMatt Macy 
122eda14cbcSMatt Macy static void
kmem_size_init(void * unused __unused)123eda14cbcSMatt Macy kmem_size_init(void *unused __unused)
124eda14cbcSMatt Macy {
125eda14cbcSMatt Macy 
126eda14cbcSMatt Macy 	kmem_size_val = (uint64_t)vm_cnt.v_page_count * PAGE_SIZE;
127eda14cbcSMatt Macy 	if (kmem_size_val > vm_kmem_size)
128eda14cbcSMatt Macy 		kmem_size_val = vm_kmem_size;
129eda14cbcSMatt Macy }
130eda14cbcSMatt Macy SYSINIT(kmem_size_init, SI_SUB_KMEM, SI_ORDER_ANY, kmem_size_init, NULL);
131eda14cbcSMatt Macy 
132eda14cbcSMatt Macy uint64_t
kmem_size(void)133eda14cbcSMatt Macy kmem_size(void)
134eda14cbcSMatt Macy {
135eda14cbcSMatt Macy 
136eda14cbcSMatt Macy 	return (kmem_size_val);
137eda14cbcSMatt Macy }
138eda14cbcSMatt Macy 
139eda14cbcSMatt Macy static int
kmem_std_constructor(void * mem,int size __unused,void * private,int flags)140eda14cbcSMatt Macy kmem_std_constructor(void *mem, int size __unused, void *private, int flags)
141eda14cbcSMatt Macy {
142eda14cbcSMatt Macy 	struct kmem_cache *cache = private;
143eda14cbcSMatt Macy 
144eda14cbcSMatt Macy 	return (cache->kc_constructor(mem, cache->kc_private, flags));
145eda14cbcSMatt Macy }
146eda14cbcSMatt Macy 
147eda14cbcSMatt Macy static void
kmem_std_destructor(void * mem,int size __unused,void * private)148eda14cbcSMatt Macy kmem_std_destructor(void *mem, int size __unused, void *private)
149eda14cbcSMatt Macy {
150eda14cbcSMatt Macy 	struct kmem_cache *cache = private;
151eda14cbcSMatt Macy 
152eda14cbcSMatt Macy 	cache->kc_destructor(mem, cache->kc_private);
153eda14cbcSMatt Macy }
154eda14cbcSMatt Macy 
155eda14cbcSMatt Macy kmem_cache_t *
kmem_cache_create(const char * name,size_t bufsize,size_t align,int (* constructor)(void *,void *,int),void (* destructor)(void *,void *),void (* reclaim)(void *)__unused,void * private,vmem_t * vmp,int cflags)156*a0b956f5SMartin Matuska kmem_cache_create(const char *name, size_t bufsize, size_t align,
157eda14cbcSMatt Macy     int (*constructor)(void *, void *, int), void (*destructor)(void *, void *),
158eda14cbcSMatt Macy     void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags)
159eda14cbcSMatt Macy {
160eda14cbcSMatt Macy 	kmem_cache_t *cache;
161eda14cbcSMatt Macy 
16216038816SMartin Matuska 	ASSERT3P(vmp, ==, NULL);
163eda14cbcSMatt Macy 
164eda14cbcSMatt Macy 	cache = kmem_alloc(sizeof (*cache), KM_SLEEP);
165eda14cbcSMatt Macy 	strlcpy(cache->kc_name, name, sizeof (cache->kc_name));
166eda14cbcSMatt Macy 	cache->kc_constructor = constructor;
167eda14cbcSMatt Macy 	cache->kc_destructor = destructor;
168eda14cbcSMatt Macy 	cache->kc_private = private;
169eda14cbcSMatt Macy #if defined(_KERNEL) && !defined(KMEM_DEBUG)
170eda14cbcSMatt Macy 	cache->kc_zone = uma_zcreate(cache->kc_name, bufsize,
171eda14cbcSMatt Macy 	    constructor != NULL ? kmem_std_constructor : NULL,
172eda14cbcSMatt Macy 	    destructor != NULL ? kmem_std_destructor : NULL,
173eda14cbcSMatt Macy 	    NULL, NULL, align > 0 ? align - 1 : 0, cflags);
174eda14cbcSMatt Macy #else
175eda14cbcSMatt Macy 	cache->kc_size = bufsize;
176eda14cbcSMatt Macy #endif
177eda14cbcSMatt Macy 
178eda14cbcSMatt Macy 	return (cache);
179eda14cbcSMatt Macy }
180eda14cbcSMatt Macy 
181eda14cbcSMatt Macy void
kmem_cache_destroy(kmem_cache_t * cache)182eda14cbcSMatt Macy kmem_cache_destroy(kmem_cache_t *cache)
183eda14cbcSMatt Macy {
184eda14cbcSMatt Macy #if defined(_KERNEL) && !defined(KMEM_DEBUG)
185eda14cbcSMatt Macy 	uma_zdestroy(cache->kc_zone);
186eda14cbcSMatt Macy #endif
187eda14cbcSMatt Macy 	kmem_free(cache, sizeof (*cache));
188eda14cbcSMatt Macy }
189eda14cbcSMatt Macy 
190eda14cbcSMatt Macy void *
kmem_cache_alloc(kmem_cache_t * cache,int flags)191eda14cbcSMatt Macy kmem_cache_alloc(kmem_cache_t *cache, int flags)
192eda14cbcSMatt Macy {
193eda14cbcSMatt Macy #if defined(_KERNEL) && !defined(KMEM_DEBUG)
194eda14cbcSMatt Macy 	return (uma_zalloc_arg(cache->kc_zone, cache, flags));
195eda14cbcSMatt Macy #else
196eda14cbcSMatt Macy 	void *p;
197eda14cbcSMatt Macy 
198eda14cbcSMatt Macy 	p = kmem_alloc(cache->kc_size, flags);
199eda14cbcSMatt Macy 	if (p != NULL && cache->kc_constructor != NULL)
200eda14cbcSMatt Macy 		kmem_std_constructor(p, cache->kc_size, cache, flags);
201eda14cbcSMatt Macy 	return (p);
202eda14cbcSMatt Macy #endif
203eda14cbcSMatt Macy }
204eda14cbcSMatt Macy 
205eda14cbcSMatt Macy void
kmem_cache_free(kmem_cache_t * cache,void * buf)206eda14cbcSMatt Macy kmem_cache_free(kmem_cache_t *cache, void *buf)
207eda14cbcSMatt Macy {
208eda14cbcSMatt Macy #if defined(_KERNEL) && !defined(KMEM_DEBUG)
209eda14cbcSMatt Macy 	uma_zfree_arg(cache->kc_zone, buf, cache);
210eda14cbcSMatt Macy #else
211eda14cbcSMatt Macy 	if (cache->kc_destructor != NULL)
212eda14cbcSMatt Macy 		kmem_std_destructor(buf, cache->kc_size, cache);
213eda14cbcSMatt Macy 	kmem_free(buf, cache->kc_size);
214eda14cbcSMatt Macy #endif
215eda14cbcSMatt Macy }
216eda14cbcSMatt Macy 
217eda14cbcSMatt Macy /*
218eda14cbcSMatt Macy  * Allow our caller to determine if there are running reaps.
219eda14cbcSMatt Macy  *
220eda14cbcSMatt Macy  * This call is very conservative and may return B_TRUE even when
221eda14cbcSMatt Macy  * reaping activity isn't active. If it returns B_FALSE, then reaping
222eda14cbcSMatt Macy  * activity is definitely inactive.
223eda14cbcSMatt Macy  */
224eda14cbcSMatt Macy boolean_t
kmem_cache_reap_active(void)225eda14cbcSMatt Macy kmem_cache_reap_active(void)
226eda14cbcSMatt Macy {
227eda14cbcSMatt Macy 
228eda14cbcSMatt Macy 	return (B_FALSE);
229eda14cbcSMatt Macy }
230eda14cbcSMatt Macy 
231eda14cbcSMatt Macy /*
232eda14cbcSMatt Macy  * Reap (almost) everything soon.
233eda14cbcSMatt Macy  *
234eda14cbcSMatt Macy  * Note: this does not wait for the reap-tasks to complete. Caller
235eda14cbcSMatt Macy  * should use kmem_cache_reap_active() (above) and/or moderation to
236eda14cbcSMatt Macy  * avoid scheduling too many reap-tasks.
237eda14cbcSMatt Macy  */
238eda14cbcSMatt Macy #ifdef _KERNEL
239eda14cbcSMatt Macy void
kmem_cache_reap_soon(kmem_cache_t * cache)240eda14cbcSMatt Macy kmem_cache_reap_soon(kmem_cache_t *cache)
241eda14cbcSMatt Macy {
242eda14cbcSMatt Macy #ifndef KMEM_DEBUG
243eda14cbcSMatt Macy #if __FreeBSD_version >= 1300043
244eda14cbcSMatt Macy 	uma_zone_reclaim(cache->kc_zone, UMA_RECLAIM_DRAIN);
245eda14cbcSMatt Macy #else
246eda14cbcSMatt Macy 	zone_drain(cache->kc_zone);
247eda14cbcSMatt Macy #endif
248eda14cbcSMatt Macy #endif
249eda14cbcSMatt Macy }
250eda14cbcSMatt Macy 
251eda14cbcSMatt Macy void
kmem_reap(void)252eda14cbcSMatt Macy kmem_reap(void)
253eda14cbcSMatt Macy {
254eda14cbcSMatt Macy #if __FreeBSD_version >= 1300043
255eda14cbcSMatt Macy 	uma_reclaim(UMA_RECLAIM_TRIM);
256eda14cbcSMatt Macy #else
257eda14cbcSMatt Macy 	uma_reclaim();
258eda14cbcSMatt Macy #endif
259eda14cbcSMatt Macy }
260eda14cbcSMatt Macy #else
261eda14cbcSMatt Macy void
kmem_cache_reap_soon(kmem_cache_t * cache __unused)262eda14cbcSMatt Macy kmem_cache_reap_soon(kmem_cache_t *cache __unused)
263eda14cbcSMatt Macy {
264eda14cbcSMatt Macy }
265eda14cbcSMatt Macy 
266eda14cbcSMatt Macy void
kmem_reap(void)267eda14cbcSMatt Macy kmem_reap(void)
268eda14cbcSMatt Macy {
269eda14cbcSMatt Macy }
270eda14cbcSMatt Macy #endif
271eda14cbcSMatt Macy 
272eda14cbcSMatt Macy int
kmem_debugging(void)273eda14cbcSMatt Macy kmem_debugging(void)
274eda14cbcSMatt Macy {
275eda14cbcSMatt Macy 	return (0);
276eda14cbcSMatt Macy }
277eda14cbcSMatt Macy 
278eda14cbcSMatt Macy void *
calloc(size_t n,size_t s)279eda14cbcSMatt Macy calloc(size_t n, size_t s)
280eda14cbcSMatt Macy {
281eda14cbcSMatt Macy 	return (kmem_zalloc(n * s, KM_NOSLEEP));
282eda14cbcSMatt Macy }
283eda14cbcSMatt Macy 
284eda14cbcSMatt Macy char *
kmem_vasprintf(const char * fmt,va_list adx)285eda14cbcSMatt Macy kmem_vasprintf(const char *fmt, va_list adx)
286eda14cbcSMatt Macy {
287eda14cbcSMatt Macy 	char *msg;
288eda14cbcSMatt Macy 	va_list adx2;
289eda14cbcSMatt Macy 
290eda14cbcSMatt Macy 	va_copy(adx2, adx);
291eda14cbcSMatt Macy 	msg = kmem_alloc(vsnprintf(NULL, 0, fmt, adx) + 1, KM_SLEEP);
292eda14cbcSMatt Macy 	(void) vsprintf(msg, fmt, adx2);
293eda14cbcSMatt Macy 	va_end(adx2);
294eda14cbcSMatt Macy 
295eda14cbcSMatt Macy 	return (msg);
296eda14cbcSMatt Macy }
297eda14cbcSMatt Macy 
298eda14cbcSMatt Macy #include <vm/uma.h>
299eda14cbcSMatt Macy #include <vm/uma_int.h>
300eda14cbcSMatt Macy #ifdef KMEM_DEBUG
301eda14cbcSMatt Macy #error "KMEM_DEBUG not currently supported"
302eda14cbcSMatt Macy #endif
303eda14cbcSMatt Macy 
304eda14cbcSMatt Macy uint64_t
spl_kmem_cache_inuse(kmem_cache_t * cache)305eda14cbcSMatt Macy spl_kmem_cache_inuse(kmem_cache_t *cache)
306eda14cbcSMatt Macy {
307eda14cbcSMatt Macy 	return (uma_zone_get_cur(cache->kc_zone));
308eda14cbcSMatt Macy }
309eda14cbcSMatt Macy 
310eda14cbcSMatt Macy uint64_t
spl_kmem_cache_entry_size(kmem_cache_t * cache)311eda14cbcSMatt Macy spl_kmem_cache_entry_size(kmem_cache_t *cache)
312eda14cbcSMatt Macy {
313eda14cbcSMatt Macy 	return (cache->kc_zone->uz_size);
314eda14cbcSMatt Macy }
315eda14cbcSMatt Macy 
316eda14cbcSMatt Macy /*
317eda14cbcSMatt Macy  * Register a move callback for cache defragmentation.
318eda14cbcSMatt Macy  * XXX: Unimplemented but harmless to stub out for now.
319eda14cbcSMatt Macy  */
320eda14cbcSMatt Macy void
spl_kmem_cache_set_move(kmem_cache_t * skc,kmem_cbrc_t (move)(void *,void *,size_t,void *))321eda14cbcSMatt Macy spl_kmem_cache_set_move(kmem_cache_t *skc,
322eda14cbcSMatt Macy     kmem_cbrc_t (move)(void *, void *, size_t, void *))
323eda14cbcSMatt Macy {
32416038816SMartin Matuska 	ASSERT3P(move, !=, NULL);
325eda14cbcSMatt Macy }
326eda14cbcSMatt Macy 
327eda14cbcSMatt Macy #ifdef KMEM_DEBUG
328eda14cbcSMatt Macy void kmem_show(void *);
329eda14cbcSMatt Macy void
kmem_show(void * dummy __unused)330eda14cbcSMatt Macy kmem_show(void *dummy __unused)
331eda14cbcSMatt Macy {
332eda14cbcSMatt Macy 	struct kmem_item *i;
333eda14cbcSMatt Macy 
334eda14cbcSMatt Macy 	mtx_lock(&kmem_items_mtx);
335eda14cbcSMatt Macy 	if (LIST_EMPTY(&kmem_items))
336eda14cbcSMatt Macy 		printf("KMEM_DEBUG: No leaked elements.\n");
337eda14cbcSMatt Macy 	else {
338eda14cbcSMatt Macy 		printf("KMEM_DEBUG: Leaked elements:\n\n");
339eda14cbcSMatt Macy 		LIST_FOREACH(i, &kmem_items, next) {
340eda14cbcSMatt Macy 			printf("address=%p\n", i);
341eda14cbcSMatt Macy 			stack_print_ddb(&i->stack);
342eda14cbcSMatt Macy 			printf("\n");
343eda14cbcSMatt Macy 		}
344eda14cbcSMatt Macy 	}
345eda14cbcSMatt Macy 	mtx_unlock(&kmem_items_mtx);
346eda14cbcSMatt Macy }
347eda14cbcSMatt Macy 
348eda14cbcSMatt Macy SYSUNINIT(sol_kmem, SI_SUB_CPU, SI_ORDER_FIRST, kmem_show, NULL);
349eda14cbcSMatt Macy #endif	/* KMEM_DEBUG */
350