1 | /* $NetBSD: slab.h,v 1.5 2015/03/02 02:26:37 riastradh Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2013 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Taylor R. Campbell. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #ifndef _LINUX_SLAB_H_ |
33 | #define _LINUX_SLAB_H_ |
34 | |
35 | #include <sys/kmem.h> |
36 | #include <sys/malloc.h> |
37 | |
38 | #include <machine/limits.h> |
39 | |
40 | #include <uvm/uvm_extern.h> /* For PAGE_SIZE. */ |
41 | |
42 | #include <linux/gfp.h> |
43 | |
44 | /* XXX Should use kmem, but Linux kfree doesn't take the size. */ |
45 | |
46 | static inline int |
47 | linux_gfp_to_malloc(gfp_t gfp) |
48 | { |
49 | int flags = 0; |
50 | |
51 | /* This has no meaning to us. */ |
52 | gfp &= ~__GFP_NOWARN; |
53 | gfp &= ~__GFP_RECLAIMABLE; |
54 | |
55 | /* Pretend this was the same as not passing __GFP_WAIT. */ |
56 | if (ISSET(gfp, __GFP_NORETRY)) { |
57 | gfp &= ~__GFP_NORETRY; |
58 | gfp &= ~__GFP_WAIT; |
59 | } |
60 | |
61 | if (ISSET(gfp, __GFP_ZERO)) { |
62 | flags |= M_ZERO; |
63 | gfp &= ~__GFP_ZERO; |
64 | } |
65 | |
66 | /* |
67 | * XXX Handle other cases as they arise -- prefer to fail early |
68 | * rather than allocate memory without respecting parameters we |
69 | * don't understand. |
70 | */ |
71 | KASSERT((gfp == GFP_ATOMIC) || |
72 | ((gfp & ~__GFP_WAIT) == (GFP_KERNEL & ~__GFP_WAIT))); |
73 | |
74 | if (ISSET(gfp, __GFP_WAIT)) { |
75 | flags |= M_WAITOK; |
76 | gfp &= ~__GFP_WAIT; |
77 | } else { |
78 | flags |= M_NOWAIT; |
79 | } |
80 | |
81 | return flags; |
82 | } |
83 | |
84 | static inline void * |
85 | kmalloc(size_t size, gfp_t gfp) |
86 | { |
87 | return malloc(size, M_TEMP, linux_gfp_to_malloc(gfp)); |
88 | } |
89 | |
90 | static inline void * |
91 | kzalloc(size_t size, gfp_t gfp) |
92 | { |
93 | return malloc(size, M_TEMP, (linux_gfp_to_malloc(gfp) | M_ZERO)); |
94 | } |
95 | |
96 | static inline void * |
97 | kmalloc_array(size_t n, size_t size, gfp_t gfp) |
98 | { |
99 | if ((size != 0) && (n > (SIZE_MAX / size))) |
100 | return NULL; |
101 | return malloc((n * size), M_TEMP, linux_gfp_to_malloc(gfp)); |
102 | } |
103 | |
104 | static inline void * |
105 | kcalloc(size_t n, size_t size, gfp_t gfp) |
106 | { |
107 | return kmalloc_array(n, size, (gfp | __GFP_ZERO)); |
108 | } |
109 | |
110 | static inline void * |
111 | krealloc(void *ptr, size_t size, gfp_t gfp) |
112 | { |
113 | return realloc(ptr, size, M_TEMP, linux_gfp_to_malloc(gfp)); |
114 | } |
115 | |
116 | static inline void |
117 | kfree(void *ptr) |
118 | { |
119 | if (ptr != NULL) |
120 | free(ptr, M_TEMP); |
121 | } |
122 | |
123 | #define SLAB_HWCACHE_ALIGN 1 |
124 | |
125 | struct kmem_cache { |
126 | pool_cache_t kc_pool_cache; |
127 | size_t kc_size; |
128 | void (*kc_ctor)(void *); |
129 | }; |
130 | |
131 | static int |
132 | kmem_cache_ctor(void *cookie, void *ptr, int flags __unused) |
133 | { |
134 | struct kmem_cache *const kc = cookie; |
135 | |
136 | if (kc->kc_ctor) |
137 | (*kc->kc_ctor)(ptr); |
138 | |
139 | return 0; |
140 | } |
141 | |
142 | static inline struct kmem_cache * |
143 | kmem_cache_create(const char *name, size_t size, size_t align, |
144 | unsigned long flags, void (*ctor)(void *)) |
145 | { |
146 | struct kmem_cache *kc; |
147 | |
148 | if (ISSET(flags, SLAB_HWCACHE_ALIGN)) |
149 | align = roundup(MAX(1, align), CACHE_LINE_SIZE); |
150 | |
151 | kc = kmem_alloc(sizeof(*kc), KM_SLEEP); |
152 | kc->kc_pool_cache = pool_cache_init(size, align, 0, 0, name, NULL, |
153 | IPL_NONE, &kmem_cache_ctor, NULL, kc); |
154 | kc->kc_size = size; |
155 | kc->kc_ctor = ctor; |
156 | |
157 | return kc; |
158 | } |
159 | |
160 | static inline void |
161 | kmem_cache_destroy(struct kmem_cache *kc) |
162 | { |
163 | |
164 | pool_cache_destroy(kc->kc_pool_cache); |
165 | kmem_free(kc, sizeof(*kc)); |
166 | } |
167 | |
168 | static inline void * |
169 | kmem_cache_alloc(struct kmem_cache *kc, gfp_t gfp) |
170 | { |
171 | int flags = 0; |
172 | void *ptr; |
173 | |
174 | if (gfp & __GFP_WAIT) |
175 | flags |= PR_NOWAIT; |
176 | else |
177 | flags |= PR_WAITOK; |
178 | |
179 | ptr = pool_cache_get(kc->kc_pool_cache, flags); |
180 | if (ptr == NULL) |
181 | return NULL; |
182 | |
183 | if (ISSET(gfp, __GFP_ZERO)) |
184 | (void)memset(ptr, 0, kc->kc_size); |
185 | |
186 | return ptr; |
187 | } |
188 | |
189 | static inline void * |
190 | kmem_cache_zalloc(struct kmem_cache *kc, gfp_t gfp) |
191 | { |
192 | |
193 | return kmem_cache_alloc(kc, (gfp | __GFP_ZERO)); |
194 | } |
195 | |
196 | static inline void |
197 | kmem_cache_free(struct kmem_cache *kc, void *ptr) |
198 | { |
199 | |
200 | pool_cache_put(kc->kc_pool_cache, ptr); |
201 | } |
202 | |
203 | #endif /* _LINUX_SLAB_H_ */ |
204 | |