Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (C) 2022 Intel Corporation.
3 : * All rights reserved.
4 : */
5 :
6 : #include "spdk/stdinc.h"
7 : #include "spdk/queue.h"
8 : #include "spdk/util.h"
9 : #include "spdk/env.h"
10 : #include "spdk/likely.h"
11 :
12 : #include "ftl_mempool.h"
13 : #include "ftl_bitmap.h"
14 :
15 : struct ftl_mempool_element {
16 : SLIST_ENTRY(ftl_mempool_element) entry;
17 : };
18 :
19 : struct ftl_mempool {
20 : SLIST_HEAD(, ftl_mempool_element) list;
21 : size_t element_size;
22 : void *buffer;
23 : size_t buffer_size;
24 : size_t count;
25 : size_t alignment;
26 : int socket_id;
27 : struct ftl_bitmap *inuse_bmp;
28 : void *inuse_buf;
29 : };
30 :
31 : static inline bool is_element_valid(struct ftl_mempool *mpool,
32 : void *element) __attribute__((unused));
33 :
34 : static inline bool ftl_mempool_is_initialized(struct ftl_mempool *mpool) __attribute__((unused));
35 :
36 : static size_t
37 1 : element_size_aligned(size_t size, size_t alignment)
38 : {
39 1 : if (!alignment) {
40 0 : return size;
41 : }
42 :
43 1 : if (size % alignment) {
44 0 : return (size / alignment + 1) * alignment;
45 : }
46 :
47 1 : return size;
48 1 : }
49 :
50 : static inline bool
51 32 : is_element_valid(struct ftl_mempool *mpool, void *element)
52 : {
53 32 : if (element < mpool->buffer) {
54 0 : return false;
55 : }
56 :
57 32 : if (element + mpool->element_size > mpool->buffer + mpool->buffer_size) {
58 0 : return false;
59 : }
60 :
61 32 : if (!mpool->alignment) {
62 0 : return true;
63 : }
64 :
65 32 : if ((size_t)element % mpool->alignment) {
66 0 : return false;
67 : }
68 :
69 32 : if ((element - mpool->buffer) % mpool->element_size != 0) {
70 0 : return false;
71 : }
72 :
73 32 : return true;
74 32 : }
75 :
76 2 : struct ftl_mempool *ftl_mempool_create(size_t count, size_t size,
77 : size_t alignment, int socket_id)
78 : {
79 2 : struct ftl_mempool *mp;
80 2 : void *buffer;
81 2 : size_t i;
82 :
83 2 : assert(count > 0);
84 2 : assert(size > 0);
85 :
86 2 : if (!spdk_u64_is_pow2(alignment)) {
87 1 : return NULL;
88 : }
89 :
90 1 : mp = calloc(1, sizeof(*mp));
91 1 : if (!mp) {
92 0 : return NULL;
93 : }
94 :
95 1 : size = spdk_max(size, sizeof(struct ftl_mempool_element));
96 :
97 1 : mp->count = count;
98 1 : mp->element_size = element_size_aligned(size, alignment);
99 1 : mp->alignment = alignment;
100 1 : mp->socket_id = socket_id;
101 1 : SLIST_INIT(&mp->list);
102 :
103 1 : mp->buffer_size = mp->element_size * mp->count;
104 1 : mp->buffer = spdk_dma_malloc_socket(mp->buffer_size, mp->alignment,
105 1 : NULL, socket_id);
106 1 : if (!mp->buffer) {
107 0 : free(mp);
108 0 : return NULL;
109 : }
110 :
111 1 : buffer = mp->buffer;
112 17 : for (i = 0; i < count; i++, buffer += mp->element_size) {
113 16 : struct ftl_mempool_element *el = buffer;
114 16 : assert(is_element_valid(mp, el));
115 16 : SLIST_INSERT_HEAD(&mp->list, el, entry);
116 16 : }
117 :
118 1 : return mp;
119 2 : }
120 :
121 : void
122 1 : ftl_mempool_destroy(struct ftl_mempool *mpool)
123 : {
124 1 : if (!mpool) {
125 0 : return;
126 : }
127 :
128 1 : spdk_dma_free(mpool->buffer);
129 1 : free(mpool);
130 1 : }
131 :
132 : static inline bool
133 33 : ftl_mempool_is_initialized(struct ftl_mempool *mpool)
134 : {
135 33 : return mpool->inuse_buf == NULL;
136 : }
137 :
138 : void *
139 17 : ftl_mempool_get(struct ftl_mempool *mpool)
140 : {
141 17 : struct ftl_mempool_element *el;
142 :
143 17 : assert(ftl_mempool_is_initialized(mpool));
144 17 : if (spdk_unlikely(SLIST_EMPTY(&mpool->list))) {
145 1 : return NULL;
146 : }
147 :
148 16 : el = SLIST_FIRST(&mpool->list);
149 16 : SLIST_REMOVE_HEAD(&mpool->list, entry);
150 :
151 16 : return el;
152 17 : }
153 :
154 : void
155 16 : ftl_mempool_put(struct ftl_mempool *mpool, void *element)
156 : {
157 16 : struct ftl_mempool_element *el = element;
158 :
159 16 : assert(ftl_mempool_is_initialized(mpool));
160 16 : assert(is_element_valid(mpool, element));
161 16 : SLIST_INSERT_HEAD(&mpool->list, el, entry);
162 16 : }
163 :
164 : struct ftl_mempool *
165 0 : ftl_mempool_create_ext(void *buffer, size_t count, size_t size, size_t alignment)
166 : {
167 0 : struct ftl_mempool *mp;
168 0 : size_t inuse_buf_sz;
169 :
170 0 : assert(buffer);
171 0 : assert(count > 0);
172 0 : assert(size > 0);
173 :
174 0 : mp = calloc(1, sizeof(*mp));
175 0 : if (!mp) {
176 0 : goto error;
177 : }
178 :
179 0 : size = spdk_max(size, sizeof(struct ftl_mempool_element));
180 :
181 0 : mp->count = count;
182 0 : mp->element_size = element_size_aligned(size, alignment);
183 0 : mp->alignment = alignment;
184 0 : SLIST_INIT(&mp->list);
185 :
186 : /* Calculate underlying inuse_bmp's buf size */
187 0 : inuse_buf_sz = spdk_divide_round_up(mp->count, 8);
188 : /* The bitmap size must be a multiple of word size (8b) - round up */
189 0 : if (inuse_buf_sz & 7UL) {
190 0 : inuse_buf_sz &= ~7UL;
191 0 : inuse_buf_sz += 8;
192 0 : }
193 :
194 0 : mp->inuse_buf = calloc(1, inuse_buf_sz);
195 0 : if (!mp->inuse_buf) {
196 0 : goto error;
197 : }
198 :
199 0 : mp->inuse_bmp = ftl_bitmap_create(mp->inuse_buf, inuse_buf_sz);
200 0 : if (!mp->inuse_bmp) {
201 0 : goto error;
202 : }
203 :
204 : /* Map the buffer */
205 0 : mp->buffer_size = mp->element_size * mp->count;
206 0 : mp->buffer = buffer;
207 :
208 0 : return mp;
209 :
210 : error:
211 0 : ftl_mempool_destroy_ext(mp);
212 0 : return NULL;
213 0 : }
214 :
215 : void
216 0 : ftl_mempool_destroy_ext(struct ftl_mempool *mpool)
217 : {
218 0 : if (!mpool) {
219 0 : return;
220 : }
221 :
222 0 : if (mpool->inuse_bmp) {
223 0 : ftl_bitmap_destroy(mpool->inuse_bmp);
224 0 : }
225 0 : free(mpool->inuse_buf);
226 0 : free(mpool);
227 0 : }
228 :
229 : void
230 0 : ftl_mempool_initialize_ext(struct ftl_mempool *mpool)
231 : {
232 0 : struct ftl_mempool_element *el;
233 0 : void *buffer = mpool->buffer;
234 0 : size_t i;
235 :
236 0 : assert(!ftl_mempool_is_initialized(mpool));
237 :
238 0 : for (i = 0; i < mpool->count; i++, buffer += mpool->element_size) {
239 0 : if (ftl_bitmap_get(mpool->inuse_bmp, i)) {
240 0 : continue;
241 : }
242 0 : el = buffer;
243 0 : assert(is_element_valid(mpool, el));
244 0 : SLIST_INSERT_HEAD(&mpool->list, el, entry);
245 0 : }
246 :
247 0 : ftl_bitmap_destroy(mpool->inuse_bmp);
248 0 : mpool->inuse_bmp = NULL;
249 :
250 0 : free(mpool->inuse_buf);
251 0 : mpool->inuse_buf = NULL;
252 0 : }
253 :
254 : ftl_df_obj_id
255 0 : ftl_mempool_get_df_obj_id(struct ftl_mempool *mpool, void *df_obj_ptr)
256 : {
257 0 : return ftl_df_get_obj_id(mpool->buffer, df_obj_ptr);
258 : }
259 :
260 : size_t
261 0 : ftl_mempool_get_df_obj_index(struct ftl_mempool *mpool, void *df_obj_ptr)
262 : {
263 0 : return ftl_mempool_get_df_obj_id(mpool, df_obj_ptr) / mpool->element_size;
264 : }
265 :
266 : void *
267 0 : ftl_mempool_get_df_ptr(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
268 : {
269 0 : return ftl_df_get_obj_ptr(mpool->buffer, df_obj_id);
270 : }
271 :
272 : void *
273 0 : ftl_mempool_claim_df(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
274 : {
275 0 : struct ftl_mempool_element *el = ftl_df_get_obj_ptr(mpool->buffer, df_obj_id);
276 :
277 0 : assert(!ftl_mempool_is_initialized(mpool));
278 0 : assert(df_obj_id % mpool->element_size == 0);
279 0 : assert(df_obj_id / mpool->element_size < mpool->count);
280 :
281 0 : ftl_bitmap_set(mpool->inuse_bmp, df_obj_id / mpool->element_size);
282 0 : return el;
283 0 : }
284 :
285 : void
286 0 : ftl_mempool_release_df(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
287 : {
288 0 : assert(!ftl_mempool_is_initialized(mpool));
289 0 : assert(df_obj_id % mpool->element_size == 0);
290 0 : assert(df_obj_id / mpool->element_size < mpool->count);
291 :
292 0 : ftl_bitmap_clear(mpool->inuse_bmp, df_obj_id / mpool->element_size);
293 0 : }
|