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$");
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
49219089SpjdMALLOC_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
65254025Sjeff#include <sys/vmem.h>
66254025Sjeff
67168404Spjdvoid *
68168404Spjdzfs_kmem_alloc(size_t size, int kmflags)
69168404Spjd{
70168404Spjd	void *p;
71168404Spjd#ifdef KMEM_DEBUG
72168404Spjd	struct kmem_item *i;
73168404Spjd
74168404Spjd	size += sizeof(struct kmem_item);
75168404Spjd#endif
76168404Spjd	p = malloc(size, M_SOLARIS, kmflags);
77168404Spjd#ifndef _KERNEL
78168404Spjd	if (kmflags & KM_SLEEP)
79168404Spjd		assert(p != NULL);
80168404Spjd#endif
81168404Spjd#ifdef KMEM_DEBUG
82168404Spjd	if (p != NULL) {
83168404Spjd		i = p;
84168404Spjd		p = (u_char *)p + sizeof(struct kmem_item);
85168404Spjd		stack_save(&i->stack);
86168404Spjd		mtx_lock(&kmem_items_mtx);
87168404Spjd		LIST_INSERT_HEAD(&kmem_items, i, next);
88168404Spjd		mtx_unlock(&kmem_items_mtx);
89168404Spjd	}
90168404Spjd#endif
91168404Spjd	return (p);
92168404Spjd}
93168404Spjd
94168404Spjdvoid
95168404Spjdzfs_kmem_free(void *buf, size_t size __unused)
96168404Spjd{
97168404Spjd#ifdef KMEM_DEBUG
98184698Srodrigc	if (buf == NULL) {
99185029Spjd		printf("%s: attempt to free NULL\n", __func__);
100184698Srodrigc		return;
101184698Srodrigc	}
102168404Spjd	struct kmem_item *i;
103168404Spjd
104168404Spjd	buf = (u_char *)buf - sizeof(struct kmem_item);
105168404Spjd	mtx_lock(&kmem_items_mtx);
106168404Spjd	LIST_FOREACH(i, &kmem_items, next) {
107168404Spjd		if (i == buf)
108168404Spjd			break;
109168404Spjd	}
110168404Spjd	ASSERT(i != NULL);
111168404Spjd	LIST_REMOVE(i, next);
112168404Spjd	mtx_unlock(&kmem_items_mtx);
113168404Spjd#endif
114168404Spjd	free(buf, M_SOLARIS);
115168404Spjd}
116168404Spjd
117213528Savgstatic uint64_t kmem_size_val;
118213528Savg
119213528Savgstatic void
120213528Savgkmem_size_init(void *unused __unused)
121213528Savg{
122213528Savg
123213528Savg	kmem_size_val = (uint64_t)cnt.v_page_count * PAGE_SIZE;
124213528Savg	if (kmem_size_val > vm_kmem_size)
125213528Savg		kmem_size_val = vm_kmem_size;
126213528Savg}
127213528SavgSYSINIT(kmem_size_init, SI_SUB_KMEM, SI_ORDER_ANY, kmem_size_init, NULL);
128213528Savg
129175632Spjduint64_t
130168566Spjdkmem_size(void)
131168566Spjd{
132168566Spjd
133213528Savg	return (kmem_size_val);
134168566Spjd}
135168566Spjd
136175632Spjduint64_t
137168566Spjdkmem_used(void)
138168566Spjd{
139168566Spjd
140254025Sjeff	return (vmem_size(kmem_arena, VMEM_ALLOC));
141168566Spjd}
142168566Spjd
143168404Spjdstatic int
144168404Spjdkmem_std_constructor(void *mem, int size __unused, void *private, int flags)
145168404Spjd{
146168404Spjd	struct kmem_cache *cache = private;
147168404Spjd
148168404Spjd	return (cache->kc_constructor(mem, cache->kc_private, flags));
149168404Spjd}
150168404Spjd
151168404Spjdstatic void
152168404Spjdkmem_std_destructor(void *mem, int size __unused, void *private)
153168404Spjd{
154168404Spjd	struct kmem_cache *cache = private;
155168404Spjd
156168404Spjd	cache->kc_destructor(mem, cache->kc_private);
157168404Spjd}
158168404Spjd
159168404Spjdkmem_cache_t *
160168404Spjdkmem_cache_create(char *name, size_t bufsize, size_t align,
161168404Spjd    int (*constructor)(void *, void *, int), void (*destructor)(void *, void *),
162168404Spjd    void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags)
163168404Spjd{
164168404Spjd	kmem_cache_t *cache;
165168404Spjd
166168404Spjd	ASSERT(vmp == NULL);
167168404Spjd
168168404Spjd	cache = kmem_alloc(sizeof(*cache), KM_SLEEP);
169168404Spjd	strlcpy(cache->kc_name, name, sizeof(cache->kc_name));
170168404Spjd	cache->kc_constructor = constructor;
171168404Spjd	cache->kc_destructor = destructor;
172168404Spjd	cache->kc_private = private;
173185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG)
174168404Spjd	cache->kc_zone = uma_zcreate(cache->kc_name, bufsize,
175168404Spjd	    constructor != NULL ? kmem_std_constructor : NULL,
176168404Spjd	    destructor != NULL ? kmem_std_destructor : NULL,
177168404Spjd	    NULL, NULL, align > 0 ? align - 1 : 0, cflags);
178168404Spjd#else
179168404Spjd	cache->kc_size = bufsize;
180168404Spjd#endif
181168404Spjd
182168404Spjd	return (cache);
183168404Spjd}
184168404Spjd
185168404Spjdvoid
186168404Spjdkmem_cache_destroy(kmem_cache_t *cache)
187168404Spjd{
188185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG)
189168404Spjd	uma_zdestroy(cache->kc_zone);
190185029Spjd#endif
191168404Spjd	kmem_free(cache, sizeof(*cache));
192168404Spjd}
193168404Spjd
194168404Spjdvoid *
195168404Spjdkmem_cache_alloc(kmem_cache_t *cache, int flags)
196168404Spjd{
197185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG)
198168404Spjd	return (uma_zalloc_arg(cache->kc_zone, cache, flags));
199168404Spjd#else
200168404Spjd	void *p;
201168404Spjd
202168404Spjd	p = kmem_alloc(cache->kc_size, flags);
203185029Spjd	if (p != NULL && cache->kc_constructor != NULL)
204185029Spjd		kmem_std_constructor(p, cache->kc_size, cache, flags);
205168404Spjd	return (p);
206168404Spjd#endif
207168404Spjd}
208168404Spjd
209168404Spjdvoid
210168404Spjdkmem_cache_free(kmem_cache_t *cache, void *buf)
211168404Spjd{
212185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG)
213168404Spjd	uma_zfree_arg(cache->kc_zone, buf, cache);
214168404Spjd#else
215185029Spjd	if (cache->kc_destructor != NULL)
216185029Spjd		kmem_std_destructor(buf, cache->kc_size, cache);
217168404Spjd	kmem_free(buf, cache->kc_size);
218168404Spjd#endif
219168404Spjd}
220168404Spjd
221168404Spjd#ifdef _KERNEL
222168404Spjdvoid
223168404Spjdkmem_cache_reap_now(kmem_cache_t *cache)
224168404Spjd{
225185029Spjd#ifndef KMEM_DEBUG
226168404Spjd	zone_drain(cache->kc_zone);
227185029Spjd#endif
228168404Spjd}
229168404Spjd
230168404Spjdvoid
231168404Spjdkmem_reap(void)
232168404Spjd{
233168404Spjd	uma_reclaim();
234168404Spjd}
235168404Spjd#else
236168404Spjdvoid
237168404Spjdkmem_cache_reap_now(kmem_cache_t *cache __unused)
238168404Spjd{
239168404Spjd}
240168404Spjd
241168404Spjdvoid
242168404Spjdkmem_reap(void)
243168404Spjd{
244168404Spjd}
245168404Spjd#endif
246168404Spjd
247168404Spjdint
248168404Spjdkmem_debugging(void)
249168404Spjd{
250168404Spjd	return (0);
251168404Spjd}
252168404Spjd
253168404Spjdvoid *
254168404Spjdcalloc(size_t n, size_t s)
255168404Spjd{
256168404Spjd	return (kmem_zalloc(n * s, KM_NOSLEEP));
257168404Spjd}
258168404Spjd
259168404Spjd#ifdef KMEM_DEBUG
260184698Srodrigcvoid kmem_show(void *);
261184698Srodrigcvoid
262168404Spjdkmem_show(void *dummy __unused)
263168404Spjd{
264168404Spjd	struct kmem_item *i;
265168404Spjd
266168404Spjd	mtx_lock(&kmem_items_mtx);
267168404Spjd	if (LIST_EMPTY(&kmem_items))
268168404Spjd		printf("KMEM_DEBUG: No leaked elements.\n");
269168404Spjd	else {
270168404Spjd		printf("KMEM_DEBUG: Leaked elements:\n\n");
271168404Spjd		LIST_FOREACH(i, &kmem_items, next) {
272168404Spjd			printf("address=%p\n", i);
273185029Spjd			stack_print_ddb(&i->stack);
274185029Spjd			printf("\n");
275168404Spjd		}
276168404Spjd	}
277168404Spjd	mtx_unlock(&kmem_items_mtx);
278168404Spjd}
279168404Spjd
280184698SrodrigcSYSUNINIT(sol_kmem, SI_SUB_CPU, SI_ORDER_FIRST, kmem_show, NULL);
281168404Spjd#endif	/* KMEM_DEBUG */
282