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 accommodate
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 : 7147 : iobuf_channel_create_cb(void *io_device, void *ctx)
77 : : {
78 : 7147 : struct iobuf_channel *ch = ctx;
79 : :
80 [ + - + - : 7147 : STAILQ_INIT(&ch->small_queue);
+ - + - +
- + - + -
+ - ]
81 [ + - + - : 7147 : STAILQ_INIT(&ch->large_queue);
+ - + - +
- + - + -
+ - ]
82 : :
83 : 7147 : return 0;
84 : : }
85 : :
86 : : static void
87 : 7147 : iobuf_channel_destroy_cb(void *io_device, void *ctx)
88 : : {
89 : 7147 : struct iobuf_channel *ch __attribute__((unused)) = ctx;
90 : :
91 [ + + + - : 7147 : assert(STAILQ_EMPTY(&ch->small_queue));
+ - + - #
# ]
92 [ + + + - : 7147 : assert(STAILQ_EMPTY(&ch->large_queue));
+ - + - #
# ]
93 : 7147 : }
94 : :
95 : : int
96 : 2301 : spdk_iobuf_initialize(void)
97 : : {
98 : 2301 : struct spdk_iobuf_opts *opts = &g_iobuf.opts;
99 : 2301 : int rc = 0;
100 : : uint64_t i;
101 : 1045 : struct spdk_iobuf_buffer *buf;
102 : :
103 [ + - + - ]: 2301 : g_iobuf.small_pool = spdk_ring_create(SPDK_RING_TYPE_MP_MC, opts->small_pool_count,
104 : : SPDK_ENV_NUMA_ID_ANY);
105 [ + + ]: 2301 : 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 [ + - + - : 2301 : opts->small_bufsize = SPDK_ALIGN_CEIL(opts->small_bufsize, IOBUF_ALIGNMENT);
+ - + - ]
113 [ + - + - : 2301 : g_iobuf.small_pool_base = spdk_malloc(opts->small_bufsize * opts->small_pool_count, IOBUF_ALIGNMENT,
+ - + - +
- ]
114 : : NULL, SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_DMA);
115 [ + + + - ]: 2301 : 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 [ + - + - : 2301 : g_iobuf.large_pool = spdk_ring_create(SPDK_RING_TYPE_MP_MC, opts->large_pool_count,
+ - ]
122 : : SPDK_ENV_NUMA_ID_ANY);
123 [ + + + - ]: 2301 : 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 [ - + - + : 2301 : opts->large_bufsize = SPDK_ALIGN_CEIL(opts->large_bufsize, IOBUF_ALIGNMENT);
- + - + ]
131 [ - + - + : 2301 : g_iobuf.large_pool_base = spdk_malloc(opts->large_bufsize * opts->large_pool_count, IOBUF_ALIGNMENT,
- + - + -
+ ]
132 : : NULL, SPDK_ENV_NUMA_ID_ANY, SPDK_MALLOC_DMA);
133 [ - + + - ]: 2301 : 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 [ + + + - : 18950419 : for (i = 0; i < opts->small_pool_count; i++) {
+ + ]
140 [ + - + - : 18948118 : buf = g_iobuf.small_pool_base + i * opts->small_bufsize;
+ - ]
141 : 18948118 : spdk_ring_enqueue(g_iobuf.small_pool, (void **)&buf, 1, NULL);
142 : 475136 : }
143 : :
144 [ + + + - : 2368437 : for (i = 0; i < opts->large_pool_count; i++) {
+ + ]
145 [ + - + - : 2366136 : buf = g_iobuf.large_pool_base + i * opts->large_bufsize;
+ - ]
146 [ + - ]: 2366136 : spdk_ring_enqueue(g_iobuf.large_pool, (void **)&buf, 1, NULL);
147 : 59392 : }
148 : :
149 : 2301 : spdk_io_device_register(&g_iobuf, iobuf_channel_create_cb, iobuf_channel_destroy_cb,
150 : : sizeof(struct iobuf_channel), "iobuf");
151 : 2301 : g_iobuf_is_initialized = true;
152 : :
153 : 2301 : 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 : 58 : }
162 : :
163 : : static void
164 : 2301 : iobuf_unregister_cb(void *io_device)
165 : : {
166 : : struct iobuf_module *module;
167 : :
168 [ + + + - : 6636 : while (!TAILQ_EMPTY(&g_iobuf.modules)) {
+ + ]
169 [ + - + - ]: 4335 : module = TAILQ_FIRST(&g_iobuf.modules);
170 [ + + + - : 4335 : TAILQ_REMOVE(&g_iobuf.modules, module, tailq);
+ - + + +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
171 [ + - + - ]: 4335 : free(module->name);
172 : 4335 : free(module);
173 : : }
174 : :
175 [ + + + - : 2301 : 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 : 0 : }
179 : :
180 [ + + + - : 2301 : 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 : 0 : }
184 : :
185 [ + - ]: 2301 : spdk_free(g_iobuf.small_pool_base);
186 [ + - ]: 2301 : g_iobuf.small_pool_base = NULL;
187 : 2301 : spdk_ring_free(g_iobuf.small_pool);
188 : 2301 : g_iobuf.small_pool = NULL;
189 : :
190 [ + - ]: 2301 : spdk_free(g_iobuf.large_pool_base);
191 [ + - ]: 2301 : g_iobuf.large_pool_base = NULL;
192 [ + - ]: 2301 : spdk_ring_free(g_iobuf.large_pool);
193 [ + - ]: 2301 : g_iobuf.large_pool = NULL;
194 : :
195 [ + - + - ]: 2301 : if (g_iobuf.finish_cb != NULL) {
196 [ + - - + : 2301 : g_iobuf.finish_cb(g_iobuf.finish_arg);
+ - + - ]
197 : 58 : }
198 : 2301 : }
199 : :
200 : : void
201 : 2301 : spdk_iobuf_finish(spdk_iobuf_finish_cb cb_fn, void *cb_arg)
202 : : {
203 [ + + + + ]: 2301 : if (!g_iobuf_is_initialized) {
204 [ # # # # ]: 0 : cb_fn(cb_arg);
205 : 0 : return;
206 : : }
207 : :
208 : 2301 : g_iobuf_is_initialized = false;
209 [ + - ]: 2301 : g_iobuf.finish_cb = cb_fn;
210 [ + - ]: 2301 : g_iobuf.finish_arg = cb_arg;
211 : :
212 : 2301 : spdk_io_device_unregister(&g_iobuf, iobuf_unregister_cb);
213 : 58 : }
214 : :
215 : : int
216 : 229 : spdk_iobuf_set_opts(const struct spdk_iobuf_opts *opts)
217 : : {
218 [ + + ]: 229 : if (!opts) {
219 : 0 : SPDK_ERRLOG("opts cannot be NULL\n");
220 : 0 : return -1;
221 : : }
222 : :
223 [ + + + - : 229 : if (!opts->opts_size) {
+ - ]
224 : 0 : SPDK_ERRLOG("opts_size inside opts cannot be zero value\n");
225 : 0 : return -1;
226 : : }
227 : :
228 [ + + + - : 229 : 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 [ + + + - : 229 : 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 [ + + + - : 229 : 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 [ + + + - : 229 : 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 [ + - + - : 229 : SET_FIELD(small_pool_count);
- + - + -
+ - + -
+ ]
257 [ + - + - : 229 : SET_FIELD(large_pool_count);
- + - + -
+ - + -
+ ]
258 [ + - + - : 229 : SET_FIELD(small_bufsize);
- + - + -
+ - + -
+ ]
259 [ + - + - : 229 : SET_FIELD(large_bufsize);
- + - + -
+ - + -
+ ]
260 : :
261 [ + - + - : 229 : g_iobuf.opts.opts_size = opts->opts_size;
+ - + - ]
262 : :
263 : : #undef SET_FIELD
264 : :
265 : 229 : return 0;
266 : 1 : }
267 : :
268 : : void
269 : 8402 : spdk_iobuf_get_opts(struct spdk_iobuf_opts *opts, size_t opts_size)
270 : : {
271 [ + + ]: 8402 : if (!opts) {
272 : 0 : SPDK_ERRLOG("opts should not be NULL\n");
273 : 0 : return;
274 : : }
275 : :
276 [ + + ]: 8402 : if (!opts_size) {
277 : 0 : SPDK_ERRLOG("opts_size should not be zero value\n");
278 : 0 : return;
279 : : }
280 : :
281 [ + - + - ]: 8402 : 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 [ + + + - : 8402 : SET_FIELD(small_pool_count);
+ - + - +
- ]
289 [ + + + - : 8402 : SET_FIELD(large_pool_count);
+ - + - +
- ]
290 [ + + + - : 8402 : SET_FIELD(small_bufsize);
+ - + - +
- ]
291 [ + + + - : 8402 : 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 : 123 : }
299 : :
300 : :
301 : : int
302 : 22564 : 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 : 5947 : struct spdk_iobuf_buffer *buf;
309 : : uint32_t i;
310 : :
311 [ + - + - : 36770 : TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
- + + - +
- + - ]
312 [ + + + + : 36770 : if (strcmp(name, module->name) == 0) {
+ + + - +
+ ]
313 : 22564 : break;
314 : : }
315 : 150 : }
316 : :
317 [ + + ]: 22564 : if (module == NULL) {
318 : 0 : SPDK_ERRLOG("Couldn't find iobuf module: '%s'\n", name);
319 : 0 : return -ENODEV;
320 : : }
321 : :
322 : 22564 : ioch = spdk_get_io_channel(&g_iobuf);
323 [ + + ]: 22564 : if (ioch == NULL) {
324 : 0 : SPDK_ERRLOG("Couldn't get iobuf IO channel\n");
325 : 0 : return -ENOMEM;
326 : : }
327 : :
328 : 22564 : iobuf_ch = spdk_io_channel_get_ctx(ioch);
329 : :
330 [ + + ]: 44652 : for (i = 0; i < IOBUF_MAX_CHANNELS; ++i) {
331 [ + + + - : 44652 : if (iobuf_ch->channels[i] == NULL) {
+ - + + ]
332 [ + - + - : 22564 : iobuf_ch->channels[i] = ch;
+ - ]
333 : 22564 : break;
334 : : }
335 : 148 : }
336 : :
337 [ - + ]: 22564 : 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 [ + - + - : 22564 : ch->small.queue = &iobuf_ch->small_queue;
+ - + - ]
343 [ + - + - : 22564 : ch->large.queue = &iobuf_ch->large_queue;
+ - + - ]
344 [ + - + - : 22564 : ch->small.pool = g_iobuf.small_pool;
+ - ]
345 [ + - + - : 22564 : ch->large.pool = g_iobuf.large_pool;
+ - + - ]
346 [ + - + - : 22564 : ch->small.bufsize = g_iobuf.opts.small_bufsize;
+ - + - +
- ]
347 [ + - + - : 22564 : ch->large.bufsize = g_iobuf.opts.large_bufsize;
+ - + - +
- ]
348 [ + - + - ]: 22564 : ch->parent = ioch;
349 [ + - + - ]: 22564 : ch->module = module;
350 [ + - + - : 22564 : ch->small.cache_size = small_cache_size;
+ - ]
351 [ + - + - : 22564 : ch->large.cache_size = large_cache_size;
+ - ]
352 [ + - + - : 22564 : ch->small.cache_count = 0;
+ - ]
353 [ + - + - : 22564 : ch->large.cache_count = 0;
+ - ]
354 : :
355 [ + - + - : 22564 : STAILQ_INIT(&ch->small.cache);
+ - + - +
- + - + -
+ - + - +
- + - ]
356 [ + - + - : 22564 : STAILQ_INIT(&ch->large.cache);
+ - + - +
- + - + -
+ - + - +
- + - ]
357 : :
358 [ + + ]: 2959599 : for (i = 0; i < small_cache_size; ++i) {
359 [ + + ]: 2937041 : if (spdk_ring_dequeue(g_iobuf.small_pool, (void **)&buf, 1) == 0) {
360 [ # # # # ]: 6 : 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 : 6 : SPDK_ERRLOG("See scripts/calc-iobuf.py for guidance on how to calculate "
364 : : "this value.\n");
365 : 6 : goto error;
366 : : }
367 [ + - + - : 2937035 : STAILQ_INSERT_TAIL(&ch->small.cache, buf, stailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
368 [ + - + - ]: 2937035 : ch->small.cache_count++;
369 : 23038 : }
370 [ + + ]: 417058 : for (i = 0; i < large_cache_size; ++i) {
371 [ + + + - ]: 394503 : if (spdk_ring_dequeue(g_iobuf.large_pool, (void **)&buf, 1) == 0) {
372 [ # # # # ]: 3 : 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 : 3 : SPDK_ERRLOG("See scripts/calc-iobuf.py for guidance on how to calculate "
376 : : "this value.\n");
377 : 3 : goto error;
378 : : }
379 [ + - + - : 394500 : STAILQ_INSERT_TAIL(&ch->large.cache, buf, stailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - ]
380 [ + - + - ]: 394500 : ch->large.cache_count++;
381 : 3422 : }
382 : :
383 : 22555 : return 0;
384 : 9 : error:
385 : 9 : spdk_iobuf_channel_fini(ch);
386 : :
387 : 9 : return -ENOMEM;
388 : 200 : }
389 : :
390 : : void
391 : 22564 : spdk_iobuf_channel_fini(struct spdk_iobuf_channel *ch)
392 : : {
393 : : struct spdk_iobuf_entry *entry __attribute__((unused));
394 : 5947 : 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 [ + + + - : 22564 : STAILQ_FOREACH(entry, ch->small.queue, stailq) {
+ - + - +
- - + # #
# # # # ]
400 [ # # # # : 0 : assert(entry->module != ch->module);
# # # # #
# # # ]
401 : 0 : }
402 [ + + + - : 22564 : STAILQ_FOREACH(entry, ch->large.queue, stailq) {
+ - + - +
- - + # #
# # # # ]
403 [ # # # # : 0 : assert(entry->module != ch->module);
# # # # #
# # # ]
404 : 0 : }
405 : :
406 : : /* Release cached buffers back to the pool */
407 [ + + + - : 2959621 : while (!STAILQ_EMPTY(&ch->small.cache)) {
+ - + - +
+ ]
408 [ + - + - : 2937057 : buf = STAILQ_FIRST(&ch->small.cache);
+ - + - ]
409 [ + + + - : 2937057 : STAILQ_REMOVE_HEAD(&ch->small.cache, stailq);
+ - + - +
- + - + -
+ - + - +
- + - + +
+ - + - +
- + - + -
+ - + - ]
410 : 2937057 : spdk_ring_enqueue(g_iobuf.small_pool, (void **)&buf, 1, NULL);
411 [ + - + - ]: 2937057 : ch->small.cache_count--;
412 : : }
413 [ + + + - : 417112 : while (!STAILQ_EMPTY(&ch->large.cache)) {
+ - + - +
+ ]
414 [ + - + - : 394548 : buf = STAILQ_FIRST(&ch->large.cache);
+ - + - ]
415 [ + + + - : 394548 : STAILQ_REMOVE_HEAD(&ch->large.cache, stailq);
+ - + - +
- + - + -
+ - + - +
- + - + +
+ - + - +
- + - + -
+ - + - ]
416 [ + - ]: 394548 : spdk_ring_enqueue(g_iobuf.large_pool, (void **)&buf, 1, NULL);
417 [ + - + - ]: 394548 : ch->large.cache_count--;
418 : : }
419 : :
420 [ + + + - : 22564 : assert(ch->small.cache_count == 0);
+ - + - #
# ]
421 [ + + + - : 22564 : assert(ch->large.cache_count == 0);
+ - + - #
# ]
422 : :
423 [ + - + - ]: 22564 : iobuf_ch = spdk_io_channel_get_ctx(ch->parent);
424 [ + + ]: 44652 : for (i = 0; i < IOBUF_MAX_CHANNELS; ++i) {
425 [ + + + - : 44652 : if (iobuf_ch->channels[i] == ch) {
+ - + + ]
426 [ + - + - : 22564 : iobuf_ch->channels[i] = NULL;
+ - ]
427 : 22564 : break;
428 : : }
429 : 148 : }
430 : :
431 [ + - + - ]: 22564 : spdk_put_io_channel(ch->parent);
432 [ + - + - ]: 22564 : ch->parent = NULL;
433 : 22564 : }
434 : :
435 : : int
436 : 4674 : spdk_iobuf_register_module(const char *name)
437 : : {
438 : : struct iobuf_module *module;
439 : :
440 [ + + + - : 7384 : TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
+ + + - +
- + - ]
441 [ + + + + : 2711 : if (strcmp(name, module->name) == 0) {
+ + + - +
- ]
442 : 1 : return -EEXIST;
443 : : }
444 : 126 : }
445 : :
446 : 4673 : module = calloc(1, sizeof(*module));
447 [ + + ]: 4673 : if (module == NULL) {
448 : 0 : return -ENOMEM;
449 : : }
450 : :
451 [ + + + - : 4673 : module->name = strdup(name);
+ - ]
452 [ + + + - : 4673 : if (module->name == NULL) {
+ - ]
453 : 0 : free(module);
454 : 0 : return -ENOMEM;
455 : : }
456 : :
457 [ + - + - : 4673 : TAILQ_INSERT_TAIL(&g_iobuf.modules, module, tailq);
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
458 : :
459 : 4673 : return 0;
460 : 150 : }
461 : :
462 : : int
463 : 335 : spdk_iobuf_unregister_module(const char *name)
464 : : {
465 : : struct iobuf_module *module;
466 : :
467 [ + - + - : 1005 : TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
+ - + - +
- + - ]
468 [ + + + + : 1005 : if (strcmp(name, module->name) == 0) {
+ + + - +
+ ]
469 [ + + + - : 335 : TAILQ_REMOVE(&g_iobuf.modules, module, tailq);
+ - - + #
# # # # #
# # # # #
# # # # #
# # - + -
+ - + - +
- + + - +
- + - + -
+ - + - +
- ]
470 [ + - + - ]: 335 : free(module->name);
471 : 335 : free(module);
472 : 335 : return 0;
473 : : }
474 : 68 : }
475 : :
476 : 0 : return -ENOENT;
477 : 34 : }
478 : :
479 : : int
480 : 280316 : 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 [ + + + - : 280364 : 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 [ + + # # : 48 : if (entry->module != ch->module) {
# # # # #
# ]
489 : 24 : continue;
490 : : }
491 : :
492 [ # # # # ]: 24 : rc = cb_fn(ch, entry, cb_ctx);
493 [ - + ]: 24 : if (rc != 0) {
494 : 0 : return rc;
495 : : }
496 : 0 : }
497 : :
498 : 280316 : return 0;
499 : 188 : }
500 : :
501 : : void
502 : 36 : 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 [ + + # # : 36 : if (len <= ch->small.bufsize) {
# # # # ]
508 [ # # ]: 18 : pool = &ch->small;
509 : 0 : } else {
510 [ - + # # : 18 : assert(len <= ch->large.bufsize);
# # # # #
# ]
511 [ # # ]: 18 : pool = &ch->large;
512 : : }
513 : :
514 [ + - + + : 36 : STAILQ_REMOVE(pool->queue, entry, spdk_iobuf_entry, stailq);
- - - - #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
515 : 36 : }
516 : :
517 : : #define IOBUF_BATCH_SIZE 32
518 : :
519 : : void *
520 : 61939895 : 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 [ + + + - : 61939895 : assert(spdk_io_channel_get_thread(ch->parent) == spdk_get_thread());
+ - # # ]
527 [ + + + - : 61939895 : if (len <= ch->small.bufsize) {
+ - + - ]
528 [ + - ]: 60201450 : pool = &ch->small;
529 : 4090 : } else {
530 [ - + # # : 1738445 : assert(len <= ch->large.bufsize);
# # # # #
# ]
531 [ # # ]: 1738445 : pool = &ch->large;
532 : : }
533 : :
534 [ + - + - : 61939895 : buf = (void *)STAILQ_FIRST(&pool->cache);
+ - ]
535 [ + + ]: 61939895 : if (buf) {
536 [ + + + - : 54367552 : STAILQ_REMOVE_HEAD(&pool->cache, stailq);
+ - + - +
- + - + -
+ - + - -
+ # # # #
# # # # #
# ]
537 [ + + + - : 54367552 : assert(pool->cache_count > 0);
+ - # # ]
538 [ + - ]: 54367552 : pool->cache_count--;
539 [ + - + - ]: 54367552 : pool->stats.cache++;
540 : 4090 : } else {
541 : 43086 : 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 [ + + # # : 7572343 : sz = spdk_ring_dequeue(pool->pool, (void **)bufs, spdk_min(IOBUF_BATCH_SIZE,
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
546 : : spdk_max(pool->cache_size, 1)));
547 [ + + ]: 7572343 : if (sz == 0) {
548 [ + + ]: 7436583 : if (entry) {
549 [ # # # # : 5610530 : STAILQ_INSERT_TAIL(pool->queue, entry, stailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
550 [ # # # # : 5610530 : entry->module = ch->module;
# # # # ]
551 [ # # # # ]: 5610530 : entry->cb_fn = cb_fn;
552 [ # # # # ]: 5610530 : pool->stats.retry++;
553 : 0 : }
554 : :
555 : 7436583 : return NULL;
556 : : }
557 : :
558 [ # # # # ]: 135760 : pool->stats.main++;
559 [ + + ]: 3868648 : for (i = 0; i < (sz - 1); i++) {
560 [ + + # # : 3732888 : STAILQ_INSERT_HEAD(&pool->cache, bufs[i], stailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
561 [ # # ]: 3732888 : pool->cache_count++;
562 : 0 : }
563 : :
564 : : /* The last one is the one we'll return */
565 [ # # # # : 135760 : buf = bufs[i];
# # ]
566 : : }
567 : :
568 : 54503312 : return (char *)buf;
569 : 4090 : }
570 : :
571 : : void
572 : 60113806 : 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 [ + + + - : 60113806 : assert(spdk_io_channel_get_thread(ch->parent) == spdk_get_thread());
+ - # # ]
580 [ + + + - : 60113806 : if (len <= ch->small.bufsize) {
+ - + - ]
581 [ + - ]: 58375379 : pool = &ch->small;
582 : 4090 : } else {
583 [ # # ]: 1738427 : pool = &ch->large;
584 : : }
585 : :
586 [ + + + - : 60113806 : if (STAILQ_EMPTY(pool->queue)) {
+ - + - -
+ ]
587 [ + + + - : 54503312 : if (pool->cache_size == 0) {
+ - ]
588 [ # # # # ]: 54 : spdk_ring_enqueue(pool->pool, (void **)&buf, 1, NULL);
589 : 54 : return;
590 : : }
591 : :
592 : 54503258 : iobuf_buf = (struct spdk_iobuf_buffer *)buf;
593 : :
594 [ + + + - : 54503258 : STAILQ_INSERT_HEAD(&pool->cache, iobuf_buf, stailq);
+ - + - +
- + - + -
# # # # #
# # # # #
+ - + - +
- ]
595 [ + - ]: 54503258 : 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 [ + - + - : 54503258 : sz = spdk_min(IOBUF_BATCH_SIZE, pool->cache_size);
- + + - +
- ]
601 [ + + + - : 54503258 : if (pool->cache_count >= pool->cache_size + sz) {
+ - + - +
- ]
602 : 10994 : struct spdk_iobuf_buffer *bufs[IOBUF_BATCH_SIZE];
603 : : size_t i;
604 : :
605 [ + + ]: 4004219 : for (i = 0; i < sz; i++) {
606 [ # # # # : 3868524 : bufs[i] = STAILQ_FIRST(&pool->cache);
# # # # #
# # # ]
607 [ - + # # : 3868524 : STAILQ_REMOVE_HEAD(&pool->cache, stailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
608 [ - + # # : 3868524 : assert(pool->cache_count > 0);
# # # # ]
609 [ # # ]: 3868524 : pool->cache_count--;
610 : 0 : }
611 : :
612 [ # # # # ]: 135695 : spdk_ring_enqueue(pool->pool, (void **)bufs, sz, NULL);
613 : 0 : }
614 : 4090 : } else {
615 [ # # # # : 5610494 : entry = STAILQ_FIRST(pool->queue);
# # # # ]
616 [ + + # # : 5610494 : STAILQ_REMOVE_HEAD(pool->queue, stailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
617 [ # # # # : 5610494 : entry->cb_fn(entry, buf);
# # # # ]
618 [ + + + + : 5610494 : if (spdk_unlikely(entry == STAILQ_LAST(pool->queue, spdk_iobuf_entry, stailq))) {
# # # # #
# # # # #
# # # # #
# ]
619 [ + + + - : 897194486 : STAILQ_REMOVE(pool->queue, entry, spdk_iobuf_entry, stailq);
+ + + - #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # ]
620 [ + + # # : 5217199 : STAILQ_INSERT_HEAD(pool->queue, entry, stailq);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
621 : 0 : }
622 : : }
623 : 4090 : }
624 : :
625 : : static void
626 : 3 : iobuf_get_channel_stats_done(struct spdk_io_channel_iter *iter, int status)
627 : : {
628 : 3 : struct iobuf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(iter);
629 : :
630 [ # # # # : 3 : ctx->cb_fn(ctx->modules, ctx->num_modules, ctx->cb_arg);
# # # # #
# # # # #
# # # # #
# ]
631 [ # # # # ]: 3 : free(ctx->modules);
632 : 3 : free(ctx);
633 : 3 : }
634 : :
635 : : static void
636 : 3 : iobuf_get_channel_stats(struct spdk_io_channel_iter *iter)
637 : : {
638 : 3 : struct iobuf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(iter);
639 : 3 : struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(iter);
640 : 3 : struct iobuf_channel *iobuf_ch = spdk_io_channel_get_ctx(ch);
641 : : struct spdk_iobuf_channel *channel;
642 : : struct iobuf_module *module;
643 : : struct spdk_iobuf_module_stats *it;
644 : : uint32_t i, j;
645 : :
646 [ + + # # : 12 : for (i = 0; i < ctx->num_modules; ++i) {
# # ]
647 [ + - ]: 18 : for (j = 0; j < IOBUF_MAX_CHANNELS; ++j) {
648 [ # # # # : 18 : channel = iobuf_ch->channels[j];
# # ]
649 [ - + ]: 18 : if (channel == NULL) {
650 : 0 : continue;
651 : : }
652 : :
653 [ # # # # : 18 : it = &ctx->modules[i];
# # ]
654 [ # # # # ]: 18 : module = (struct iobuf_module *)channel->module;
655 [ - + - + : 18 : if (strcmp(it->module, module->name) == 0) {
+ + # # #
# # # #
# ]
656 [ # # # # : 9 : it->small_pool.cache += channel->small.stats.cache;
# # # # #
# # # #
# ]
657 [ # # # # : 9 : it->small_pool.main += channel->small.stats.main;
# # # # #
# # # #
# ]
658 [ # # # # : 9 : it->small_pool.retry += channel->small.stats.retry;
# # # # #
# # # #
# ]
659 [ # # # # : 9 : it->large_pool.cache += channel->large.stats.cache;
# # # # #
# # # #
# ]
660 [ # # # # : 9 : it->large_pool.main += channel->large.stats.main;
# # # # #
# # # #
# ]
661 [ # # # # : 9 : it->large_pool.retry += channel->large.stats.retry;
# # # # #
# # # #
# ]
662 : 9 : break;
663 : : }
664 : 0 : }
665 : 0 : }
666 : :
667 : 3 : spdk_for_each_channel_continue(iter, 0);
668 : 3 : }
669 : :
670 : : int
671 : 3 : spdk_iobuf_get_stats(spdk_iobuf_get_stats_cb cb_fn, void *cb_arg)
672 : : {
673 : : struct iobuf_module *module;
674 : : struct iobuf_get_stats_ctx *ctx;
675 : : uint32_t i;
676 : :
677 : 3 : ctx = calloc(1, sizeof(*ctx));
678 [ - + ]: 3 : if (ctx == NULL) {
679 : 0 : return -ENOMEM;
680 : : }
681 : :
682 [ + + # # : 12 : TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
# # # # #
# # # ]
683 [ # # ]: 9 : ++ctx->num_modules;
684 : 0 : }
685 : :
686 [ # # # # : 3 : ctx->modules = calloc(ctx->num_modules, sizeof(struct spdk_iobuf_module_stats));
# # # # ]
687 [ - + # # : 3 : if (ctx->modules == NULL) {
# # ]
688 : 0 : free(ctx);
689 : 0 : return -ENOMEM;
690 : : }
691 : :
692 : 3 : i = 0;
693 [ + + # # : 12 : TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
# # # # #
# # # ]
694 [ # # # # : 9 : ctx->modules[i].module = module->name;
# # # # #
# # # #
# ]
695 : 9 : ++i;
696 : 0 : }
697 : :
698 [ # # # # ]: 3 : ctx->cb_fn = cb_fn;
699 [ # # # # ]: 3 : ctx->cb_arg = cb_arg;
700 : :
701 : 3 : spdk_for_each_channel(&g_iobuf, iobuf_get_channel_stats, ctx,
702 : : iobuf_get_channel_stats_done);
703 : 3 : return 0;
704 : 0 : }
|