LCOV - code coverage report
Current view: top level - spdk/lib/thread - iobuf.c (source / functions) Hit Total Coverage
Test: Combined Lines: 218 304 71.7 %
Date: 2024-07-12 00:10:58 Functions: 15 18 83.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 118 188 62.8 %

           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                 :            : struct iobuf_channel {
      31                 :            :         spdk_iobuf_entry_stailq_t       small_queue;
      32                 :            :         spdk_iobuf_entry_stailq_t       large_queue;
      33                 :            :         struct spdk_iobuf_channel       *channels[IOBUF_MAX_CHANNELS];
      34                 :            : };
      35                 :            : 
      36                 :            : struct iobuf_module {
      37                 :            :         char                            *name;
      38                 :            :         TAILQ_ENTRY(iobuf_module)       tailq;
      39                 :            : };
      40                 :            : 
      41                 :            : struct iobuf {
      42                 :            :         struct spdk_ring                *small_pool;
      43                 :            :         struct spdk_ring                *large_pool;
      44                 :            :         void                            *small_pool_base;
      45                 :            :         void                            *large_pool_base;
      46                 :            :         struct spdk_iobuf_opts          opts;
      47                 :            :         TAILQ_HEAD(, iobuf_module)      modules;
      48                 :            :         spdk_iobuf_finish_cb            finish_cb;
      49                 :            :         void                            *finish_arg;
      50                 :            : };
      51                 :            : 
      52                 :            : static struct iobuf g_iobuf = {
      53                 :            :         .modules = TAILQ_HEAD_INITIALIZER(g_iobuf.modules),
      54                 :            :         .small_pool = NULL,
      55                 :            :         .large_pool = NULL,
      56                 :            :         .small_pool_base = NULL,
      57                 :            :         .large_pool_base = NULL,
      58                 :            :         .opts = {
      59                 :            :                 .small_pool_count = IOBUF_DEFAULT_SMALL_POOL_SIZE,
      60                 :            :                 .large_pool_count = IOBUF_DEFAULT_LARGE_POOL_SIZE,
      61                 :            :                 .small_bufsize = IOBUF_DEFAULT_SMALL_BUFSIZE,
      62                 :            :                 .large_bufsize = IOBUF_DEFAULT_LARGE_BUFSIZE,
      63                 :            :         },
      64                 :            : };
      65                 :            : 
      66                 :            : struct iobuf_get_stats_ctx {
      67                 :            :         struct spdk_iobuf_module_stats  *modules;
      68                 :            :         uint32_t                        num_modules;
      69                 :            :         spdk_iobuf_get_stats_cb         cb_fn;
      70                 :            :         void                            *cb_arg;
      71                 :            : };
      72                 :            : 
      73                 :            : static int
      74                 :       8775 : iobuf_channel_create_cb(void *io_device, void *ctx)
      75                 :            : {
      76                 :       8775 :         struct iobuf_channel *ch = ctx;
      77                 :            : 
      78                 :       8775 :         STAILQ_INIT(&ch->small_queue);
      79                 :       8775 :         STAILQ_INIT(&ch->large_queue);
      80                 :            : 
      81                 :       8775 :         return 0;
      82                 :            : }
      83                 :            : 
      84                 :            : static void
      85                 :       8775 : iobuf_channel_destroy_cb(void *io_device, void *ctx)
      86                 :            : {
      87                 :       8775 :         struct iobuf_channel *ch __attribute__((unused)) = ctx;
      88                 :            : 
      89         [ -  + ]:       8775 :         assert(STAILQ_EMPTY(&ch->small_queue));
      90         [ -  + ]:       8775 :         assert(STAILQ_EMPTY(&ch->large_queue));
      91                 :       8775 : }
      92                 :            : 
      93                 :            : int
      94                 :       3261 : spdk_iobuf_initialize(void)
      95                 :            : {
      96                 :       3261 :         struct spdk_iobuf_opts *opts = &g_iobuf.opts;
      97                 :       3261 :         int rc = 0;
      98                 :            :         uint64_t i;
      99                 :       1695 :         struct spdk_iobuf_buffer *buf;
     100                 :            : 
     101                 :       3261 :         g_iobuf.small_pool = spdk_ring_create(SPDK_RING_TYPE_MP_MC, opts->small_pool_count,
     102                 :            :                                               SPDK_ENV_SOCKET_ID_ANY);
     103         [ -  + ]:       3261 :         if (!g_iobuf.small_pool) {
     104                 :          0 :                 SPDK_ERRLOG("Failed to create small iobuf pool\n");
     105                 :          0 :                 rc = -ENOMEM;
     106                 :          0 :                 goto error;
     107                 :            :         }
     108                 :            : 
     109                 :            :         /* Round up to the nearest alignment so that each element remains aligned */
     110                 :       3261 :         opts->small_bufsize = SPDK_ALIGN_CEIL(opts->small_bufsize, IOBUF_ALIGNMENT);
     111                 :       3261 :         g_iobuf.small_pool_base = spdk_malloc(opts->small_bufsize * opts->small_pool_count, IOBUF_ALIGNMENT,
     112                 :            :                                               NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
     113         [ -  + ]:       3261 :         if (g_iobuf.small_pool_base == NULL) {
     114                 :          0 :                 SPDK_ERRLOG("Unable to allocate requested small iobuf pool size\n");
     115                 :          0 :                 rc = -ENOMEM;
     116                 :          0 :                 goto error;
     117                 :            :         }
     118                 :            : 
     119                 :       3261 :         g_iobuf.large_pool = spdk_ring_create(SPDK_RING_TYPE_MP_MC, opts->large_pool_count,
     120                 :            :                                               SPDK_ENV_SOCKET_ID_ANY);
     121         [ -  + ]:       3261 :         if (!g_iobuf.large_pool) {
     122                 :          0 :                 SPDK_ERRLOG("Failed to create large iobuf pool\n");
     123                 :          0 :                 rc = -ENOMEM;
     124                 :          0 :                 goto error;
     125                 :            :         }
     126                 :            : 
     127                 :            :         /* Round up to the nearest alignment so that each element remains aligned */
     128                 :       3261 :         opts->large_bufsize = SPDK_ALIGN_CEIL(opts->large_bufsize, IOBUF_ALIGNMENT);
     129                 :       3261 :         g_iobuf.large_pool_base = spdk_malloc(opts->large_bufsize * opts->large_pool_count, IOBUF_ALIGNMENT,
     130                 :            :                                               NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
     131         [ -  + ]:       3261 :         if (g_iobuf.large_pool_base == NULL) {
     132                 :          0 :                 SPDK_ERRLOG("Unable to allocate requested large iobuf pool size\n");
     133                 :          0 :                 rc = -ENOMEM;
     134                 :          0 :                 goto error;
     135                 :            :         }
     136                 :            : 
     137         [ +  + ]:   26829713 :         for (i = 0; i < opts->small_pool_count; i++) {
     138                 :   26826448 :                 buf = g_iobuf.small_pool_base + i * opts->small_bufsize;
     139                 :   26826448 :                 spdk_ring_enqueue(g_iobuf.small_pool, (void **)&buf, 1, NULL);
     140                 :            :         }
     141                 :            : 
     142         [ +  + ]:    3349985 :         for (i = 0; i < opts->large_pool_count; i++) {
     143                 :    3346724 :                 buf = g_iobuf.large_pool_base + i * opts->large_bufsize;
     144                 :    3346724 :                 spdk_ring_enqueue(g_iobuf.large_pool, (void **)&buf, 1, NULL);
     145                 :            :         }
     146                 :            : 
     147                 :       3261 :         spdk_io_device_register(&g_iobuf, iobuf_channel_create_cb, iobuf_channel_destroy_cb,
     148                 :            :                                 sizeof(struct iobuf_channel), "iobuf");
     149                 :            : 
     150                 :       3261 :         return 0;
     151                 :          0 : error:
     152                 :          0 :         spdk_free(g_iobuf.small_pool_base);
     153                 :          0 :         spdk_ring_free(g_iobuf.small_pool);
     154                 :          0 :         spdk_free(g_iobuf.large_pool_base);
     155                 :          0 :         spdk_ring_free(g_iobuf.large_pool);
     156                 :            : 
     157                 :          0 :         return rc;
     158                 :            : }
     159                 :            : 
     160                 :            : static void
     161                 :       3261 : iobuf_unregister_cb(void *io_device)
     162                 :            : {
     163                 :            :         struct iobuf_module *module;
     164                 :            : 
     165         [ +  + ]:       8527 :         while (!TAILQ_EMPTY(&g_iobuf.modules)) {
     166                 :       5266 :                 module = TAILQ_FIRST(&g_iobuf.modules);
     167         [ +  + ]:       5266 :                 TAILQ_REMOVE(&g_iobuf.modules, module, tailq);
     168                 :       5266 :                 free(module->name);
     169                 :       5266 :                 free(module);
     170                 :            :         }
     171                 :            : 
     172         [ -  + ]:       3261 :         if (spdk_ring_count(g_iobuf.small_pool) != g_iobuf.opts.small_pool_count) {
     173                 :          0 :                 SPDK_ERRLOG("small iobuf pool count is %zu, expected %"PRIu64"\n",
     174                 :            :                             spdk_ring_count(g_iobuf.small_pool), g_iobuf.opts.small_pool_count);
     175                 :            :         }
     176                 :            : 
     177         [ -  + ]:       3261 :         if (spdk_ring_count(g_iobuf.large_pool) != g_iobuf.opts.large_pool_count) {
     178                 :          0 :                 SPDK_ERRLOG("large iobuf pool count is %zu, expected %"PRIu64"\n",
     179                 :            :                             spdk_ring_count(g_iobuf.large_pool), g_iobuf.opts.large_pool_count);
     180                 :            :         }
     181                 :            : 
     182                 :       3261 :         spdk_free(g_iobuf.small_pool_base);
     183                 :       3261 :         g_iobuf.small_pool_base = NULL;
     184                 :       3261 :         spdk_ring_free(g_iobuf.small_pool);
     185                 :       3261 :         g_iobuf.small_pool = NULL;
     186                 :            : 
     187                 :       3261 :         spdk_free(g_iobuf.large_pool_base);
     188                 :       3261 :         g_iobuf.large_pool_base = NULL;
     189                 :       3261 :         spdk_ring_free(g_iobuf.large_pool);
     190                 :       3261 :         g_iobuf.large_pool = NULL;
     191                 :            : 
     192         [ +  - ]:       3261 :         if (g_iobuf.finish_cb != NULL) {
     193                 :       3261 :                 g_iobuf.finish_cb(g_iobuf.finish_arg);
     194                 :            :         }
     195                 :       3261 : }
     196                 :            : 
     197                 :            : void
     198                 :       3261 : spdk_iobuf_finish(spdk_iobuf_finish_cb cb_fn, void *cb_arg)
     199                 :            : {
     200                 :       3261 :         g_iobuf.finish_cb = cb_fn;
     201                 :       3261 :         g_iobuf.finish_arg = cb_arg;
     202                 :            : 
     203                 :       3261 :         spdk_io_device_unregister(&g_iobuf, iobuf_unregister_cb);
     204                 :       3261 : }
     205                 :            : 
     206                 :            : int
     207                 :        211 : spdk_iobuf_set_opts(const struct spdk_iobuf_opts *opts)
     208                 :            : {
     209         [ -  + ]:        211 :         if (opts->small_pool_count < IOBUF_MIN_SMALL_POOL_SIZE) {
     210                 :          0 :                 SPDK_ERRLOG("small_pool_count must be at least %" PRIu32 "\n",
     211                 :            :                             IOBUF_MIN_SMALL_POOL_SIZE);
     212                 :          0 :                 return -EINVAL;
     213                 :            :         }
     214         [ -  + ]:        211 :         if (opts->large_pool_count < IOBUF_MIN_LARGE_POOL_SIZE) {
     215                 :          0 :                 SPDK_ERRLOG("large_pool_count must be at least %" PRIu32 "\n",
     216                 :            :                             IOBUF_MIN_LARGE_POOL_SIZE);
     217                 :          0 :                 return -EINVAL;
     218                 :            :         }
     219                 :            : 
     220                 :        211 :         g_iobuf.opts = *opts;
     221                 :            : 
     222         [ -  + ]:        211 :         if (opts->small_bufsize < IOBUF_MIN_SMALL_BUFSIZE) {
     223                 :          0 :                 SPDK_ERRLOG("small_bufsize must be at least %" PRIu32 ". Automatically increasing.\n",
     224                 :            :                             IOBUF_MIN_SMALL_BUFSIZE);
     225                 :          0 :                 g_iobuf.opts.small_bufsize = IOBUF_MIN_SMALL_BUFSIZE;
     226                 :            :         }
     227                 :            : 
     228         [ -  + ]:        211 :         if (opts->large_bufsize < IOBUF_MIN_LARGE_BUFSIZE) {
     229                 :          0 :                 SPDK_WARNLOG("large_bufsize must be at least %" PRIu32 ". Automatically increasing.\n",
     230                 :            :                              IOBUF_MIN_LARGE_BUFSIZE);
     231                 :          0 :                 g_iobuf.opts.large_bufsize = IOBUF_MIN_LARGE_BUFSIZE;
     232                 :            :         }
     233                 :            : 
     234                 :        211 :         return 0;
     235                 :            : }
     236                 :            : 
     237                 :            : void
     238                 :       9173 : spdk_iobuf_get_opts(struct spdk_iobuf_opts *opts)
     239                 :            : {
     240                 :       9173 :         *opts = g_iobuf.opts;
     241                 :       9173 : }
     242                 :            : 
     243                 :            : int
     244                 :      24159 : spdk_iobuf_channel_init(struct spdk_iobuf_channel *ch, const char *name,
     245                 :            :                         uint32_t small_cache_size, uint32_t large_cache_size)
     246                 :            : {
     247                 :            :         struct spdk_io_channel *ioch;
     248                 :            :         struct iobuf_channel *iobuf_ch;
     249                 :            :         struct iobuf_module *module;
     250                 :       8008 :         struct spdk_iobuf_buffer *buf;
     251                 :            :         uint32_t i;
     252                 :            : 
     253         [ +  - ]:      38062 :         TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
     254   [ +  +  -  +  :      38062 :                 if (strcmp(name, module->name) == 0) {
                   +  + ]
     255                 :      24159 :                         break;
     256                 :            :                 }
     257                 :            :         }
     258                 :            : 
     259         [ -  + ]:      24159 :         if (module == NULL) {
     260                 :          0 :                 SPDK_ERRLOG("Couldn't find iobuf module: '%s'\n", name);
     261                 :          0 :                 return -ENODEV;
     262                 :            :         }
     263                 :            : 
     264                 :      24159 :         ioch = spdk_get_io_channel(&g_iobuf);
     265         [ -  + ]:      24159 :         if (ioch == NULL) {
     266                 :          0 :                 SPDK_ERRLOG("Couldn't get iobuf IO channel\n");
     267                 :          0 :                 return -ENOMEM;
     268                 :            :         }
     269                 :            : 
     270                 :      24159 :         iobuf_ch = spdk_io_channel_get_ctx(ioch);
     271                 :            : 
     272         [ +  - ]:      46037 :         for (i = 0; i < IOBUF_MAX_CHANNELS; ++i) {
     273         [ +  + ]:      46037 :                 if (iobuf_ch->channels[i] == NULL) {
     274                 :      24159 :                         iobuf_ch->channels[i] = ch;
     275                 :      24159 :                         break;
     276                 :            :                 }
     277                 :            :         }
     278                 :            : 
     279         [ -  + ]:      24159 :         if (i == IOBUF_MAX_CHANNELS) {
     280                 :          0 :                 SPDK_ERRLOG("Max number of iobuf channels (%" PRIu32 ") exceeded.\n", i);
     281                 :          0 :                 goto error;
     282                 :            :         }
     283                 :            : 
     284                 :      24159 :         ch->small.queue = &iobuf_ch->small_queue;
     285                 :      24159 :         ch->large.queue = &iobuf_ch->large_queue;
     286                 :      24159 :         ch->small.pool = g_iobuf.small_pool;
     287                 :      24159 :         ch->large.pool = g_iobuf.large_pool;
     288                 :      24159 :         ch->small.bufsize = g_iobuf.opts.small_bufsize;
     289                 :      24159 :         ch->large.bufsize = g_iobuf.opts.large_bufsize;
     290                 :      24159 :         ch->parent = ioch;
     291                 :      24159 :         ch->module = module;
     292                 :      24159 :         ch->small.cache_size = small_cache_size;
     293                 :      24159 :         ch->large.cache_size = large_cache_size;
     294                 :      24159 :         ch->small.cache_count = 0;
     295                 :      24159 :         ch->large.cache_count = 0;
     296                 :            : 
     297                 :      24159 :         STAILQ_INIT(&ch->small.cache);
     298                 :      24159 :         STAILQ_INIT(&ch->large.cache);
     299                 :            : 
     300         [ +  + ]:    3139630 :         for (i = 0; i < small_cache_size; ++i) {
     301         [ +  + ]:    3115483 :                 if (spdk_ring_dequeue(g_iobuf.small_pool, (void **)&buf, 1) == 0) {
     302                 :         12 :                         SPDK_ERRLOG("Failed to populate iobuf small buffer cache. "
     303                 :            :                                     "You may need to increase spdk_iobuf_opts.small_pool_count (%"PRIu64")\n",
     304                 :            :                                     g_iobuf.opts.small_pool_count);
     305                 :         12 :                         SPDK_ERRLOG("See scripts/calc-iobuf.py for guidance on how to calculate "
     306                 :            :                                     "this value.\n");
     307                 :         12 :                         goto error;
     308                 :            :                 }
     309                 :    3115471 :                 STAILQ_INSERT_TAIL(&ch->small.cache, buf, stailq);
     310                 :    3115471 :                 ch->small.cache_count++;
     311                 :            :         }
     312         [ +  + ]:     420202 :         for (i = 0; i < large_cache_size; ++i) {
     313         [ +  + ]:     396061 :                 if (spdk_ring_dequeue(g_iobuf.large_pool, (void **)&buf, 1) == 0) {
     314                 :          6 :                         SPDK_ERRLOG("Failed to populate iobuf large buffer cache. "
     315                 :            :                                     "You may need to increase spdk_iobuf_opts.large_pool_count (%"PRIu64")\n",
     316                 :            :                                     g_iobuf.opts.large_pool_count);
     317                 :          6 :                         SPDK_ERRLOG("See scripts/calc-iobuf.py for guidance on how to calculate "
     318                 :            :                                     "this value.\n");
     319                 :          6 :                         goto error;
     320                 :            :                 }
     321                 :     396055 :                 STAILQ_INSERT_TAIL(&ch->large.cache, buf, stailq);
     322                 :     396055 :                 ch->large.cache_count++;
     323                 :            :         }
     324                 :            : 
     325                 :      24141 :         return 0;
     326                 :         18 : error:
     327                 :         18 :         spdk_iobuf_channel_fini(ch);
     328                 :            : 
     329                 :         18 :         return -ENOMEM;
     330                 :            : }
     331                 :            : 
     332                 :            : void
     333                 :      24159 : spdk_iobuf_channel_fini(struct spdk_iobuf_channel *ch)
     334                 :            : {
     335                 :            :         struct spdk_iobuf_entry *entry __attribute__((unused));
     336                 :       8008 :         struct spdk_iobuf_buffer *buf;
     337                 :            :         struct iobuf_channel *iobuf_ch;
     338                 :            :         uint32_t i;
     339                 :            : 
     340                 :            :         /* Make sure none of the wait queue entries are coming from this module */
     341         [ -  + ]:      24159 :         STAILQ_FOREACH(entry, ch->small.queue, stailq) {
     342         [ #  # ]:          0 :                 assert(entry->module != ch->module);
     343                 :            :         }
     344         [ -  + ]:      24159 :         STAILQ_FOREACH(entry, ch->large.queue, stailq) {
     345         [ #  # ]:          0 :                 assert(entry->module != ch->module);
     346                 :            :         }
     347                 :            : 
     348                 :            :         /* Release cached buffers back to the pool */
     349         [ +  + ]:    3139642 :         while (!STAILQ_EMPTY(&ch->small.cache)) {
     350                 :    3115483 :                 buf = STAILQ_FIRST(&ch->small.cache);
     351         [ +  + ]:    3115483 :                 STAILQ_REMOVE_HEAD(&ch->small.cache, stailq);
     352                 :    3115483 :                 spdk_ring_enqueue(g_iobuf.small_pool, (void **)&buf, 1, NULL);
     353                 :    3115483 :                 ch->small.cache_count--;
     354                 :            :         }
     355         [ +  + ]:     420302 :         while (!STAILQ_EMPTY(&ch->large.cache)) {
     356                 :     396143 :                 buf = STAILQ_FIRST(&ch->large.cache);
     357         [ +  + ]:     396143 :                 STAILQ_REMOVE_HEAD(&ch->large.cache, stailq);
     358                 :     396143 :                 spdk_ring_enqueue(g_iobuf.large_pool, (void **)&buf, 1, NULL);
     359                 :     396143 :                 ch->large.cache_count--;
     360                 :            :         }
     361                 :            : 
     362         [ -  + ]:      24159 :         assert(ch->small.cache_count == 0);
     363         [ -  + ]:      24159 :         assert(ch->large.cache_count == 0);
     364                 :            : 
     365                 :      24159 :         iobuf_ch = spdk_io_channel_get_ctx(ch->parent);
     366         [ +  - ]:      46037 :         for (i = 0; i < IOBUF_MAX_CHANNELS; ++i) {
     367         [ +  + ]:      46037 :                 if (iobuf_ch->channels[i] == ch) {
     368                 :      24159 :                         iobuf_ch->channels[i] = NULL;
     369                 :      24159 :                         break;
     370                 :            :                 }
     371                 :            :         }
     372                 :            : 
     373                 :      24159 :         spdk_put_io_channel(ch->parent);
     374                 :      24159 :         ch->parent = NULL;
     375                 :      24159 : }
     376                 :            : 
     377                 :            : int
     378                 :       5468 : spdk_iobuf_register_module(const char *name)
     379                 :            : {
     380                 :            :         struct iobuf_module *module;
     381                 :            : 
     382         [ +  + ]:       7869 :         TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
     383   [ -  +  -  +  :       2402 :                 if (strcmp(name, module->name) == 0) {
                   +  + ]
     384                 :          1 :                         return -EEXIST;
     385                 :            :                 }
     386                 :            :         }
     387                 :            : 
     388                 :       5467 :         module = calloc(1, sizeof(*module));
     389         [ -  + ]:       5467 :         if (module == NULL) {
     390                 :          0 :                 return -ENOMEM;
     391                 :            :         }
     392                 :            : 
     393         [ -  + ]:       5467 :         module->name = strdup(name);
     394         [ -  + ]:       5467 :         if (module->name == NULL) {
     395                 :          0 :                 free(module);
     396                 :          0 :                 return -ENOMEM;
     397                 :            :         }
     398                 :            : 
     399                 :       5467 :         TAILQ_INSERT_TAIL(&g_iobuf.modules, module, tailq);
     400                 :            : 
     401                 :       5467 :         return 0;
     402                 :            : }
     403                 :            : 
     404                 :            : int
     405                 :        195 : spdk_iobuf_unregister_module(const char *name)
     406                 :            : {
     407                 :            :         struct iobuf_module *module;
     408                 :            : 
     409         [ +  - ]:        585 :         TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
     410   [ -  +  -  +  :        585 :                 if (strcmp(name, module->name) == 0) {
                   +  + ]
     411         [ -  + ]:        195 :                         TAILQ_REMOVE(&g_iobuf.modules, module, tailq);
     412                 :        195 :                         free(module->name);
     413                 :        195 :                         free(module);
     414                 :        195 :                         return 0;
     415                 :            :                 }
     416                 :            :         }
     417                 :            : 
     418                 :          0 :         return -ENOENT;
     419                 :            : }
     420                 :            : 
     421                 :            : int
     422                 :      99782 : spdk_iobuf_for_each_entry(struct spdk_iobuf_channel *ch, struct spdk_iobuf_pool *pool,
     423                 :            :                           spdk_iobuf_for_each_entry_fn cb_fn, void *cb_ctx)
     424                 :            : {
     425                 :            :         struct spdk_iobuf_entry *entry, *tmp;
     426                 :            :         int rc;
     427                 :            : 
     428         [ +  + ]:      99878 :         STAILQ_FOREACH_SAFE(entry, pool->queue, stailq, tmp) {
     429                 :            :                 /* We only want to iterate over the entries requested by the module which owns ch */
     430         [ +  + ]:         96 :                 if (entry->module != ch->module) {
     431                 :         48 :                         continue;
     432                 :            :                 }
     433                 :            : 
     434                 :         48 :                 rc = cb_fn(ch, entry, cb_ctx);
     435         [ -  + ]:         48 :                 if (rc != 0) {
     436                 :          0 :                         return rc;
     437                 :            :                 }
     438                 :            :         }
     439                 :            : 
     440                 :      99782 :         return 0;
     441                 :            : }
     442                 :            : 
     443                 :            : void
     444                 :         72 : spdk_iobuf_entry_abort(struct spdk_iobuf_channel *ch, struct spdk_iobuf_entry *entry,
     445                 :            :                        uint64_t len)
     446                 :            : {
     447                 :            :         struct spdk_iobuf_pool *pool;
     448                 :            : 
     449         [ +  + ]:         72 :         if (len <= ch->small.bufsize) {
     450                 :         36 :                 pool = &ch->small;
     451                 :            :         } else {
     452         [ -  + ]:         36 :                 assert(len <= ch->large.bufsize);
     453                 :         36 :                 pool = &ch->large;
     454                 :            :         }
     455                 :            : 
     456   [ +  -  +  +  :         72 :         STAILQ_REMOVE(pool->queue, entry, spdk_iobuf_entry, stailq);
             -  -  -  - ]
     457                 :         72 : }
     458                 :            : 
     459                 :            : #define IOBUF_BATCH_SIZE 32
     460                 :            : 
     461                 :            : void *
     462                 :   54126189 : spdk_iobuf_get(struct spdk_iobuf_channel *ch, uint64_t len,
     463                 :            :                struct spdk_iobuf_entry *entry, spdk_iobuf_get_cb cb_fn)
     464                 :            : {
     465                 :            :         struct spdk_iobuf_pool *pool;
     466                 :            :         void *buf;
     467                 :            : 
     468         [ -  + ]:   54126189 :         assert(spdk_io_channel_get_thread(ch->parent) == spdk_get_thread());
     469         [ +  + ]:   54126189 :         if (len <= ch->small.bufsize) {
     470                 :   52563697 :                 pool = &ch->small;
     471                 :            :         } else {
     472         [ -  + ]:    1562492 :                 assert(len <= ch->large.bufsize);
     473                 :    1562492 :                 pool = &ch->large;
     474                 :            :         }
     475                 :            : 
     476                 :   54126189 :         buf = (void *)STAILQ_FIRST(&pool->cache);
     477         [ +  + ]:   54126189 :         if (buf) {
     478         [ +  + ]:   52597419 :                 STAILQ_REMOVE_HEAD(&pool->cache, stailq);
     479         [ -  + ]:   52597419 :                 assert(pool->cache_count > 0);
     480                 :   52597419 :                 pool->cache_count--;
     481                 :   52597419 :                 pool->stats.cache++;
     482                 :            :         } else {
     483                 :      33036 :                 struct spdk_iobuf_buffer *bufs[IOBUF_BATCH_SIZE];
     484                 :            :                 size_t sz, i;
     485                 :            : 
     486                 :            :                 /* If we're going to dequeue, we may as well dequeue a batch. */
     487         [ +  + ]:    1528770 :                 sz = spdk_ring_dequeue(pool->pool, (void **)bufs, spdk_min(IOBUF_BATCH_SIZE,
     488                 :            :                                        spdk_max(pool->cache_size, 1)));
     489         [ +  + ]:    1528770 :                 if (sz == 0) {
     490         [ +  + ]:    1290570 :                         if (entry) {
     491                 :      32234 :                                 STAILQ_INSERT_TAIL(pool->queue, entry, stailq);
     492                 :      32234 :                                 entry->module = ch->module;
     493                 :      32234 :                                 entry->cb_fn = cb_fn;
     494                 :      32234 :                                 pool->stats.retry++;
     495                 :            :                         }
     496                 :            : 
     497                 :    1290570 :                         return NULL;
     498                 :            :                 }
     499                 :            : 
     500                 :     238200 :                 pool->stats.main++;
     501         [ +  + ]:    7478988 :                 for (i = 0; i < (sz - 1); i++) {
     502         [ +  + ]:    7240788 :                         STAILQ_INSERT_HEAD(&pool->cache, bufs[i], stailq);
     503                 :    7240788 :                         pool->cache_count++;
     504                 :            :                 }
     505                 :            : 
     506                 :            :                 /* The last one is the one we'll return */
     507                 :     238200 :                 buf = bufs[i];
     508                 :            :         }
     509                 :            : 
     510                 :   52835619 :         return (char *)buf;
     511                 :            : }
     512                 :            : 
     513                 :            : void
     514                 :   52867781 : spdk_iobuf_put(struct spdk_iobuf_channel *ch, void *buf, uint64_t len)
     515                 :            : {
     516                 :            :         struct spdk_iobuf_entry *entry;
     517                 :            :         struct spdk_iobuf_buffer *iobuf_buf;
     518                 :            :         struct spdk_iobuf_pool *pool;
     519                 :            :         size_t sz;
     520                 :            : 
     521         [ -  + ]:   52867781 :         assert(spdk_io_channel_get_thread(ch->parent) == spdk_get_thread());
     522         [ +  + ]:   52867781 :         if (len <= ch->small.bufsize) {
     523                 :   51305325 :                 pool = &ch->small;
     524                 :            :         } else {
     525                 :    1562456 :                 pool = &ch->large;
     526                 :            :         }
     527                 :            : 
     528         [ +  + ]:   52867781 :         if (STAILQ_EMPTY(pool->queue)) {
     529         [ +  + ]:   52835619 :                 if (pool->cache_size == 0) {
     530                 :         96 :                         spdk_ring_enqueue(pool->pool, (void **)&buf, 1, NULL);
     531                 :         96 :                         return;
     532                 :            :                 }
     533                 :            : 
     534                 :   52835523 :                 iobuf_buf = (struct spdk_iobuf_buffer *)buf;
     535                 :            : 
     536         [ +  + ]:   52835523 :                 STAILQ_INSERT_HEAD(&pool->cache, iobuf_buf, stailq);
     537                 :   52835523 :                 pool->cache_count++;
     538                 :            : 
     539                 :            :                 /* The cache size may exceed the configured amount. We always dequeue from the
     540                 :            :                  * central pool in batches of known size, so wait until at least a batch
     541                 :            :                  * has been returned to actually return the buffers to the central pool. */
     542                 :   52835523 :                 sz = spdk_min(IOBUF_BATCH_SIZE, pool->cache_size);
     543         [ +  + ]:   52835523 :                 if (pool->cache_count >= pool->cache_size + sz) {
     544                 :       6649 :                         struct spdk_iobuf_buffer *bufs[IOBUF_BATCH_SIZE];
     545                 :            :                         size_t i;
     546                 :            : 
     547         [ +  + ]:    7716885 :                         for (i = 0; i < sz; i++) {
     548                 :    7478792 :                                 bufs[i] = STAILQ_FIRST(&pool->cache);
     549         [ -  + ]:    7478792 :                                 STAILQ_REMOVE_HEAD(&pool->cache, stailq);
     550         [ -  + ]:    7478792 :                                 assert(pool->cache_count > 0);
     551                 :    7478792 :                                 pool->cache_count--;
     552                 :            :                         }
     553                 :            : 
     554                 :     238093 :                         spdk_ring_enqueue(pool->pool, (void **)bufs, sz, NULL);
     555                 :            :                 }
     556                 :            :         } else {
     557                 :      32162 :                 entry = STAILQ_FIRST(pool->queue);
     558         [ +  + ]:      32162 :                 STAILQ_REMOVE_HEAD(pool->queue, stailq);
     559                 :      32162 :                 entry->cb_fn(entry, buf);
     560                 :            :         }
     561                 :            : }
     562                 :            : 
     563                 :            : static void
     564                 :          0 : iobuf_get_channel_stats_done(struct spdk_io_channel_iter *iter, int status)
     565                 :            : {
     566                 :          0 :         struct iobuf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(iter);
     567                 :            : 
     568                 :          0 :         ctx->cb_fn(ctx->modules, ctx->num_modules, ctx->cb_arg);
     569                 :          0 :         free(ctx->modules);
     570                 :          0 :         free(ctx);
     571                 :          0 : }
     572                 :            : 
     573                 :            : static void
     574                 :          0 : iobuf_get_channel_stats(struct spdk_io_channel_iter *iter)
     575                 :            : {
     576                 :          0 :         struct iobuf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(iter);
     577                 :          0 :         struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(iter);
     578                 :          0 :         struct iobuf_channel *iobuf_ch = spdk_io_channel_get_ctx(ch);
     579                 :            :         struct spdk_iobuf_channel *channel;
     580                 :            :         struct iobuf_module *module;
     581                 :            :         struct spdk_iobuf_module_stats *it;
     582                 :            :         uint32_t i, j;
     583                 :            : 
     584         [ #  # ]:          0 :         for (i = 0; i < ctx->num_modules; ++i) {
     585         [ #  # ]:          0 :                 for (j = 0; j < IOBUF_MAX_CHANNELS; ++j) {
     586                 :          0 :                         channel = iobuf_ch->channels[j];
     587         [ #  # ]:          0 :                         if (channel == NULL) {
     588                 :          0 :                                 continue;
     589                 :            :                         }
     590                 :            : 
     591                 :          0 :                         it = &ctx->modules[i];
     592                 :          0 :                         module = (struct iobuf_module *)channel->module;
     593   [ #  #  #  #  :          0 :                         if (strcmp(it->module, module->name) == 0) {
                   #  # ]
     594                 :          0 :                                 it->small_pool.cache += channel->small.stats.cache;
     595                 :          0 :                                 it->small_pool.main += channel->small.stats.main;
     596                 :          0 :                                 it->small_pool.retry += channel->small.stats.retry;
     597                 :          0 :                                 it->large_pool.cache += channel->large.stats.cache;
     598                 :          0 :                                 it->large_pool.main += channel->large.stats.main;
     599                 :          0 :                                 it->large_pool.retry += channel->large.stats.retry;
     600                 :          0 :                                 break;
     601                 :            :                         }
     602                 :            :                 }
     603                 :            :         }
     604                 :            : 
     605                 :          0 :         spdk_for_each_channel_continue(iter, 0);
     606                 :          0 : }
     607                 :            : 
     608                 :            : int
     609                 :          0 : spdk_iobuf_get_stats(spdk_iobuf_get_stats_cb cb_fn, void *cb_arg)
     610                 :            : {
     611                 :            :         struct iobuf_module *module;
     612                 :            :         struct iobuf_get_stats_ctx *ctx;
     613                 :            :         uint32_t i;
     614                 :            : 
     615                 :          0 :         ctx = calloc(1, sizeof(*ctx));
     616         [ #  # ]:          0 :         if (ctx == NULL) {
     617                 :          0 :                 return -ENOMEM;
     618                 :            :         }
     619                 :            : 
     620         [ #  # ]:          0 :         TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
     621                 :          0 :                 ++ctx->num_modules;
     622                 :            :         }
     623                 :            : 
     624                 :          0 :         ctx->modules = calloc(ctx->num_modules, sizeof(struct spdk_iobuf_module_stats));
     625         [ #  # ]:          0 :         if (ctx->modules == NULL) {
     626                 :          0 :                 free(ctx);
     627                 :          0 :                 return -ENOMEM;
     628                 :            :         }
     629                 :            : 
     630                 :          0 :         i = 0;
     631         [ #  # ]:          0 :         TAILQ_FOREACH(module, &g_iobuf.modules, tailq) {
     632                 :          0 :                 ctx->modules[i].module = module->name;
     633                 :          0 :                 ++i;
     634                 :            :         }
     635                 :            : 
     636                 :          0 :         ctx->cb_fn = cb_fn;
     637                 :          0 :         ctx->cb_arg = cb_arg;
     638                 :            : 
     639                 :          0 :         spdk_for_each_channel(&g_iobuf, iobuf_get_channel_stats, ctx,
     640                 :            :                               iobuf_get_channel_stats_done);
     641                 :          0 :         return 0;
     642                 :            : }

Generated by: LCOV version 1.14