Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2023 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/env.h"
7 : : #include "spdk/util.h"
8 : : #include "spdk/likely.h"
9 : : #include "spdk/log.h"
10 : : #include "spdk/thread.h"
11 : :
12 : : #define IOBUF_MIN_SMALL_POOL_SIZE 64
13 : : #define IOBUF_MIN_LARGE_POOL_SIZE 8
14 : : #define IOBUF_DEFAULT_SMALL_POOL_SIZE 8192
15 : : #define IOBUF_DEFAULT_LARGE_POOL_SIZE 1024
16 : : #define IOBUF_ALIGNMENT 4096
17 : : #define IOBUF_MIN_SMALL_BUFSIZE 4096
18 : : #define IOBUF_MIN_LARGE_BUFSIZE 8192
19 : : #define IOBUF_DEFAULT_SMALL_BUFSIZE (8 * 1024)
20 : : /* 132k is a weird choice at first, but this needs to be large enough to accomodate
21 : : * the default maximum size (128k) plus metadata everywhere. For code paths that
22 : : * are explicitly configured, the math is instead done properly. This is only
23 : : * for the default. */
24 : : #define IOBUF_DEFAULT_LARGE_BUFSIZE (132 * 1024)
25 : : #define IOBUF_MAX_CHANNELS 64
26 : :
27 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_iobuf_buffer) <= IOBUF_MIN_SMALL_BUFSIZE,
28 : : "Invalid data offset");
29 : :
30 : : static bool g_iobuf_is_initialized = false;
31 : :
32 : : struct iobuf_channel {
33 : : spdk_iobuf_entry_stailq_t small_queue;
34 : : spdk_iobuf_entry_stailq_t large_queue;
35 : : struct spdk_iobuf_channel *channels[IOBUF_MAX_CHANNELS];
36 : : };
37 : :
38 : : struct iobuf_module {
39 : : char *name;
40 : : TAILQ_ENTRY(iobuf_module) tailq;
41 : : };
42 : :
43 : : struct iobuf {
44 : : struct spdk_ring *small_pool;
45 : : struct spdk_ring *large_pool;
46 : : void *small_pool_base;
47 : : void *large_pool_base;
48 : : struct spdk_iobuf_opts opts;
49 : : TAILQ_HEAD(, iobuf_module) modules;
50 : : spdk_iobuf_finish_cb finish_cb;
51 : : void *finish_arg;
52 : : };
53 : :
54 : : static struct iobuf g_iobuf = {
55 : : .modules = TAILQ_HEAD_INITIALIZER(g_iobuf.modules),
56 : : .small_pool = NULL,
57 : : .large_pool = NULL,
58 : : .small_pool_base = NULL,
59 : : .large_pool_base = NULL,
60 : : .opts = {
61 : : .small_pool_count = IOBUF_DEFAULT_SMALL_POOL_SIZE,
62 : : .large_pool_count = IOBUF_DEFAULT_LARGE_POOL_SIZE,
63 : : .small_bufsize = IOBUF_DEFAULT_SMALL_BUFSIZE,
64 : : .large_bufsize = IOBUF_DEFAULT_LARGE_BUFSIZE,
65 : : },
66 : : };
67 : :
68 : : struct iobuf_get_stats_ctx {
69 : : struct spdk_iobuf_module_stats *modules;
70 : : uint32_t num_modules;
71 : : spdk_iobuf_get_stats_cb cb_fn;
72 : : void *cb_arg;
73 : : };
74 : :
75 : : static int
76 : 10170 : iobuf_channel_create_cb(void *io_device, void *ctx)
77 : : {
78 : 10170 : struct iobuf_channel *ch = ctx;
79 : :
80 : 10170 : STAILQ_INIT(&ch->small_queue);
81 : 10170 : STAILQ_INIT(&ch->large_queue);
82 : :
83 : 10170 : return 0;
84 : : }
85 : :
86 : : static void
87 : 10170 : iobuf_channel_destroy_cb(void *io_device, void *ctx)
88 : : {
89 : 10170 : struct iobuf_channel *ch __attribute__((unused)) = ctx;
90 : :
91 [ - + ]: 10170 : assert(STAILQ_EMPTY(&ch->small_queue));
92 [ - + ]: 10170 : assert(STAILQ_EMPTY(&ch->large_queue));
93 : 10170 : }
94 : :
95 : : int
96 : 3134 : spdk_iobuf_initialize(void)
97 : : {
98 : 3134 : struct spdk_iobuf_opts *opts = &g_iobuf.opts;
99 : 3134 : int rc = 0;
100 : : uint64_t i;
101 : 1656 : struct spdk_iobuf_buffer *buf;
102 : :
103 : 3134 : g_iobuf.small_pool = spdk_ring_create(SPDK_RING_TYPE_MP_MC, opts->small_pool_count,
104 : : SPDK_ENV_SOCKET_ID_ANY);
105 [ - + ]: 3134 : if (!g_iobuf.small_pool) {
106 : 0 : SPDK_ERRLOG("Failed to create small iobuf pool\n");
107 : 0 : rc = -ENOMEM;
108 : 0 : goto error;
109 : : }
110 : :
111 : : /* Round up to the nearest alignment so that each element remains aligned */
112 : 3134 : opts->small_bufsize = SPDK_ALIGN_CEIL(opts->small_bufsize, IOBUF_ALIGNMENT);
113 : 3134 : g_iobuf.small_pool_base = spdk_malloc(opts->small_bufsize * opts->small_pool_count, IOBUF_ALIGNMENT,
114 : : NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
115 [ - + ]: 3134 : if (g_iobuf.small_pool_base == NULL) {
116 : 0 : SPDK_ERRLOG("Unable to allocate requested small iobuf pool size\n");
117 : 0 : rc = -ENOMEM;
118 : 0 : goto error;
119 : : }
120 : :
121 : 3134 : g_iobuf.large_pool = spdk_ring_create(SPDK_RING_TYPE_MP_MC, opts->large_pool_count,
122 : : SPDK_ENV_SOCKET_ID_ANY);
123 [ - + ]: 3134 : if (!g_iobuf.large_pool) {
124 : 0 : SPDK_ERRLOG("Failed to create large iobuf pool\n");
125 : 0 : rc = -ENOMEM;
126 : 0 : goto error;
127 : : }
128 : :
129 : : /* Round up to the nearest alignment so that each element remains aligned */
130 : 3134 : opts->large_bufsize = SPDK_ALIGN_CEIL(opts->large_bufsize, IOBUF_ALIGNMENT);
131 : 3134 : g_iobuf.large_pool_base = spdk_malloc(opts->large_bufsize * opts->large_pool_count, IOBUF_ALIGNMENT,
132 : : NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
133 [ - + ]: 3134 : if (g_iobuf.large_pool_base == NULL) {
134 : 0 : SPDK_ERRLOG("Unable to allocate requested large iobuf pool size\n");
135 : 0 : rc = -ENOMEM;
136 : 0 : goto error;
137 : : }
138 : :
139 [ + + ]: 25789206 : for (i = 0; i < opts->small_pool_count; i++) {
140 : 25786070 : buf = g_iobuf.small_pool_base + i * opts->small_bufsize;
141 : 25786070 : spdk_ring_enqueue(g_iobuf.small_pool, (void **)&buf, 1, NULL);
142 : : }
143 : :
144 [ + + ]: 3219810 : for (i = 0; i < opts->large_pool_count; i++) {
145 : 3216676 : buf = g_iobuf.large_pool_base + i * opts->large_bufsize;
146 : 3216676 : spdk_ring_enqueue(g_iobuf.large_pool, (void **)&buf, 1, NULL);
147 : : }
148 : :
149 : 3134 : spdk_io_device_register(&g_iobuf, iobuf_channel_create_cb, iobuf_channel_destroy_cb,
150 : : sizeof(struct iobuf_channel), "iobuf");
151 : 3134 : g_iobuf_is_initialized = true;
152 : :
153 : 3134 : return 0;
154 : 0 : error:
155 : 0 : spdk_free(g_iobuf.small_pool_base);
156 : 0 : spdk_ring_free(g_iobuf.small_pool);
157 : 0 : spdk_free(g_iobuf.large_pool_base);
158 : 0 : spdk_ring_free(g_iobuf.large_pool);
159 : :
160 : 0 : return rc;
161 : : }
162 : :
163 : : static void
164 : 3134 : iobuf_unregister_cb(void *io_device)
165 : : {
166 : : struct iobuf_module *module;
167 : :
168 [ + + ]: 8566 : while (!TAILQ_EMPTY(&g_iobuf.modules)) {
169 : 5432 : module = TAILQ_FIRST(&g_iobuf.modules);
170 [ + + ]: 5432 : TAILQ_REMOVE(&g_iobuf.modules, module, tailq);
171 : 5432 : free(module->name);
172 : 5432 : free(module);
173 : : }
174 : :
175 [ - + ]: 3134 : if (spdk_ring_count(g_iobuf.small_pool) != g_iobuf.opts.small_pool_count) {
176 : 0 : SPDK_ERRLOG("small iobuf pool count is %zu, expected %"PRIu64"\n",
177 : : spdk_ring_count(g_iobuf.small_pool), g_iobuf.opts.small_pool_count);
178 : : }
179 : :
180 [ - + ]: 3134 : if (spdk_ring_count(g_iobuf.large_pool) != g_iobuf.opts.large_pool_count) {
181 : 0 : SPDK_ERRLOG("large iobuf pool count is %zu, expected %"PRIu64"\n",
182 : : spdk_ring_count(g_iobuf.large_pool), g_iobuf.opts.large_pool_count);
183 : : }
184 : :
185 : 3134 : spdk_free(g_iobuf.small_pool_base);
186 : 3134 : g_iobuf.small_pool_base = NULL;
187 : 3134 : spdk_ring_free(g_iobuf.small_pool);
188 : 3134 : g_iobuf.small_pool = NULL;
189 : :
190 : 3134 : spdk_free(g_iobuf.large_pool_base);
191 : 3134 : g_iobuf.large_pool_base = NULL;
192 : 3134 : spdk_ring_free(g_iobuf.large_pool);
193 : 3134 : g_iobuf.large_pool = NULL;
194 : :
195 [ + - ]: 3134 : if (g_iobuf.finish_cb != NULL) {
196 : 3134 : g_iobuf.finish_cb(g_iobuf.finish_arg);
197 : : }
198 : 3134 : }
199 : :
200 : : void
201 : 3134 : spdk_iobuf_finish(spdk_iobuf_finish_cb cb_fn, void *cb_arg)
202 : : {
203 [ - + - + ]: 3134 : if (!g_iobuf_is_initialized) {
204 : 0 : cb_fn(cb_arg);
205 : 0 : return;
206 : : }
207 : :
208 : 3134 : g_iobuf_is_initialized = false;
209 : 3134 : g_iobuf.finish_cb = cb_fn;
210 : 3134 : g_iobuf.finish_arg = cb_arg;
211 : :
212 : 3134 : spdk_io_device_unregister(&g_iobuf, iobuf_unregister_cb);
213 : : }
214 : :
215 : : int
216 : 241 : spdk_iobuf_set_opts(const struct spdk_iobuf_opts *opts)
217 : : {
218 [ - + ]: 241 : if (!opts) {
219 : 0 : SPDK_ERRLOG("opts cannot be NULL\n");
220 : 0 : return -1;
221 : : }
222 : :
223 [ - + ]: 241 : if (!opts->opts_size) {
224 : 0 : SPDK_ERRLOG("opts_size inside opts cannot be zero value\n");
225 : 0 : return -1;
226 : : }
227 : :
228 [ - + ]: 241 : if (opts->small_pool_count < IOBUF_MIN_SMALL_POOL_SIZE) {
229 : 0 : SPDK_ERRLOG("small_pool_count must be at least %" PRIu32 "\n",
230 : : IOBUF_MIN_SMALL_POOL_SIZE);
231 : 0 : return -EINVAL;
232 : : }
233 [ - + ]: 241 : if (opts->large_pool_count < IOBUF_MIN_LARGE_POOL_SIZE) {
234 : 0 : SPDK_ERRLOG("large_pool_count must be at least %" PRIu32 "\n",
235 : : IOBUF_MIN_LARGE_POOL_SIZE);
236 : 0 : return -EINVAL;
237 : : }
238 : :
239 [ - + ]: 241 : if (opts->small_bufsize < IOBUF_MIN_SMALL_BUFSIZE) {
240 : 0 : SPDK_ERRLOG("small_bufsize must be at least %" PRIu32 "\n",
241 : : IOBUF_MIN_SMALL_BUFSIZE);
242 : 0 : return -EINVAL;
243 : : }
244 : :
245 [ - + ]: 241 : if (opts->large_bufsize < IOBUF_MIN_LARGE_BUFSIZE) {
246 : 0 : SPDK_ERRLOG("large_bufsize must be at least %" PRIu32 "\n",
247 : : IOBUF_MIN_LARGE_BUFSIZE);
248 : 0 : return -EINVAL;
249 : : }
250 : :
251 : : #define SET_FIELD(field) \
252 : : if (offsetof(struct spdk_iobuf_opts, field) + sizeof(opts->field) <= opts->opts_size) { \
253 : : g_iobuf.opts.field = opts->field; \
254 : : } \
255 : :
256 [ + - ]: 241 : SET_FIELD(small_pool_count);
257 [ + - ]: 241 : SET_FIELD(large_pool_count);
258 [ + - ]: 241 : SET_FIELD(small_bufsize);
259 [ + - ]: 241 : SET_FIELD(large_bufsize);
260 : :
261 : 241 : g_iobuf.opts.opts_size = opts->opts_size;
262 : :
263 : : #undef SET_FIELD
264 : :
265 : 241 : return 0;
266 : : }
267 : :
268 : : void
269 : 11775 : spdk_iobuf_get_opts(struct spdk_iobuf_opts *opts, size_t opts_size)
270 : : {
271 [ - + ]: 11775 : if (!opts) {
272 : 0 : SPDK_ERRLOG("opts should not be NULL\n");
273 : 0 : return;
274 : : }
275 : :
276 [ - + ]: 11775 : if (!opts_size) {
277 : 0 : SPDK_ERRLOG("opts_size should not be zero value\n");
278 : 0 : return;
279 : : }
280 : :
281 : 11775 : opts->opts_size = opts_size;
282 : :
283 : : #define SET_FIELD(field) \
284 : : if (offsetof(struct spdk_iobuf_opts, field) + sizeof(opts->field) <= opts_size) { \
285 : : opts->field = g_iobuf.opts.field; \
286 : : } \
287 : :
288 [ + - ]: 11775 : SET_FIELD(small_pool_count);
289 [ + - ]: 11775 : SET_FIELD(large_pool_count);
290 [ + - ]: 11775 : SET_FIELD(small_bufsize);
291 [ + - ]: 11775 : SET_FIELD(large_bufsize);
292 : :
293 : : #undef SET_FIELD
294 : :
295 : : /* Do not remove this statement, you should always update this statement when you adding a new field,
296 : : * and do not forget to add the SET_FIELD statement for your added field. */
297 : : SPDK_STATIC_ASSERT(sizeof(struct spdk_iobuf_opts) == 32, "Incorrect size");
298 : : }
299 : :
300 : :
301 : : int
302 : 27604 : spdk_iobuf_channel_init(struct spdk_iobuf_channel *ch, const char *name,
303 : : uint32_t small_cache_size, uint32_t large_cache_size)
304 : : {
305 : : struct spdk_io_channel *ioch;
306 : : struct iobuf_channel *iobuf_ch;
307 : : struct iobuf_module *module;
308 : 10376 : struct spdk_iobuf_buffer *buf;
309 : : uint32_t i;
310 : :
311 [ + - ]: 43700 : TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
312 [ + + - + : 43700 : if (strcmp(name, module->name) == 0) {
+ + ]
313 : 27604 : break;
314 : : }
315 : : }
316 : :
317 [ - + ]: 27604 : if (module == NULL) {
318 : 0 : SPDK_ERRLOG("Couldn't find iobuf module: '%s'\n", name);
319 : 0 : return -ENODEV;
320 : : }
321 : :
322 : 27604 : ioch = spdk_get_io_channel(&g_iobuf);
323 [ - + ]: 27604 : if (ioch == NULL) {
324 : 0 : SPDK_ERRLOG("Couldn't get iobuf IO channel\n");
325 : 0 : return -ENOMEM;
326 : : }
327 : :
328 : 27604 : iobuf_ch = spdk_io_channel_get_ctx(ioch);
329 : :
330 [ + - ]: 51519 : for (i = 0; i < IOBUF_MAX_CHANNELS; ++i) {
331 [ + + ]: 51519 : if (iobuf_ch->channels[i] == NULL) {
332 : 27604 : iobuf_ch->channels[i] = ch;
333 : 27604 : break;
334 : : }
335 : : }
336 : :
337 [ - + ]: 27604 : if (i == IOBUF_MAX_CHANNELS) {
338 : 0 : SPDK_ERRLOG("Max number of iobuf channels (%" PRIu32 ") exceeded.\n", i);
339 : 0 : goto error;
340 : : }
341 : :
342 : 27604 : ch->small.queue = &iobuf_ch->small_queue;
343 : 27604 : ch->large.queue = &iobuf_ch->large_queue;
344 : 27604 : ch->small.pool = g_iobuf.small_pool;
345 : 27604 : ch->large.pool = g_iobuf.large_pool;
346 : 27604 : ch->small.bufsize = g_iobuf.opts.small_bufsize;
347 : 27604 : ch->large.bufsize = g_iobuf.opts.large_bufsize;
348 : 27604 : ch->parent = ioch;
349 : 27604 : ch->module = module;
350 : 27604 : ch->small.cache_size = small_cache_size;
351 : 27604 : ch->large.cache_size = large_cache_size;
352 : 27604 : ch->small.cache_count = 0;
353 : 27604 : ch->large.cache_count = 0;
354 : :
355 : 27604 : STAILQ_INIT(&ch->small.cache);
356 : 27604 : STAILQ_INIT(&ch->large.cache);
357 : :
358 [ + + ]: 3608282 : for (i = 0; i < small_cache_size; ++i) {
359 [ + + ]: 3580690 : if (spdk_ring_dequeue(g_iobuf.small_pool, (void **)&buf, 1) == 0) {
360 : 12 : SPDK_ERRLOG("Failed to populate '%s' iobuf small buffer cache at %d/%d entries. "
361 : : "You may need to increase spdk_iobuf_opts.small_pool_count (%"PRIu64")\n",
362 : : name, i, small_cache_size, g_iobuf.opts.small_pool_count);
363 : 12 : SPDK_ERRLOG("See scripts/calc-iobuf.py for guidance on how to calculate "
364 : : "this value.\n");
365 : 12 : goto error;
366 : : }
367 : 3580678 : STAILQ_INSERT_TAIL(&ch->small.cache, buf, stailq);
368 : 3580678 : ch->small.cache_count++;
369 : : }
370 [ + + ]: 501616 : for (i = 0; i < large_cache_size; ++i) {
371 [ + + ]: 474030 : if (spdk_ring_dequeue(g_iobuf.large_pool, (void **)&buf, 1) == 0) {
372 : 6 : SPDK_ERRLOG("Failed to populate '%s' iobuf large buffer cache at %d/%d entries. "
373 : : "You may need to increase spdk_iobuf_opts.large_pool_count (%"PRIu64")\n",
374 : : name, i, large_cache_size, g_iobuf.opts.large_pool_count);
375 : 6 : SPDK_ERRLOG("See scripts/calc-iobuf.py for guidance on how to calculate "
376 : : "this value.\n");
377 : 6 : goto error;
378 : : }
379 : 474024 : STAILQ_INSERT_TAIL(&ch->large.cache, buf, stailq);
380 : 474024 : ch->large.cache_count++;
381 : : }
382 : :
383 : 27586 : return 0;
384 : 18 : error:
385 : 18 : spdk_iobuf_channel_fini(ch);
386 : :
387 : 18 : return -ENOMEM;
388 : : }
389 : :
390 : : void
391 : 27604 : spdk_iobuf_channel_fini(struct spdk_iobuf_channel *ch)
392 : : {
393 : : struct spdk_iobuf_entry *entry __attribute__((unused));
394 : 10376 : struct spdk_iobuf_buffer *buf;
395 : : struct iobuf_channel *iobuf_ch;
396 : : uint32_t i;
397 : :
398 : : /* Make sure none of the wait queue entries are coming from this module */
399 [ - + ]: 27604 : STAILQ_FOREACH(entry, ch->small.queue, stailq) {
400 [ # # ]: 0 : assert(entry->module != ch->module);
401 : : }
402 [ - + ]: 27604 : STAILQ_FOREACH(entry, ch->large.queue, stailq) {
403 [ # # ]: 0 : assert(entry->module != ch->module);
404 : : }
405 : :
406 : : /* Release cached buffers back to the pool */
407 [ + + ]: 3608294 : while (!STAILQ_EMPTY(&ch->small.cache)) {
408 : 3580690 : buf = STAILQ_FIRST(&ch->small.cache);
409 [ + + ]: 3580690 : STAILQ_REMOVE_HEAD(&ch->small.cache, stailq);
410 : 3580690 : spdk_ring_enqueue(g_iobuf.small_pool, (void **)&buf, 1, NULL);
411 : 3580690 : ch->small.cache_count--;
412 : : }
413 [ + + ]: 501700 : while (!STAILQ_EMPTY(&ch->large.cache)) {
414 : 474096 : buf = STAILQ_FIRST(&ch->large.cache);
415 [ + + ]: 474096 : STAILQ_REMOVE_HEAD(&ch->large.cache, stailq);
416 : 474096 : spdk_ring_enqueue(g_iobuf.large_pool, (void **)&buf, 1, NULL);
417 : 474096 : ch->large.cache_count--;
418 : : }
419 : :
420 [ - + ]: 27604 : assert(ch->small.cache_count == 0);
421 [ - + ]: 27604 : assert(ch->large.cache_count == 0);
422 : :
423 : 27604 : iobuf_ch = spdk_io_channel_get_ctx(ch->parent);
424 [ + - ]: 51519 : for (i = 0; i < IOBUF_MAX_CHANNELS; ++i) {
425 [ + + ]: 51519 : if (iobuf_ch->channels[i] == ch) {
426 : 27604 : iobuf_ch->channels[i] = NULL;
427 : 27604 : break;
428 : : }
429 : : }
430 : :
431 : 27604 : spdk_put_io_channel(ch->parent);
432 : 27604 : ch->parent = NULL;
433 : 27604 : }
434 : :
435 : : int
436 : 5707 : spdk_iobuf_register_module(const char *name)
437 : : {
438 : : struct iobuf_module *module;
439 : :
440 [ + + ]: 8547 : TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
441 [ - + - + : 2841 : if (strcmp(name, module->name) == 0) {
+ + ]
442 : 1 : return -EEXIST;
443 : : }
444 : : }
445 : :
446 : 5706 : module = calloc(1, sizeof(*module));
447 [ - + ]: 5706 : if (module == NULL) {
448 : 0 : return -ENOMEM;
449 : : }
450 : :
451 [ - + ]: 5706 : module->name = strdup(name);
452 [ - + ]: 5706 : if (module->name == NULL) {
453 : 0 : free(module);
454 : 0 : return -ENOMEM;
455 : : }
456 : :
457 : 5706 : TAILQ_INSERT_TAIL(&g_iobuf.modules, module, tailq);
458 : :
459 : 5706 : return 0;
460 : : }
461 : :
462 : : int
463 : 268 : spdk_iobuf_unregister_module(const char *name)
464 : : {
465 : : struct iobuf_module *module;
466 : :
467 [ + - ]: 804 : TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
468 [ + + - + : 804 : if (strcmp(name, module->name) == 0) {
+ + ]
469 [ - + ]: 268 : TAILQ_REMOVE(&g_iobuf.modules, module, tailq);
470 : 268 : free(module->name);
471 : 268 : free(module);
472 : 268 : return 0;
473 : : }
474 : : }
475 : :
476 : 0 : return -ENOENT;
477 : : }
478 : :
479 : : int
480 : 162480 : spdk_iobuf_for_each_entry(struct spdk_iobuf_channel *ch, struct spdk_iobuf_pool *pool,
481 : : spdk_iobuf_for_each_entry_fn cb_fn, void *cb_ctx)
482 : : {
483 : : struct spdk_iobuf_entry *entry, *tmp;
484 : : int rc;
485 : :
486 [ + + ]: 162576 : STAILQ_FOREACH_SAFE(entry, pool->queue, stailq, tmp) {
487 : : /* We only want to iterate over the entries requested by the module which owns ch */
488 [ + + ]: 96 : if (entry->module != ch->module) {
489 : 48 : continue;
490 : : }
491 : :
492 : 48 : rc = cb_fn(ch, entry, cb_ctx);
493 [ - + ]: 48 : if (rc != 0) {
494 : 0 : return rc;
495 : : }
496 : : }
497 : :
498 : 162480 : return 0;
499 : : }
500 : :
501 : : void
502 : 72 : spdk_iobuf_entry_abort(struct spdk_iobuf_channel *ch, struct spdk_iobuf_entry *entry,
503 : : uint64_t len)
504 : : {
505 : : struct spdk_iobuf_pool *pool;
506 : :
507 [ + + ]: 72 : if (len <= ch->small.bufsize) {
508 : 36 : pool = &ch->small;
509 : : } else {
510 [ - + ]: 36 : assert(len <= ch->large.bufsize);
511 : 36 : pool = &ch->large;
512 : : }
513 : :
514 [ + - + + : 72 : STAILQ_REMOVE(pool->queue, entry, spdk_iobuf_entry, stailq);
- - - - ]
515 : 72 : }
516 : :
517 : : #define IOBUF_BATCH_SIZE 32
518 : :
519 : : void *
520 : 65034546 : spdk_iobuf_get(struct spdk_iobuf_channel *ch, uint64_t len,
521 : : struct spdk_iobuf_entry *entry, spdk_iobuf_get_cb cb_fn)
522 : : {
523 : : struct spdk_iobuf_pool *pool;
524 : : void *buf;
525 : :
526 [ - + ]: 65034546 : assert(spdk_io_channel_get_thread(ch->parent) == spdk_get_thread());
527 [ + + ]: 65034546 : if (len <= ch->small.bufsize) {
528 : 63264527 : pool = &ch->small;
529 : : } else {
530 [ - + ]: 1770019 : assert(len <= ch->large.bufsize);
531 : 1770019 : pool = &ch->large;
532 : : }
533 : :
534 : 65034546 : buf = (void *)STAILQ_FIRST(&pool->cache);
535 [ + + ]: 65034546 : if (buf) {
536 [ + + ]: 62477612 : STAILQ_REMOVE_HEAD(&pool->cache, stailq);
537 [ - + ]: 62477612 : assert(pool->cache_count > 0);
538 : 62477612 : pool->cache_count--;
539 : 62477612 : pool->stats.cache++;
540 : : } else {
541 : 49511 : struct spdk_iobuf_buffer *bufs[IOBUF_BATCH_SIZE];
542 : : size_t sz, i;
543 : :
544 : : /* If we're going to dequeue, we may as well dequeue a batch. */
545 [ + + ]: 2556934 : sz = spdk_ring_dequeue(pool->pool, (void **)bufs, spdk_min(IOBUF_BATCH_SIZE,
546 : : spdk_max(pool->cache_size, 1)));
547 [ + + ]: 2556934 : if (sz == 0) {
548 [ + + ]: 2299289 : if (entry) {
549 : 47659 : STAILQ_INSERT_TAIL(pool->queue, entry, stailq);
550 : 47659 : entry->module = ch->module;
551 : 47659 : entry->cb_fn = cb_fn;
552 : 47659 : pool->stats.retry++;
553 : : }
554 : :
555 : 2299289 : return NULL;
556 : : }
557 : :
558 : 257645 : pool->stats.main++;
559 [ + + ]: 7756364 : for (i = 0; i < (sz - 1); i++) {
560 [ + + ]: 7498719 : STAILQ_INSERT_HEAD(&pool->cache, bufs[i], stailq);
561 : 7498719 : pool->cache_count++;
562 : : }
563 : :
564 : : /* The last one is the one we'll return */
565 : 257645 : buf = bufs[i];
566 : : }
567 : :
568 : 62735257 : return (char *)buf;
569 : : }
570 : :
571 : : void
572 : 62782844 : spdk_iobuf_put(struct spdk_iobuf_channel *ch, void *buf, uint64_t len)
573 : : {
574 : : struct spdk_iobuf_entry *entry;
575 : : struct spdk_iobuf_buffer *iobuf_buf;
576 : : struct spdk_iobuf_pool *pool;
577 : : size_t sz;
578 : :
579 [ - + ]: 62782844 : assert(spdk_io_channel_get_thread(ch->parent) == spdk_get_thread());
580 [ + + ]: 62782844 : if (len <= ch->small.bufsize) {
581 : 61012861 : pool = &ch->small;
582 : : } else {
583 : 1769983 : pool = &ch->large;
584 : : }
585 : :
586 [ + + ]: 62782844 : if (STAILQ_EMPTY(pool->queue)) {
587 [ + + ]: 62735257 : if (pool->cache_size == 0) {
588 : 96 : spdk_ring_enqueue(pool->pool, (void **)&buf, 1, NULL);
589 : 96 : return;
590 : : }
591 : :
592 : 62735161 : iobuf_buf = (struct spdk_iobuf_buffer *)buf;
593 : :
594 [ + + ]: 62735161 : STAILQ_INSERT_HEAD(&pool->cache, iobuf_buf, stailq);
595 : 62735161 : pool->cache_count++;
596 : :
597 : : /* The cache size may exceed the configured amount. We always dequeue from the
598 : : * central pool in batches of known size, so wait until at least a batch
599 : : * has been returned to actually return the buffers to the central pool. */
600 : 62735161 : sz = spdk_min(IOBUF_BATCH_SIZE, pool->cache_size);
601 [ + + ]: 62735161 : if (pool->cache_count >= pool->cache_size + sz) {
602 : 8522 : struct spdk_iobuf_buffer *bufs[IOBUF_BATCH_SIZE];
603 : : size_t i;
604 : :
605 [ + + ]: 8013723 : for (i = 0; i < sz; i++) {
606 : 7756184 : bufs[i] = STAILQ_FIRST(&pool->cache);
607 [ - + ]: 7756184 : STAILQ_REMOVE_HEAD(&pool->cache, stailq);
608 [ - + ]: 7756184 : assert(pool->cache_count > 0);
609 : 7756184 : pool->cache_count--;
610 : : }
611 : :
612 : 257539 : spdk_ring_enqueue(pool->pool, (void **)bufs, sz, NULL);
613 : : }
614 : : } else {
615 : 47587 : entry = STAILQ_FIRST(pool->queue);
616 [ + + ]: 47587 : STAILQ_REMOVE_HEAD(pool->queue, stailq);
617 : 47587 : entry->cb_fn(entry, buf);
618 : : }
619 : : }
620 : :
621 : : static void
622 : 0 : iobuf_get_channel_stats_done(struct spdk_io_channel_iter *iter, int status)
623 : : {
624 : 0 : struct iobuf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(iter);
625 : :
626 : 0 : ctx->cb_fn(ctx->modules, ctx->num_modules, ctx->cb_arg);
627 : 0 : free(ctx->modules);
628 : 0 : free(ctx);
629 : 0 : }
630 : :
631 : : static void
632 : 0 : iobuf_get_channel_stats(struct spdk_io_channel_iter *iter)
633 : : {
634 : 0 : struct iobuf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(iter);
635 : 0 : struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(iter);
636 : 0 : struct iobuf_channel *iobuf_ch = spdk_io_channel_get_ctx(ch);
637 : : struct spdk_iobuf_channel *channel;
638 : : struct iobuf_module *module;
639 : : struct spdk_iobuf_module_stats *it;
640 : : uint32_t i, j;
641 : :
642 [ # # ]: 0 : for (i = 0; i < ctx->num_modules; ++i) {
643 [ # # ]: 0 : for (j = 0; j < IOBUF_MAX_CHANNELS; ++j) {
644 : 0 : channel = iobuf_ch->channels[j];
645 [ # # ]: 0 : if (channel == NULL) {
646 : 0 : continue;
647 : : }
648 : :
649 : 0 : it = &ctx->modules[i];
650 : 0 : module = (struct iobuf_module *)channel->module;
651 [ # # # # : 0 : if (strcmp(it->module, module->name) == 0) {
# # ]
652 : 0 : it->small_pool.cache += channel->small.stats.cache;
653 : 0 : it->small_pool.main += channel->small.stats.main;
654 : 0 : it->small_pool.retry += channel->small.stats.retry;
655 : 0 : it->large_pool.cache += channel->large.stats.cache;
656 : 0 : it->large_pool.main += channel->large.stats.main;
657 : 0 : it->large_pool.retry += channel->large.stats.retry;
658 : 0 : break;
659 : : }
660 : : }
661 : : }
662 : :
663 : 0 : spdk_for_each_channel_continue(iter, 0);
664 : 0 : }
665 : :
666 : : int
667 : 0 : spdk_iobuf_get_stats(spdk_iobuf_get_stats_cb cb_fn, void *cb_arg)
668 : : {
669 : : struct iobuf_module *module;
670 : : struct iobuf_get_stats_ctx *ctx;
671 : : uint32_t i;
672 : :
673 : 0 : ctx = calloc(1, sizeof(*ctx));
674 [ # # ]: 0 : if (ctx == NULL) {
675 : 0 : return -ENOMEM;
676 : : }
677 : :
678 [ # # ]: 0 : TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
679 : 0 : ++ctx->num_modules;
680 : : }
681 : :
682 : 0 : ctx->modules = calloc(ctx->num_modules, sizeof(struct spdk_iobuf_module_stats));
683 [ # # ]: 0 : if (ctx->modules == NULL) {
684 : 0 : free(ctx);
685 : 0 : return -ENOMEM;
686 : : }
687 : :
688 : 0 : i = 0;
689 [ # # ]: 0 : TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
690 : 0 : ctx->modules[i].module = module->name;
691 : 0 : ++i;
692 : : }
693 : :
694 : 0 : ctx->cb_fn = cb_fn;
695 : 0 : ctx->cb_arg = cb_arg;
696 : :
697 : 0 : spdk_for_each_channel(&g_iobuf, iobuf_get_channel_stats, ctx,
698 : : iobuf_get_channel_stats_done);
699 : 0 : return 0;
700 : : }
|