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
136168404Spjdstatic int
137168404Spjdkmem_std_constructor(void *mem, int size __unused, void *private, int flags)
138168404Spjd{
139168404Spjd	struct kmem_cache *cache = private;
140168404Spjd
141168404Spjd	return (cache->kc_constructor(mem, cache->kc_private, flags));
142168404Spjd}
143168404Spjd
144168404Spjdstatic void
145168404Spjdkmem_std_destructor(void *mem, int size __unused, void *private)
146168404Spjd{
147168404Spjd	struct kmem_cache *cache = private;
148168404Spjd
149168404Spjd	cache->kc_destructor(mem, cache->kc_private);
150168404Spjd}
151168404Spjd
152168404Spjdkmem_cache_t *
153168404Spjdkmem_cache_create(char *name, size_t bufsize, size_t align,
154168404Spjd    int (*constructor)(void *, void *, int), void (*destructor)(void *, void *),
155168404Spjd    void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int cflags)
156168404Spjd{
157168404Spjd	kmem_cache_t *cache;
158168404Spjd
159168404Spjd	ASSERT(vmp == NULL);
160168404Spjd
161168404Spjd	cache = kmem_alloc(sizeof(*cache), KM_SLEEP);
162168404Spjd	strlcpy(cache->kc_name, name, sizeof(cache->kc_name));
163168404Spjd	cache->kc_constructor = constructor;
164168404Spjd	cache->kc_destructor = destructor;
165168404Spjd	cache->kc_private = private;
166185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG)
167168404Spjd	cache->kc_zone = uma_zcreate(cache->kc_name, bufsize,
168168404Spjd	    constructor != NULL ? kmem_std_constructor : NULL,
169168404Spjd	    destructor != NULL ? kmem_std_destructor : NULL,
170168404Spjd	    NULL, NULL, align > 0 ? align - 1 : 0, cflags);
171168404Spjd#else
172168404Spjd	cache->kc_size = bufsize;
173168404Spjd#endif
174168404Spjd
175168404Spjd	return (cache);
176168404Spjd}
177168404Spjd
178168404Spjdvoid
179168404Spjdkmem_cache_destroy(kmem_cache_t *cache)
180168404Spjd{
181185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG)
182168404Spjd	uma_zdestroy(cache->kc_zone);
183185029Spjd#endif
184168404Spjd	kmem_free(cache, sizeof(*cache));
185168404Spjd}
186168404Spjd
187168404Spjdvoid *
188168404Spjdkmem_cache_alloc(kmem_cache_t *cache, int flags)
189168404Spjd{
190185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG)
191168404Spjd	return (uma_zalloc_arg(cache->kc_zone, cache, flags));
192168404Spjd#else
193168404Spjd	void *p;
194168404Spjd
195168404Spjd	p = kmem_alloc(cache->kc_size, flags);
196185029Spjd	if (p != NULL && cache->kc_constructor != NULL)
197185029Spjd		kmem_std_constructor(p, cache->kc_size, cache, flags);
198168404Spjd	return (p);
199168404Spjd#endif
200168404Spjd}
201168404Spjd
202168404Spjdvoid
203168404Spjdkmem_cache_free(kmem_cache_t *cache, void *buf)
204168404Spjd{
205185029Spjd#if defined(_KERNEL) && !defined(KMEM_DEBUG)
206168404Spjd	uma_zfree_arg(cache->kc_zone, buf, cache);
207168404Spjd#else
208185029Spjd	if (cache->kc_destructor != NULL)
209185029Spjd		kmem_std_destructor(buf, cache->kc_size, cache);
210168404Spjd	kmem_free(buf, cache->kc_size);
211168404Spjd#endif
212168404Spjd}
213168404Spjd
214168404Spjd#ifdef _KERNEL
215168404Spjdvoid
216168404Spjdkmem_cache_reap_now(kmem_cache_t *cache)
217168404Spjd{
218185029Spjd#ifndef KMEM_DEBUG
219168404Spjd	zone_drain(cache->kc_zone);
220185029Spjd#endif
221168404Spjd}
222168404Spjd
223168404Spjdvoid
224168404Spjdkmem_reap(void)
225168404Spjd{
226168404Spjd	uma_reclaim();
227168404Spjd}
228168404Spjd#else
229168404Spjdvoid
230168404Spjdkmem_cache_reap_now(kmem_cache_t *cache __unused)
231168404Spjd{
232168404Spjd}
233168404Spjd
234168404Spjdvoid
235168404Spjdkmem_reap(void)
236168404Spjd{
237168404Spjd}
238168404Spjd#endif
239168404Spjd
240168404Spjdint
241168404Spjdkmem_debugging(void)
242168404Spjd{
243168404Spjd	return (0);
244168404Spjd}
245168404Spjd
246168404Spjdvoid *
247168404Spjdcalloc(size_t n, size_t s)
248168404Spjd{
249168404Spjd	return (kmem_zalloc(n * s, KM_NOSLEEP));
250168404Spjd}
251168404Spjd
252168404Spjd#ifdef KMEM_DEBUG
253184698Srodrigcvoid kmem_show(void *);
254184698Srodrigcvoid
255168404Spjdkmem_show(void *dummy __unused)
256168404Spjd{
257168404Spjd	struct kmem_item *i;
258168404Spjd
259168404Spjd	mtx_lock(&kmem_items_mtx);
260168404Spjd	if (LIST_EMPTY(&kmem_items))
261168404Spjd		printf("KMEM_DEBUG: No leaked elements.\n");
262168404Spjd	else {
263168404Spjd		printf("KMEM_DEBUG: Leaked elements:\n\n");
264168404Spjd		LIST_FOREACH(i, &kmem_items, next) {
265168404Spjd			printf("address=%p\n", i);
266185029Spjd			stack_print_ddb(&i->stack);
267185029Spjd			printf("\n");
268168404Spjd		}
269168404Spjd	}
270168404Spjd	mtx_unlock(&kmem_items_mtx);
271168404Spjd}
272168404Spjd
273184698SrodrigcSYSUNINIT(sol_kmem, SI_SUB_CPU, SI_ORDER_FIRST, kmem_show, NULL);
274168404Spjd#endif	/* KMEM_DEBUG */
275