diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2015-05-04 19:52:20 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-05-14 15:14:23 -0400 |
commit | c1a67fefd0546a5552289c65fe31b1d60e64b643 (patch) | |
tree | e96bfb877d770c45e4b7a58d251edf3808ae5d32 | |
parent | c854ab5773be1c1a0d3cef0c3a3261f2c48ab7f8 (diff) |
mempool: Add mempool_init()/mempool_exit()
Allows mempools to be embedded in other structs, getting rid of a
pointer indirection from allocation fastpaths.
mempool_exit() is safe to call on an uninitialized but zeroed mempool.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r-- | include/linux/mempool.h | 34 | ||||
-rw-r--r-- | mm/mempool.c | 108 |
2 files changed, 115 insertions, 27 deletions
diff --git a/include/linux/mempool.h b/include/linux/mempool.h index b51f5c430c26..0c964ac107c2 100644 --- a/include/linux/mempool.h +++ b/include/linux/mempool.h | |||
@@ -25,6 +25,18 @@ typedef struct mempool_s { | |||
25 | wait_queue_head_t wait; | 25 | wait_queue_head_t wait; |
26 | } mempool_t; | 26 | } mempool_t; |
27 | 27 | ||
28 | static inline bool mempool_initialized(mempool_t *pool) | ||
29 | { | ||
30 | return pool->elements != NULL; | ||
31 | } | ||
32 | |||
33 | void mempool_exit(mempool_t *pool); | ||
34 | int mempool_init_node(mempool_t *pool, int min_nr, mempool_alloc_t *alloc_fn, | ||
35 | mempool_free_t *free_fn, void *pool_data, | ||
36 | gfp_t gfp_mask, int node_id); | ||
37 | int mempool_init(mempool_t *pool, int min_nr, mempool_alloc_t *alloc_fn, | ||
38 | mempool_free_t *free_fn, void *pool_data); | ||
39 | |||
28 | extern mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, | 40 | extern mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, |
29 | mempool_free_t *free_fn, void *pool_data); | 41 | mempool_free_t *free_fn, void *pool_data); |
30 | extern mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn, | 42 | extern mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn, |
@@ -43,6 +55,14 @@ extern void mempool_free(void *element, mempool_t *pool); | |||
43 | */ | 55 | */ |
44 | void *mempool_alloc_slab(gfp_t gfp_mask, void *pool_data); | 56 | void *mempool_alloc_slab(gfp_t gfp_mask, void *pool_data); |
45 | void mempool_free_slab(void *element, void *pool_data); | 57 | void mempool_free_slab(void *element, void *pool_data); |
58 | |||
59 | static inline int | ||
60 | mempool_init_slab_pool(mempool_t *pool, int min_nr, struct kmem_cache *kc) | ||
61 | { | ||
62 | return mempool_init(pool, min_nr, mempool_alloc_slab, | ||
63 | mempool_free_slab, (void *) kc); | ||
64 | } | ||
65 | |||
46 | static inline mempool_t * | 66 | static inline mempool_t * |
47 | mempool_create_slab_pool(int min_nr, struct kmem_cache *kc) | 67 | mempool_create_slab_pool(int min_nr, struct kmem_cache *kc) |
48 | { | 68 | { |
@@ -56,6 +76,13 @@ mempool_create_slab_pool(int min_nr, struct kmem_cache *kc) | |||
56 | */ | 76 | */ |
57 | void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data); | 77 | void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data); |
58 | void mempool_kfree(void *element, void *pool_data); | 78 | void mempool_kfree(void *element, void *pool_data); |
79 | |||
80 | static inline int mempool_init_kmalloc_pool(mempool_t *pool, int min_nr, size_t size) | ||
81 | { | ||
82 | return mempool_init(pool, min_nr, mempool_kmalloc, | ||
83 | mempool_kfree, (void *) size); | ||
84 | } | ||
85 | |||
59 | static inline mempool_t *mempool_create_kmalloc_pool(int min_nr, size_t size) | 86 | static inline mempool_t *mempool_create_kmalloc_pool(int min_nr, size_t size) |
60 | { | 87 | { |
61 | return mempool_create(min_nr, mempool_kmalloc, mempool_kfree, | 88 | return mempool_create(min_nr, mempool_kmalloc, mempool_kfree, |
@@ -68,6 +95,13 @@ static inline mempool_t *mempool_create_kmalloc_pool(int min_nr, size_t size) | |||
68 | */ | 95 | */ |
69 | void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data); | 96 | void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data); |
70 | void mempool_free_pages(void *element, void *pool_data); | 97 | void mempool_free_pages(void *element, void *pool_data); |
98 | |||
99 | static inline int mempool_init_page_pool(mempool_t *pool, int min_nr, int order) | ||
100 | { | ||
101 | return mempool_init(pool, min_nr, mempool_alloc_pages, | ||
102 | mempool_free_pages, (void *)(long)order); | ||
103 | } | ||
104 | |||
71 | static inline mempool_t *mempool_create_page_pool(int min_nr, int order) | 105 | static inline mempool_t *mempool_create_page_pool(int min_nr, int order) |
72 | { | 106 | { |
73 | return mempool_create(min_nr, mempool_alloc_pages, mempool_free_pages, | 107 | return mempool_create(min_nr, mempool_alloc_pages, mempool_free_pages, |
diff --git a/mm/mempool.c b/mm/mempool.c index 5c9dce34719b..b54f2c20e5e0 100644 --- a/mm/mempool.c +++ b/mm/mempool.c | |||
@@ -138,6 +138,28 @@ static void *remove_element(mempool_t *pool, gfp_t flags) | |||
138 | } | 138 | } |
139 | 139 | ||
140 | /** | 140 | /** |
141 | * mempool_exit - exit a mempool initialized with mempool_init() | ||
142 | * @pool: pointer to the memory pool which was initialized with | ||
143 | * mempool_init(). | ||
144 | * | ||
145 | * Free all reserved elements in @pool and @pool itself. This function | ||
146 | * only sleeps if the free_fn() function sleeps. | ||
147 | * | ||
148 | * May be called on a zeroed but uninitialized mempool (i.e. allocated with | ||
149 | * kzalloc()). | ||
150 | */ | ||
151 | void mempool_exit(mempool_t *pool) | ||
152 | { | ||
153 | while (pool->curr_nr) { | ||
154 | void *element = remove_element(pool, GFP_KERNEL); | ||
155 | pool->free(element, pool->pool_data); | ||
156 | } | ||
157 | kfree(pool->elements); | ||
158 | pool->elements = NULL; | ||
159 | } | ||
160 | EXPORT_SYMBOL(mempool_exit); | ||
161 | |||
162 | /** | ||
141 | * mempool_destroy - deallocate a memory pool | 163 | * mempool_destroy - deallocate a memory pool |
142 | * @pool: pointer to the memory pool which was allocated via | 164 | * @pool: pointer to the memory pool which was allocated via |
143 | * mempool_create(). | 165 | * mempool_create(). |
@@ -150,15 +172,65 @@ void mempool_destroy(mempool_t *pool) | |||
150 | if (unlikely(!pool)) | 172 | if (unlikely(!pool)) |
151 | return; | 173 | return; |
152 | 174 | ||
153 | while (pool->curr_nr) { | 175 | mempool_exit(pool); |
154 | void *element = remove_element(pool, GFP_KERNEL); | ||
155 | pool->free(element, pool->pool_data); | ||
156 | } | ||
157 | kfree(pool->elements); | ||
158 | kfree(pool); | 176 | kfree(pool); |
159 | } | 177 | } |
160 | EXPORT_SYMBOL(mempool_destroy); | 178 | EXPORT_SYMBOL(mempool_destroy); |
161 | 179 | ||
180 | int mempool_init_node(mempool_t *pool, int min_nr, mempool_alloc_t *alloc_fn, | ||
181 | mempool_free_t *free_fn, void *pool_data, | ||
182 | gfp_t gfp_mask, int node_id) | ||
183 | { | ||
184 | spin_lock_init(&pool->lock); | ||
185 | pool->min_nr = min_nr; | ||
186 | pool->pool_data = pool_data; | ||
187 | pool->alloc = alloc_fn; | ||
188 | pool->free = free_fn; | ||
189 | init_waitqueue_head(&pool->wait); | ||
190 | |||
191 | pool->elements = kmalloc_array_node(min_nr, sizeof(void *), | ||
192 | gfp_mask, node_id); | ||
193 | if (!pool->elements) | ||
194 | return -ENOMEM; | ||
195 | |||
196 | /* | ||
197 | * First pre-allocate the guaranteed number of buffers. | ||
198 | */ | ||
199 | while (pool->curr_nr < pool->min_nr) { | ||
200 | void *element; | ||
201 | |||
202 | element = pool->alloc(gfp_mask, pool->pool_data); | ||
203 | if (unlikely(!element)) { | ||
204 | mempool_exit(pool); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | add_element(pool, element); | ||
208 | } | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | EXPORT_SYMBOL(mempool_init_node); | ||
213 | |||
214 | /** | ||
215 | * mempool_init - initialize a memory pool | ||
216 | * @min_nr: the minimum number of elements guaranteed to be | ||
217 | * allocated for this pool. | ||
218 | * @alloc_fn: user-defined element-allocation function. | ||
219 | * @free_fn: user-defined element-freeing function. | ||
220 | * @pool_data: optional private data available to the user-defined functions. | ||
221 | * | ||
222 | * Like mempool_create(), but initializes the pool in (i.e. embedded in another | ||
223 | * structure). | ||
224 | */ | ||
225 | int mempool_init(mempool_t *pool, int min_nr, mempool_alloc_t *alloc_fn, | ||
226 | mempool_free_t *free_fn, void *pool_data) | ||
227 | { | ||
228 | return mempool_init_node(pool, min_nr, alloc_fn, free_fn, | ||
229 | pool_data, GFP_KERNEL, NUMA_NO_NODE); | ||
230 | |||
231 | } | ||
232 | EXPORT_SYMBOL(mempool_init); | ||
233 | |||
162 | /** | 234 | /** |
163 | * mempool_create - create a memory pool | 235 | * mempool_create - create a memory pool |
164 | * @min_nr: the minimum number of elements guaranteed to be | 236 | * @min_nr: the minimum number of elements guaranteed to be |
@@ -186,35 +258,17 @@ mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn, | |||
186 | gfp_t gfp_mask, int node_id) | 258 | gfp_t gfp_mask, int node_id) |
187 | { | 259 | { |
188 | mempool_t *pool; | 260 | mempool_t *pool; |
261 | |||
189 | pool = kzalloc_node(sizeof(*pool), gfp_mask, node_id); | 262 | pool = kzalloc_node(sizeof(*pool), gfp_mask, node_id); |
190 | if (!pool) | 263 | if (!pool) |
191 | return NULL; | 264 | return NULL; |
192 | pool->elements = kmalloc_array_node(min_nr, sizeof(void *), | 265 | |
193 | gfp_mask, node_id); | 266 | if (mempool_init_node(pool, min_nr, alloc_fn, free_fn, pool_data, |
194 | if (!pool->elements) { | 267 | gfp_mask, node_id)) { |
195 | kfree(pool); | 268 | kfree(pool); |
196 | return NULL; | 269 | return NULL; |
197 | } | 270 | } |
198 | spin_lock_init(&pool->lock); | ||
199 | pool->min_nr = min_nr; | ||
200 | pool->pool_data = pool_data; | ||
201 | init_waitqueue_head(&pool->wait); | ||
202 | pool->alloc = alloc_fn; | ||
203 | pool->free = free_fn; | ||
204 | 271 | ||
205 | /* | ||
206 | * First pre-allocate the guaranteed number of buffers. | ||
207 | */ | ||
208 | while (pool->curr_nr < pool->min_nr) { | ||
209 | void *element; | ||
210 | |||
211 | element = pool->alloc(gfp_mask, pool->pool_data); | ||
212 | if (unlikely(!element)) { | ||
213 | mempool_destroy(pool); | ||
214 | return NULL; | ||
215 | } | ||
216 | add_element(pool, element); | ||
217 | } | ||
218 | return pool; | 272 | return pool; |
219 | } | 273 | } |
220 | EXPORT_SYMBOL(mempool_create_node); | 274 | EXPORT_SYMBOL(mempool_create_node); |