LCOV - code coverage report
Current view: top level - lib/fsdev - fsdev.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 364 519 70.1 %
Date: 2024-12-15 03:48:28 Functions: 49 63 77.8 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       3             :  */
       4             : 
       5             : #include "spdk/stdinc.h"
       6             : #include "spdk/fsdev.h"
       7             : #include "spdk/config.h"
       8             : #include "spdk/env.h"
       9             : #include "spdk/likely.h"
      10             : #include "spdk/queue.h"
      11             : #include "spdk/util.h"
      12             : #include "spdk/notify.h"
      13             : #include "spdk/fsdev_module.h"
      14             : #include "spdk/log.h"
      15             : #include "spdk/string.h"
      16             : #include "fsdev_internal.h"
      17             : 
      18             : #define SPDK_FSDEV_IO_POOL_SIZE (64 * 1024 - 1)
      19             : #define SPDK_FSDEV_IO_CACHE_SIZE 256
      20             : 
      21             : static struct spdk_fsdev_opts g_fsdev_opts = {
      22             :         .fsdev_io_pool_size = SPDK_FSDEV_IO_POOL_SIZE,
      23             :         .fsdev_io_cache_size = SPDK_FSDEV_IO_CACHE_SIZE,
      24             : };
      25             : 
      26             : TAILQ_HEAD(spdk_fsdev_list, spdk_fsdev);
      27             : 
      28             : RB_HEAD(fsdev_name_tree, spdk_fsdev_name);
      29             : 
      30             : static int
      31          39 : fsdev_name_cmp(struct spdk_fsdev_name *name1, struct spdk_fsdev_name *name2)
      32             : {
      33          39 :         return strcmp(name1->name, name2->name);
      34             : }
      35             : 
      36         156 : RB_GENERATE_STATIC(fsdev_name_tree, spdk_fsdev_name, node, fsdev_name_cmp);
      37             : 
      38             : struct spdk_fsdev_mgr {
      39             :         struct spdk_mempool *fsdev_io_pool;
      40             : 
      41             :         TAILQ_HEAD(fsdev_module_list, spdk_fsdev_module) fsdev_modules;
      42             : 
      43             :         struct spdk_fsdev_list fsdevs;
      44             :         struct fsdev_name_tree fsdev_names;
      45             : 
      46             :         bool init_complete;
      47             :         bool module_init_complete;
      48             : 
      49             :         struct spdk_spinlock spinlock;
      50             : };
      51             : 
      52             : static struct spdk_fsdev_mgr g_fsdev_mgr = {
      53             :         .fsdev_modules = TAILQ_HEAD_INITIALIZER(g_fsdev_mgr.fsdev_modules),
      54             :         .fsdevs = TAILQ_HEAD_INITIALIZER(g_fsdev_mgr.fsdevs),
      55             :         .fsdev_names = RB_INITIALIZER(g_fsdev_mgr.fsdev_names),
      56             :         .init_complete = false,
      57             :         .module_init_complete = false,
      58             : };
      59             : 
      60             : static void
      61             : __attribute__((constructor))
      62           1 : _fsdev_init(void)
      63             : {
      64           1 :         spdk_spin_init(&g_fsdev_mgr.spinlock);
      65           1 : }
      66             : 
      67             : 
      68             : static spdk_fsdev_init_cb       g_init_cb_fn = NULL;
      69             : static void                     *g_init_cb_arg = NULL;
      70             : 
      71             : static spdk_fsdev_fini_cb       g_fini_cb_fn = NULL;
      72             : static void                     *g_fini_cb_arg = NULL;
      73             : static struct spdk_thread       *g_fini_thread = NULL;
      74             : 
      75             : struct spdk_fsdev_mgmt_channel {
      76             :         /*
      77             :          * Each thread keeps a cache of fsdev_io - this allows
      78             :          *  fsdev threads which are *not* DPDK threads to still
      79             :          *  benefit from a per-thread fsdev_io cache.  Without
      80             :          *  this, non-DPDK threads fetching from the mempool
      81             :          *  incur a cmpxchg on get and put.
      82             :          */
      83             :         fsdev_io_stailq_t per_thread_cache;
      84             :         uint32_t        per_thread_cache_count;
      85             :         uint32_t        fsdev_io_cache_size;
      86             : 
      87             :         TAILQ_HEAD(, spdk_fsdev_shared_resource) shared_resources;
      88             : };
      89             : 
      90             : /*
      91             :  * Per-module (or per-io_device) data. Multiple fsdevs built on the same io_device
      92             :  * will queue here their IO that awaits retry. It makes it possible to retry sending
      93             :  * IO to one fsdev after IO from other fsdev completes.
      94             :  */
      95             : struct spdk_fsdev_shared_resource {
      96             :         /* The fsdev management channel */
      97             :         struct spdk_fsdev_mgmt_channel *mgmt_ch;
      98             : 
      99             :         /*
     100             :          * Count of I/O submitted to fsdev module and waiting for completion.
     101             :          * Incremented before submit_request() is called on an spdk_fsdev_io.
     102             :          */
     103             :         uint64_t                io_outstanding;
     104             : 
     105             :         /* I/O channel allocated by a fsdev module */
     106             :         struct spdk_io_channel  *shared_ch;
     107             : 
     108             :         /* Refcount of fsdev channels using this resource */
     109             :         uint32_t                ref;
     110             : 
     111             :         TAILQ_ENTRY(spdk_fsdev_shared_resource) link;
     112             : };
     113             : 
     114             : struct spdk_fsdev_channel {
     115             :         struct spdk_fsdev       *fsdev;
     116             : 
     117             :         /* The channel for the underlying device */
     118             :         struct spdk_io_channel  *channel;
     119             : 
     120             :         /* Per io_device per thread data */
     121             :         struct spdk_fsdev_shared_resource *shared_resource;
     122             : 
     123             :         /*
     124             :          * Count of I/O submitted to the underlying dev module through this channel
     125             :          * and waiting for completion.
     126             :          */
     127             :         uint64_t                io_outstanding;
     128             : 
     129             :         /*
     130             :          * List of all submitted I/Os.
     131             :          */
     132             :         fsdev_io_tailq_t        io_submitted;
     133             : };
     134             : 
     135             : struct spdk_fsdev_desc {
     136             :         struct spdk_fsdev               *fsdev;
     137             :         struct spdk_thread              *thread;
     138             :         struct {
     139             :                 spdk_fsdev_event_cb_t event_fn;
     140             :                 void *ctx;
     141             :         }                               callback;
     142             :         bool                            closed;
     143             :         struct spdk_spinlock            spinlock;
     144             :         uint32_t                        refs;
     145             :         TAILQ_ENTRY(spdk_fsdev_desc)    link;
     146             : };
     147             : 
     148             : #define __fsdev_to_io_dev(fsdev)        (((char *)fsdev) + 1)
     149             : #define __fsdev_from_io_dev(io_dev)     ((struct spdk_fsdev *)(((char *)io_dev) - 1))
     150             : #define __io_ch_to_fsdev_mgmt_ch(io_ch) ((struct spdk_fsdev_mgmt_channel *)spdk_io_channel_get_ctx(io_ch))
     151             : 
     152             : static struct spdk_fsdev *
     153          39 : fsdev_get_by_name(const char *fsdev_name)
     154             : {
     155          39 :         struct spdk_fsdev_name find;
     156             :         struct spdk_fsdev_name *res;
     157             : 
     158          39 :         find.name = (char *)fsdev_name;
     159          39 :         res = RB_FIND(fsdev_name_tree, &g_fsdev_mgr.fsdev_names, &find);
     160          39 :         if (res != NULL) {
     161          39 :                 return res->fsdev;
     162             :         }
     163             : 
     164           0 :         return NULL;
     165             : }
     166             : 
     167             : static int
     168           1 : fsdev_module_get_max_ctx_size(void)
     169             : {
     170             :         struct spdk_fsdev_module *fsdev_module;
     171           1 :         int max_fsdev_module_size = 0;
     172             : 
     173           2 :         TAILQ_FOREACH(fsdev_module, &g_fsdev_mgr.fsdev_modules, internal.tailq) {
     174           1 :                 if (fsdev_module->get_ctx_size && fsdev_module->get_ctx_size() > max_fsdev_module_size) {
     175           0 :                         max_fsdev_module_size = fsdev_module->get_ctx_size();
     176             :                 }
     177             :         }
     178             : 
     179           1 :         return max_fsdev_module_size;
     180             : }
     181             : 
     182             : void
     183           0 : spdk_fsdev_subsystem_config_json(struct spdk_json_write_ctx *w)
     184             : {
     185             :         struct spdk_fsdev_module *fsdev_module;
     186             :         struct spdk_fsdev *fsdev;
     187             : 
     188           0 :         assert(w != NULL);
     189             : 
     190           0 :         spdk_json_write_array_begin(w);
     191             : 
     192           0 :         spdk_json_write_object_begin(w);
     193           0 :         spdk_json_write_named_string(w, "method", "fsdev_set_opts");
     194           0 :         spdk_json_write_named_object_begin(w, "params");
     195           0 :         spdk_json_write_named_uint32(w, "fsdev_io_pool_size", g_fsdev_opts.fsdev_io_pool_size);
     196           0 :         spdk_json_write_named_uint32(w, "fsdev_io_cache_size", g_fsdev_opts.fsdev_io_cache_size);
     197           0 :         spdk_json_write_object_end(w); /* params */
     198           0 :         spdk_json_write_object_end(w);
     199             : 
     200           0 :         TAILQ_FOREACH(fsdev_module, &g_fsdev_mgr.fsdev_modules, internal.tailq) {
     201           0 :                 if (fsdev_module->config_json) {
     202           0 :                         fsdev_module->config_json(w);
     203             :                 }
     204             :         }
     205             : 
     206           0 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
     207             : 
     208           0 :         TAILQ_FOREACH(fsdev, &g_fsdev_mgr.fsdevs, internal.link) {
     209           0 :                 if (fsdev->fn_table->write_config_json) {
     210           0 :                         fsdev->fn_table->write_config_json(fsdev, w);
     211             :                 }
     212             :         }
     213             : 
     214           0 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
     215           0 :         spdk_json_write_array_end(w);
     216           0 : }
     217             : 
     218             : static void
     219          38 : fsdev_mgmt_channel_destroy(void *io_device, void *ctx_buf)
     220             : {
     221          38 :         struct spdk_fsdev_mgmt_channel *ch = ctx_buf;
     222             :         struct spdk_fsdev_io *fsdev_io;
     223             : 
     224          38 :         if (!TAILQ_EMPTY(&ch->shared_resources)) {
     225           0 :                 SPDK_ERRLOG("Module channel list wasn't empty on mgmt channel free\n");
     226             :         }
     227             : 
     228       19494 :         while (!STAILQ_EMPTY(&ch->per_thread_cache)) {
     229       19456 :                 fsdev_io = STAILQ_FIRST(&ch->per_thread_cache);
     230       19456 :                 STAILQ_REMOVE_HEAD(&ch->per_thread_cache, internal.buf_link);
     231       19456 :                 ch->per_thread_cache_count--;
     232       19456 :                 spdk_mempool_put(g_fsdev_mgr.fsdev_io_pool, (void *)fsdev_io);
     233             :         }
     234             : 
     235          38 :         assert(ch->per_thread_cache_count == 0);
     236          38 :         return;
     237             : }
     238             : 
     239             : static int
     240          38 : fsdev_mgmt_channel_create(void *io_device, void *ctx_buf)
     241             : {
     242          38 :         struct spdk_fsdev_mgmt_channel *ch = ctx_buf;
     243             :         struct spdk_fsdev_io *fsdev_io;
     244             :         uint32_t i;
     245             : 
     246          38 :         STAILQ_INIT(&ch->per_thread_cache);
     247          38 :         ch->fsdev_io_cache_size = g_fsdev_opts.fsdev_io_cache_size;
     248             : 
     249             :         /* Pre-populate fsdev_io cache to ensure this thread cannot be starved. */
     250          38 :         ch->per_thread_cache_count = 0;
     251       19494 :         for (i = 0; i < ch->fsdev_io_cache_size; i++) {
     252       19456 :                 fsdev_io = spdk_mempool_get(g_fsdev_mgr.fsdev_io_pool);
     253       19456 :                 if (fsdev_io == NULL) {
     254           0 :                         SPDK_ERRLOG("You need to increase fsdev_io_pool_size using fsdev_set_options RPC.\n");
     255           0 :                         assert(false);
     256             :                         fsdev_mgmt_channel_destroy(io_device, ctx_buf);
     257             :                         return -1;
     258             :                 }
     259       19456 :                 ch->per_thread_cache_count++;
     260       19456 :                 STAILQ_INSERT_HEAD(&ch->per_thread_cache, fsdev_io, internal.buf_link);
     261             :         }
     262             : 
     263          38 :         TAILQ_INIT(&ch->shared_resources);
     264          38 :         return 0;
     265             : }
     266             : 
     267             : static void
     268           1 : fsdev_init_complete(int rc)
     269             : {
     270           1 :         spdk_fsdev_init_cb cb_fn = g_init_cb_fn;
     271           1 :         void *cb_arg = g_init_cb_arg;
     272             : 
     273           1 :         g_fsdev_mgr.init_complete = true;
     274           1 :         g_init_cb_fn = NULL;
     275           1 :         g_init_cb_arg = NULL;
     276             : 
     277           1 :         cb_fn(cb_arg, rc);
     278           1 : }
     279             : 
     280             : static void
     281           0 : fsdev_init_failed(void *cb_arg)
     282             : {
     283           0 :         fsdev_init_complete(-1);
     284           0 : }
     285             : 
     286             : static int
     287           1 : fsdev_modules_init(void)
     288             : {
     289             :         struct spdk_fsdev_module *module;
     290           1 :         int rc = 0;
     291             : 
     292           2 :         TAILQ_FOREACH(module, &g_fsdev_mgr.fsdev_modules, internal.tailq) {
     293           1 :                 rc = module->module_init();
     294           1 :                 if (rc != 0) {
     295           0 :                         spdk_thread_send_msg(spdk_get_thread(), fsdev_init_failed, module);
     296           0 :                         return rc;
     297             :                 }
     298             :         }
     299             : 
     300           1 :         return 0;
     301             : }
     302             : 
     303             : void
     304           1 : spdk_fsdev_initialize(spdk_fsdev_init_cb cb_fn, void *cb_arg)
     305             : {
     306           1 :         int rc = 0;
     307           1 :         char mempool_name[32];
     308             : 
     309           1 :         assert(cb_fn != NULL);
     310             : 
     311           1 :         g_init_cb_fn = cb_fn;
     312           1 :         g_init_cb_arg = cb_arg;
     313             : 
     314           1 :         spdk_notify_type_register("fsdev_register");
     315           1 :         spdk_notify_type_register("fsdev_unregister");
     316             : 
     317           1 :         snprintf(mempool_name, sizeof(mempool_name), "fsdev_io_%d", getpid());
     318             : 
     319           2 :         g_fsdev_mgr.fsdev_io_pool = spdk_mempool_create(mempool_name,
     320           1 :                                     g_fsdev_opts.fsdev_io_pool_size,
     321             :                                     sizeof(struct spdk_fsdev_io) +
     322           1 :                                     fsdev_module_get_max_ctx_size(),
     323             :                                     0,
     324             :                                     SPDK_ENV_NUMA_ID_ANY);
     325             : 
     326           1 :         if (g_fsdev_mgr.fsdev_io_pool == NULL) {
     327           0 :                 SPDK_ERRLOG("Could not allocate spdk_fsdev_io pool\n");
     328           0 :                 fsdev_init_complete(-1);
     329           0 :                 return;
     330             :         }
     331             : 
     332           1 :         spdk_io_device_register(&g_fsdev_mgr, fsdev_mgmt_channel_create,
     333             :                                 fsdev_mgmt_channel_destroy,
     334             :                                 sizeof(struct spdk_fsdev_mgmt_channel),
     335             :                                 "fsdev_mgr");
     336             : 
     337           1 :         rc = fsdev_modules_init();
     338           1 :         g_fsdev_mgr.module_init_complete = true;
     339           1 :         if (rc != 0) {
     340           0 :                 SPDK_ERRLOG("fsdev modules init failed\n");
     341           0 :                 return;
     342             :         }
     343             : 
     344           1 :         fsdev_init_complete(0);
     345             : }
     346             : 
     347             : static void
     348           1 : fsdev_mgr_unregister_cb(void *io_device)
     349             : {
     350           1 :         spdk_fsdev_fini_cb cb_fn = g_fini_cb_fn;
     351             : 
     352           1 :         if (g_fsdev_mgr.fsdev_io_pool) {
     353           1 :                 if (spdk_mempool_count(g_fsdev_mgr.fsdev_io_pool) != g_fsdev_opts.fsdev_io_pool_size) {
     354           1 :                         SPDK_ERRLOG("fsdev IO pool count is %zu but should be %u\n",
     355             :                                     spdk_mempool_count(g_fsdev_mgr.fsdev_io_pool),
     356             :                                     g_fsdev_opts.fsdev_io_pool_size);
     357             :                 }
     358             : 
     359           1 :                 spdk_mempool_free(g_fsdev_mgr.fsdev_io_pool);
     360             :         }
     361             : 
     362           1 :         cb_fn(g_fini_cb_arg);
     363           1 :         g_fini_cb_fn = NULL;
     364           1 :         g_fini_cb_arg = NULL;
     365           1 :         g_fsdev_mgr.init_complete = false;
     366           1 :         g_fsdev_mgr.module_init_complete = false;
     367           1 : }
     368             : 
     369             : static void
     370           1 : fsdev_module_fini_iter(void *arg)
     371             : {
     372             :         struct spdk_fsdev_module *fsdev_module;
     373             : 
     374             :         /* FIXME: Handling initialization failures is broken now,
     375             :          * so we won't even try cleaning up after successfully
     376             :          * initialized modules. if module_init_complete is false,
     377             :          * just call spdk_fsdev_mgr_unregister_cb
     378             :          */
     379           1 :         if (!g_fsdev_mgr.module_init_complete) {
     380           0 :                 fsdev_mgr_unregister_cb(NULL);
     381           0 :                 return;
     382             :         }
     383             : 
     384             :         /* Start iterating from the last touched module */
     385           1 :         fsdev_module = TAILQ_LAST(&g_fsdev_mgr.fsdev_modules, fsdev_module_list);
     386           2 :         while (fsdev_module) {
     387           1 :                 if (fsdev_module->module_fini) {
     388           1 :                         fsdev_module->module_fini();
     389             :                 }
     390             : 
     391           1 :                 fsdev_module = TAILQ_PREV(fsdev_module, fsdev_module_list,
     392             :                                           internal.tailq);
     393             :         }
     394             : 
     395           1 :         spdk_io_device_unregister(&g_fsdev_mgr, fsdev_mgr_unregister_cb);
     396             : }
     397             : 
     398             : static void
     399           1 : fsdev_finish_unregister_fsdevs_iter(void *cb_arg, int fsdeverrno)
     400             : {
     401           1 :         struct spdk_fsdev *fsdev = cb_arg;
     402             : 
     403           1 :         if (fsdeverrno && fsdev) {
     404           0 :                 SPDK_WARNLOG("Unable to unregister fsdev '%s' during spdk_fsdev_finish()\n",
     405             :                              fsdev->name);
     406             : 
     407             :                 /*
     408             :                  * Since the call to spdk_fsdev_unregister() failed, we have no way to free this
     409             :                  *  fsdev; try to continue by manually removing this fsdev from the list and continue
     410             :                  *  with the next fsdev in the list.
     411             :                  */
     412           0 :                 TAILQ_REMOVE(&g_fsdev_mgr.fsdevs, fsdev, internal.link);
     413             :         }
     414             : 
     415           1 :         fsdev = TAILQ_FIRST(&g_fsdev_mgr.fsdevs);
     416           1 :         if (!fsdev) {
     417           1 :                 SPDK_DEBUGLOG(fsdev, "Done unregistering fsdevs\n");
     418             :                 /*
     419             :                  * Fsdev module finish need to be deferred as we might be in the middle of some context
     420             :                  * that will use this fsdev (or private fsdev driver ctx data)
     421             :                  * after returning.
     422             :                  */
     423           1 :                 spdk_thread_send_msg(spdk_get_thread(), fsdev_module_fini_iter, NULL);
     424           1 :                 return;
     425             :         }
     426             : 
     427           0 :         SPDK_DEBUGLOG(fsdev, "Unregistering fsdev '%s'\n", fsdev->name);
     428           0 :         spdk_fsdev_unregister(fsdev, fsdev_finish_unregister_fsdevs_iter, fsdev);
     429           0 :         return;
     430             : }
     431             : 
     432             : void
     433           1 : spdk_fsdev_finish(spdk_fsdev_fini_cb cb_fn, void *cb_arg)
     434             : {
     435           1 :         assert(cb_fn != NULL);
     436           1 :         g_fini_thread = spdk_get_thread();
     437           1 :         g_fini_cb_fn = cb_fn;
     438           1 :         g_fini_cb_arg = cb_arg;
     439           1 :         fsdev_finish_unregister_fsdevs_iter(NULL, 0);
     440           1 : }
     441             : 
     442             : struct spdk_fsdev_io *
     443          37 : fsdev_channel_get_io(struct spdk_fsdev_channel *channel)
     444             : {
     445          37 :         struct spdk_fsdev_mgmt_channel *ch = channel->shared_resource->mgmt_ch;
     446             :         struct spdk_fsdev_io *fsdev_io;
     447             : 
     448          37 :         if (ch->per_thread_cache_count > 0) {
     449          37 :                 fsdev_io = STAILQ_FIRST(&ch->per_thread_cache);
     450          37 :                 STAILQ_REMOVE_HEAD(&ch->per_thread_cache, internal.buf_link);
     451          37 :                 ch->per_thread_cache_count--;
     452             :         } else {
     453           0 :                 fsdev_io = spdk_mempool_get(g_fsdev_mgr.fsdev_io_pool);
     454             :         }
     455             : 
     456          37 :         return fsdev_io;
     457             : }
     458             : 
     459             : void
     460          37 : spdk_fsdev_free_io(struct spdk_fsdev_io *fsdev_io)
     461             : {
     462             :         struct spdk_fsdev_mgmt_channel *ch;
     463             : 
     464          37 :         assert(fsdev_io != NULL);
     465             : 
     466          37 :         ch = fsdev_io->internal.ch->shared_resource->mgmt_ch;
     467             : 
     468          37 :         if (ch->per_thread_cache_count < ch->fsdev_io_cache_size) {
     469          37 :                 ch->per_thread_cache_count++;
     470          37 :                 STAILQ_INSERT_HEAD(&ch->per_thread_cache, fsdev_io, internal.buf_link);
     471             :         } else {
     472           0 :                 spdk_mempool_put(g_fsdev_mgr.fsdev_io_pool, (void *)fsdev_io);
     473             :         }
     474          37 : }
     475             : 
     476             : void
     477          37 : fsdev_io_submit(struct spdk_fsdev_io *fsdev_io)
     478             : {
     479          37 :         struct spdk_fsdev *fsdev = fsdev_io->fsdev;
     480          37 :         struct spdk_fsdev_channel *ch = fsdev_io->internal.ch;
     481          37 :         struct spdk_fsdev_shared_resource *shared_resource = ch->shared_resource;
     482             : 
     483          37 :         TAILQ_INSERT_TAIL(&ch->io_submitted, fsdev_io, internal.ch_link);
     484             : 
     485          37 :         ch->io_outstanding++;
     486          37 :         shared_resource->io_outstanding++;
     487          37 :         fsdev_io->internal.in_submit_request = true;
     488          37 :         fsdev->fn_table->submit_request(ch->channel, fsdev_io);
     489          37 :         fsdev_io->internal.in_submit_request = false;
     490          37 : }
     491             : 
     492             : static void
     493          38 : fsdev_channel_destroy_resource(struct spdk_fsdev_channel *ch)
     494             : {
     495             :         struct spdk_fsdev_shared_resource *shared_resource;
     496             : 
     497          38 :         spdk_put_io_channel(ch->channel);
     498             : 
     499          38 :         shared_resource = ch->shared_resource;
     500             : 
     501          38 :         assert(TAILQ_EMPTY(&ch->io_submitted));
     502          38 :         assert(ch->io_outstanding == 0);
     503          38 :         assert(shared_resource->ref > 0);
     504          38 :         shared_resource->ref--;
     505          38 :         if (shared_resource->ref == 0) {
     506          38 :                 assert(shared_resource->io_outstanding == 0);
     507          38 :                 TAILQ_REMOVE(&shared_resource->mgmt_ch->shared_resources, shared_resource, link);
     508          38 :                 spdk_put_io_channel(spdk_io_channel_from_ctx(shared_resource->mgmt_ch));
     509          38 :                 free(shared_resource);
     510             :         }
     511          38 : }
     512             : 
     513             : static void
     514          39 : fsdev_desc_free(struct spdk_fsdev_desc *desc)
     515             : {
     516          39 :         spdk_spin_destroy(&desc->spinlock);
     517          39 :         free(desc);
     518          39 : }
     519             : 
     520             : 
     521             : static int
     522          38 : fsdev_channel_create(void *io_device, void *ctx_buf)
     523             : {
     524          38 :         struct spdk_fsdev               *fsdev = __fsdev_from_io_dev(io_device);
     525          38 :         struct spdk_fsdev_channel       *ch = ctx_buf;
     526             :         struct spdk_io_channel          *mgmt_io_ch;
     527             :         struct spdk_fsdev_mgmt_channel  *mgmt_ch;
     528             :         struct spdk_fsdev_shared_resource *shared_resource;
     529             : 
     530          38 :         ch->fsdev = fsdev;
     531          38 :         ch->channel = fsdev->fn_table->get_io_channel(fsdev->ctxt);
     532          38 :         if (!ch->channel) {
     533           0 :                 return -1;
     534             :         }
     535             : 
     536          38 :         mgmt_io_ch = spdk_get_io_channel(&g_fsdev_mgr);
     537          38 :         if (!mgmt_io_ch) {
     538           0 :                 spdk_put_io_channel(ch->channel);
     539           0 :                 return -1;
     540             :         }
     541             : 
     542          38 :         mgmt_ch = __io_ch_to_fsdev_mgmt_ch(mgmt_io_ch);
     543          38 :         TAILQ_FOREACH(shared_resource, &mgmt_ch->shared_resources, link) {
     544           0 :                 if (shared_resource->shared_ch == ch->channel) {
     545           0 :                         spdk_put_io_channel(mgmt_io_ch);
     546           0 :                         shared_resource->ref++;
     547           0 :                         break;
     548             :                 }
     549             :         }
     550             : 
     551          38 :         if (shared_resource == NULL) {
     552          38 :                 shared_resource = calloc(1, sizeof(*shared_resource));
     553          38 :                 if (shared_resource == NULL) {
     554           0 :                         spdk_put_io_channel(ch->channel);
     555           0 :                         spdk_put_io_channel(mgmt_io_ch);
     556           0 :                         return -1;
     557             :                 }
     558             : 
     559          38 :                 shared_resource->mgmt_ch = mgmt_ch;
     560          38 :                 shared_resource->io_outstanding = 0;
     561          38 :                 shared_resource->shared_ch = ch->channel;
     562          38 :                 shared_resource->ref = 1;
     563          38 :                 TAILQ_INSERT_TAIL(&mgmt_ch->shared_resources, shared_resource, link);
     564             :         }
     565             : 
     566          38 :         ch->io_outstanding = 0;
     567          38 :         ch->shared_resource = shared_resource;
     568          38 :         TAILQ_INIT(&ch->io_submitted);
     569          38 :         return 0;
     570             : }
     571             : 
     572             : static void
     573          38 : fsdev_channel_destroy(void *io_device, void *ctx_buf)
     574             : {
     575          38 :         struct spdk_fsdev_channel *ch = ctx_buf;
     576             : 
     577          38 :         SPDK_DEBUGLOG(fsdev, "Destroying channel %p for fsdev %s on thread %p\n",
     578             :                       ch, ch->fsdev->name,
     579             :                       spdk_get_thread());
     580          38 :         fsdev_channel_destroy_resource(ch);
     581          38 : }
     582             : 
     583             : /*
     584             :  * If the name already exists in the global fsdev name tree, RB_INSERT() returns a pointer
     585             :  * to it. Hence we do not have to call fsdev_get_by_name() when using this function.
     586             :  */
     587             : static int
     588          39 : fsdev_name_add(struct spdk_fsdev_name *fsdev_name, struct spdk_fsdev *fsdev, const char *name)
     589             : {
     590             :         struct spdk_fsdev_name *tmp;
     591             : 
     592          39 :         fsdev_name->name = strdup(name);
     593          39 :         if (fsdev_name->name == NULL) {
     594           0 :                 SPDK_ERRLOG("Unable to allocate fsdev name\n");
     595           0 :                 return -ENOMEM;
     596             :         }
     597             : 
     598          39 :         fsdev_name->fsdev = fsdev;
     599             : 
     600          39 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
     601          39 :         tmp = RB_INSERT(fsdev_name_tree, &g_fsdev_mgr.fsdev_names, fsdev_name);
     602          39 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
     603          39 :         if (tmp != NULL) {
     604           0 :                 SPDK_ERRLOG("Fsdev name %s already exists\n", name);
     605           0 :                 free(fsdev_name->name);
     606           0 :                 return -EEXIST;
     607             :         }
     608             : 
     609          39 :         return 0;
     610             : }
     611             : 
     612             : static void
     613          39 : fsdev_name_del_unsafe(struct spdk_fsdev_name *fsdev_name)
     614             : {
     615          39 :         RB_REMOVE(fsdev_name_tree, &g_fsdev_mgr.fsdev_names, fsdev_name);
     616          39 :         free(fsdev_name->name);
     617          39 : }
     618             : 
     619             : struct spdk_io_channel *
     620          38 : spdk_fsdev_get_io_channel(struct spdk_fsdev_desc *desc)
     621             : {
     622          38 :         return spdk_get_io_channel(__fsdev_to_io_dev(spdk_fsdev_desc_get_fsdev(desc)));
     623             : }
     624             : 
     625             : int
     626           3 : spdk_fsdev_set_opts(const struct spdk_fsdev_opts *opts)
     627             : {
     628             :         uint32_t min_pool_size;
     629             : 
     630           3 :         if (!opts) {
     631           1 :                 SPDK_ERRLOG("opts cannot be NULL\n");
     632           1 :                 return -EINVAL;
     633             :         }
     634             : 
     635           2 :         if (!opts->opts_size) {
     636           1 :                 SPDK_ERRLOG("opts_size inside opts cannot be zero value\n");
     637           1 :                 return -EINVAL;
     638             :         }
     639             : 
     640             :         /*
     641             :          * Add 1 to the thread count to account for the extra mgmt_ch that gets created during subsystem
     642             :          *  initialization.  A second mgmt_ch will be created on the same thread when the application starts
     643             :          *  but before the deferred put_io_channel event is executed for the first mgmt_ch.
     644             :          */
     645           1 :         min_pool_size = opts->fsdev_io_cache_size * (spdk_thread_get_count() + 1);
     646           1 :         if (opts->fsdev_io_pool_size < min_pool_size) {
     647           0 :                 SPDK_ERRLOG("fsdev_io_pool_size %" PRIu32 " is not compatible with bdev_io_cache_size %" PRIu32
     648             :                             " and %" PRIu32 " threads\n", opts->fsdev_io_pool_size, opts->fsdev_io_cache_size,
     649             :                             spdk_thread_get_count());
     650           0 :                 SPDK_ERRLOG("fsdev_io_pool_size must be at least %" PRIu32 "\n", min_pool_size);
     651           0 :                 return -EINVAL;
     652             :         }
     653             : 
     654             : #define SET_FIELD(field) \
     655             :         if (offsetof(struct spdk_fsdev_opts, field) + sizeof(opts->field) <= opts->opts_size) { \
     656             :                 g_fsdev_opts.field = opts->field; \
     657             :         } \
     658             : 
     659           1 :         SET_FIELD(fsdev_io_pool_size);
     660           1 :         SET_FIELD(fsdev_io_cache_size);
     661             : 
     662           1 :         g_fsdev_opts.opts_size = opts->opts_size;
     663             : 
     664             : #undef SET_FIELD
     665             : 
     666           1 :         return 0;
     667             : }
     668             : 
     669             : int
     670           2 : spdk_fsdev_get_opts(struct spdk_fsdev_opts *opts, size_t opts_size)
     671             : {
     672           2 :         if (!opts) {
     673           0 :                 SPDK_ERRLOG("opts should not be NULL\n");
     674           0 :                 return -EINVAL;
     675             :         }
     676             : 
     677           2 :         if (!opts_size) {
     678           0 :                 SPDK_ERRLOG("opts_size should not be zero value\n");
     679           0 :                 return -EINVAL;
     680             :         }
     681             : 
     682           2 :         opts->opts_size = opts_size;
     683             : 
     684             : #define SET_FIELD(field) \
     685             :         if (offsetof(struct spdk_fsdev_opts, field) + sizeof(opts->field) <= opts_size) { \
     686             :                 opts->field = g_fsdev_opts.field; \
     687             :         }
     688             : 
     689           2 :         SET_FIELD(fsdev_io_pool_size);
     690           2 :         SET_FIELD(fsdev_io_cache_size);
     691             : 
     692             :         /* Do not remove this statement, you should always update this statement when you adding a new field,
     693             :          * and do not forget to add the SET_FIELD statement for your added field. */
     694             :         SPDK_STATIC_ASSERT(sizeof(struct spdk_fsdev_opts) == 12, "Incorrect size");
     695             : 
     696             : #undef SET_FIELD
     697           2 :         return 0;
     698             : }
     699             : 
     700             : int
     701           0 : spdk_fsdev_get_memory_domains(struct spdk_fsdev *fsdev, struct spdk_memory_domain **domains,
     702             :                               int array_size)
     703             : {
     704           0 :         if (!fsdev) {
     705           0 :                 return -EINVAL;
     706             :         }
     707             : 
     708           0 :         if (fsdev->fn_table->get_memory_domains) {
     709           0 :                 return fsdev->fn_table->get_memory_domains(fsdev->ctxt, domains, array_size);
     710             :         }
     711             : 
     712           0 :         return 0;
     713             : }
     714             : 
     715             : const char *
     716           1 : spdk_fsdev_get_module_name(const struct spdk_fsdev *fsdev)
     717             : {
     718           1 :         return fsdev->module->name;
     719             : }
     720             : 
     721             : const char *
     722          79 : spdk_fsdev_get_name(const struct spdk_fsdev *fsdev)
     723             : {
     724          79 :         return fsdev->name;
     725             : }
     726             : 
     727             : static inline void
     728          74 : fsdev_io_complete(void *ctx)
     729             : {
     730          74 :         struct spdk_fsdev_io *fsdev_io = ctx;
     731          74 :         struct spdk_fsdev_channel *fsdev_ch = fsdev_io->internal.ch;
     732             : 
     733          74 :         if (spdk_unlikely(fsdev_io->internal.in_submit_request)) {
     734             :                 /*
     735             :                  * Defer completion to avoid potential infinite recursion if the
     736             :                  * user's completion callback issues a new I/O.
     737             :                  */
     738          37 :                 spdk_thread_send_msg(spdk_fsdev_io_get_thread(fsdev_io),
     739             :                                      fsdev_io_complete, fsdev_io);
     740          37 :                 return;
     741             :         }
     742             : 
     743          37 :         TAILQ_REMOVE(&fsdev_ch->io_submitted, fsdev_io, internal.ch_link);
     744             : 
     745          37 :         assert(fsdev_io->internal.cb_fn != NULL);
     746          37 :         assert(spdk_get_thread() == spdk_fsdev_io_get_thread(fsdev_io));
     747          37 :         fsdev_io->internal.cb_fn(fsdev_io, fsdev_io->internal.cb_arg);
     748             : }
     749             : 
     750             : 
     751             : void
     752          37 : spdk_fsdev_io_complete(struct spdk_fsdev_io *fsdev_io, int status)
     753             : {
     754          37 :         struct spdk_fsdev_channel *fsdev_ch = fsdev_io->internal.ch;
     755          37 :         struct spdk_fsdev_shared_resource *shared_resource = fsdev_ch->shared_resource;
     756             : 
     757          37 :         assert(status <= 0);
     758          37 :         fsdev_io->internal.status = status;
     759          37 :         assert(fsdev_ch->io_outstanding > 0);
     760          37 :         assert(shared_resource->io_outstanding > 0);
     761          37 :         fsdev_ch->io_outstanding--;
     762          37 :         shared_resource->io_outstanding--;
     763          37 :         fsdev_io_complete(fsdev_io);
     764          37 : }
     765             : 
     766             : struct spdk_thread *
     767          74 : spdk_fsdev_io_get_thread(struct spdk_fsdev_io *fsdev_io)
     768             : {
     769          74 :         return spdk_io_channel_get_thread(fsdev_io->internal.ch->channel);
     770             : }
     771             : 
     772             : struct spdk_io_channel *
     773           0 : spdk_fsdev_io_get_io_channel(struct spdk_fsdev_io *fsdev_io)
     774             : {
     775           0 :         return fsdev_io->internal.ch->channel;
     776             : }
     777             : 
     778             : static int
     779          39 : fsdev_register(struct spdk_fsdev *fsdev)
     780             : {
     781             :         char *fsdev_name;
     782             :         int ret;
     783             : 
     784          39 :         assert(fsdev->module != NULL);
     785             : 
     786          39 :         if (!fsdev->name) {
     787           0 :                 SPDK_ERRLOG("Fsdev name is NULL\n");
     788           0 :                 return -EINVAL;
     789             :         }
     790             : 
     791          39 :         if (!strlen(fsdev->name)) {
     792           0 :                 SPDK_ERRLOG("Fsdev name must not be an empty string\n");
     793           0 :                 return -EINVAL;
     794             :         }
     795             : 
     796             :         /* Users often register their own I/O devices using the fsdev name. In
     797             :          * order to avoid conflicts, prepend fsdev_. */
     798          39 :         fsdev_name = spdk_sprintf_alloc("fsdev_%s", fsdev->name);
     799          39 :         if (!fsdev_name) {
     800           0 :                 SPDK_ERRLOG("Unable to allocate memory for internal fsdev name.\n");
     801           0 :                 return -ENOMEM;
     802             :         }
     803             : 
     804          39 :         fsdev->internal.status = SPDK_FSDEV_STATUS_READY;
     805          39 :         TAILQ_INIT(&fsdev->internal.open_descs);
     806             : 
     807          39 :         ret = fsdev_name_add(&fsdev->internal.fsdev_name, fsdev, fsdev->name);
     808          39 :         if (ret != 0) {
     809           0 :                 free(fsdev_name);
     810           0 :                 return ret;
     811             :         }
     812             : 
     813          39 :         spdk_io_device_register(__fsdev_to_io_dev(fsdev),
     814             :                                 fsdev_channel_create, fsdev_channel_destroy,
     815             :                                 sizeof(struct spdk_fsdev_channel),
     816             :                                 fsdev_name);
     817             : 
     818          39 :         free(fsdev_name);
     819             : 
     820          39 :         spdk_spin_init(&fsdev->internal.spinlock);
     821             : 
     822          39 :         SPDK_DEBUGLOG(fsdev, "Inserting fsdev %s into list\n", fsdev->name);
     823          39 :         TAILQ_INSERT_TAIL(&g_fsdev_mgr.fsdevs, fsdev, internal.link);
     824          39 :         return 0;
     825             : }
     826             : 
     827             : static void
     828          39 : fsdev_destroy_cb(void *io_device)
     829             : {
     830             :         int                     rc;
     831             :         struct spdk_fsdev       *fsdev;
     832             :         spdk_fsdev_unregister_cb cb_fn;
     833             :         void                    *cb_arg;
     834             : 
     835          39 :         fsdev = __fsdev_from_io_dev(io_device);
     836          39 :         cb_fn = fsdev->internal.unregister_cb;
     837          39 :         cb_arg = fsdev->internal.unregister_ctx;
     838             : 
     839          39 :         spdk_spin_destroy(&fsdev->internal.spinlock);
     840             : 
     841          39 :         rc = fsdev->fn_table->destruct(fsdev->ctxt);
     842          39 :         if (rc < 0) {
     843           0 :                 SPDK_ERRLOG("destruct failed\n");
     844             :         }
     845          39 :         if (rc <= 0 && cb_fn != NULL) {
     846          39 :                 cb_fn(cb_arg, rc);
     847             :         }
     848          39 : }
     849             : 
     850             : void
     851           0 : spdk_fsdev_destruct_done(struct spdk_fsdev *fsdev, int fsdeverrno)
     852             : {
     853           0 :         if (fsdev->internal.unregister_cb != NULL) {
     854           0 :                 fsdev->internal.unregister_cb(fsdev->internal.unregister_ctx, fsdeverrno);
     855             :         }
     856           0 : }
     857             : 
     858             : static void
     859           0 : _remove_notify(void *arg)
     860             : {
     861           0 :         struct spdk_fsdev_desc *desc = arg;
     862             : 
     863           0 :         spdk_spin_lock(&desc->spinlock);
     864           0 :         desc->refs--;
     865             : 
     866           0 :         if (!desc->closed) {
     867           0 :                 spdk_spin_unlock(&desc->spinlock);
     868           0 :                 desc->callback.event_fn(SPDK_FSDEV_EVENT_REMOVE, desc->fsdev, desc->callback.ctx);
     869           0 :                 return;
     870           0 :         } else if (0 == desc->refs) {
     871             :                 /* This descriptor was closed after this remove_notify message was sent.
     872             :                  * spdk_fsdev_close() could not free the descriptor since this message was
     873             :                  * in flight, so we free it now using fsdev_desc_free().
     874             :                  */
     875           0 :                 spdk_spin_unlock(&desc->spinlock);
     876           0 :                 fsdev_desc_free(desc);
     877           0 :                 return;
     878             :         }
     879           0 :         spdk_spin_unlock(&desc->spinlock);
     880             : }
     881             : 
     882             : /* Must be called while holding g_fsdev_mgr.mutex and fsdev->internal.spinlock.
     883             :  * returns: 0 - fsdev removed and ready to be destructed.
     884             :  *          -EBUSY - fsdev can't be destructed yet.  */
     885             : static int
     886          39 : fsdev_unregister_unsafe(struct spdk_fsdev *fsdev)
     887             : {
     888             :         struct spdk_fsdev_desc  *desc, *tmp;
     889          39 :         int                     rc = 0;
     890             : 
     891             :         /* Notify each descriptor about hotremoval */
     892          39 :         TAILQ_FOREACH_SAFE(desc, &fsdev->internal.open_descs, link, tmp) {
     893           0 :                 rc = -EBUSY;
     894           0 :                 spdk_spin_lock(&desc->spinlock);
     895             :                 /*
     896             :                  * Defer invocation of the event_cb to a separate message that will
     897             :                  *  run later on its thread.  This ensures this context unwinds and
     898             :                  *  we don't recursively unregister this fsdev again if the event_cb
     899             :                  *  immediately closes its descriptor.
     900             :                  */
     901           0 :                 desc->refs++;
     902           0 :                 spdk_thread_send_msg(desc->thread, _remove_notify, desc);
     903           0 :                 spdk_spin_unlock(&desc->spinlock);
     904             :         }
     905             : 
     906             :         /* If there are no descriptors, proceed removing the fsdev */
     907          39 :         if (rc == 0) {
     908          39 :                 TAILQ_REMOVE(&g_fsdev_mgr.fsdevs, fsdev, internal.link);
     909          39 :                 SPDK_DEBUGLOG(fsdev, "Removing fsdev %s from list done\n", fsdev->name);
     910          39 :                 fsdev_name_del_unsafe(&fsdev->internal.fsdev_name);
     911          39 :                 spdk_notify_send("fsdev_unregister", spdk_fsdev_get_name(fsdev));
     912             :         }
     913             : 
     914          39 :         return rc;
     915             : }
     916             : 
     917             : static void
     918          39 : fsdev_unregister(struct spdk_fsdev *fsdev, void *_ctx, int status)
     919             : {
     920             :         int rc;
     921             : 
     922          39 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
     923          39 :         spdk_spin_lock(&fsdev->internal.spinlock);
     924             :         /*
     925             :          * Set the status to REMOVING after completing to abort channels. Otherwise,
     926             :          * the last spdk_fsdev_close() may call spdk_io_device_unregister() while
     927             :          * spdk_fsdev_for_each_channel() is executed and spdk_io_device_unregister()
     928             :          * may fail.
     929             :          */
     930          39 :         fsdev->internal.status = SPDK_FSDEV_STATUS_REMOVING;
     931          39 :         rc = fsdev_unregister_unsafe(fsdev);
     932          39 :         spdk_spin_unlock(&fsdev->internal.spinlock);
     933          39 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
     934             : 
     935          39 :         if (rc == 0) {
     936          39 :                 spdk_io_device_unregister(__fsdev_to_io_dev(fsdev), fsdev_destroy_cb);
     937             :         }
     938          39 : }
     939             : 
     940             : void
     941          39 : spdk_fsdev_unregister(struct spdk_fsdev *fsdev, spdk_fsdev_unregister_cb cb_fn, void *cb_arg)
     942             : {
     943             :         struct spdk_thread      *thread;
     944             : 
     945          39 :         SPDK_DEBUGLOG(fsdev, "Removing fsdev %s from list\n", fsdev->name);
     946             : 
     947          39 :         thread = spdk_get_thread();
     948          39 :         if (!thread) {
     949             :                 /* The user called this from a non-SPDK thread. */
     950           0 :                 if (cb_fn != NULL) {
     951           0 :                         cb_fn(cb_arg, -ENOTSUP);
     952             :                 }
     953           0 :                 return;
     954             :         }
     955             : 
     956          39 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
     957          39 :         if (fsdev->internal.status == SPDK_FSDEV_STATUS_UNREGISTERING ||
     958          39 :             fsdev->internal.status == SPDK_FSDEV_STATUS_REMOVING) {
     959           0 :                 spdk_spin_unlock(&g_fsdev_mgr.spinlock);
     960           0 :                 if (cb_fn) {
     961           0 :                         cb_fn(cb_arg, -EBUSY);
     962             :                 }
     963           0 :                 return;
     964             :         }
     965             : 
     966          39 :         spdk_spin_lock(&fsdev->internal.spinlock);
     967          39 :         fsdev->internal.status = SPDK_FSDEV_STATUS_UNREGISTERING;
     968          39 :         fsdev->internal.unregister_cb = cb_fn;
     969          39 :         fsdev->internal.unregister_ctx = cb_arg;
     970          39 :         spdk_spin_unlock(&fsdev->internal.spinlock);
     971          39 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
     972             : 
     973             :         /* @todo: bdev aborts IOs on all channels here. */
     974          39 :         fsdev_unregister(fsdev, fsdev, 0);
     975             : }
     976             : 
     977             : static void
     978           0 : _tmp_fsdev_event_cb(enum spdk_fsdev_event_type type, struct spdk_fsdev *fsdev, void *ctx)
     979             : {
     980           0 :         SPDK_NOTICELOG("Unexpected fsdev event type: %d\n", type);
     981           0 : }
     982             : 
     983             : int
     984           0 : spdk_fsdev_unregister_by_name(const char *fsdev_name, struct spdk_fsdev_module *module,
     985             :                               spdk_fsdev_unregister_cb cb_fn, void *cb_arg)
     986             : {
     987           0 :         struct spdk_fsdev_desc *desc;
     988             :         struct spdk_fsdev *fsdev;
     989             :         int rc;
     990             : 
     991           0 :         rc = spdk_fsdev_open(fsdev_name, _tmp_fsdev_event_cb, NULL, &desc);
     992           0 :         if (rc != 0) {
     993           0 :                 SPDK_ERRLOG("Failed to open fsdev with name: %s\n", fsdev_name);
     994           0 :                 return rc;
     995             :         }
     996             : 
     997           0 :         fsdev = spdk_fsdev_desc_get_fsdev(desc);
     998             : 
     999           0 :         if (fsdev->module != module) {
    1000           0 :                 spdk_fsdev_close(desc);
    1001           0 :                 SPDK_ERRLOG("Fsdev %s was not registered by the specified module.\n",
    1002             :                             fsdev_name);
    1003           0 :                 return -ENODEV;
    1004             :         }
    1005             : 
    1006           0 :         spdk_fsdev_unregister(fsdev, cb_fn, cb_arg);
    1007           0 :         spdk_fsdev_close(desc);
    1008             : 
    1009           0 :         return 0;
    1010             : }
    1011             : 
    1012             : static int
    1013          39 : fsdev_open(struct spdk_fsdev *fsdev, struct spdk_fsdev_desc *desc)
    1014             : {
    1015             :         struct spdk_thread *thread;
    1016             : 
    1017          39 :         thread = spdk_get_thread();
    1018          39 :         if (!thread) {
    1019           0 :                 SPDK_ERRLOG("Cannot open fsdev from non-SPDK thread.\n");
    1020           0 :                 return -ENOTSUP;
    1021             :         }
    1022             : 
    1023          39 :         SPDK_DEBUGLOG(fsdev, "Opening descriptor %p for fsdev %s on thread %p\n",
    1024             :                       desc, fsdev->name, spdk_get_thread());
    1025             : 
    1026          39 :         desc->fsdev = fsdev;
    1027          39 :         desc->thread = thread;
    1028             : 
    1029          39 :         spdk_spin_lock(&fsdev->internal.spinlock);
    1030          39 :         if (fsdev->internal.status == SPDK_FSDEV_STATUS_UNREGISTERING ||
    1031          39 :             fsdev->internal.status == SPDK_FSDEV_STATUS_REMOVING) {
    1032           0 :                 spdk_spin_unlock(&fsdev->internal.spinlock);
    1033           0 :                 return -ENODEV;
    1034             :         }
    1035             : 
    1036          39 :         TAILQ_INSERT_TAIL(&fsdev->internal.open_descs, desc, link);
    1037          39 :         spdk_spin_unlock(&fsdev->internal.spinlock);
    1038          39 :         return 0;
    1039             : }
    1040             : 
    1041             : static int
    1042          39 : fsdev_desc_alloc(struct spdk_fsdev *fsdev, spdk_fsdev_event_cb_t event_cb, void *event_ctx,
    1043             :                  struct spdk_fsdev_desc **_desc)
    1044             : {
    1045             :         struct spdk_fsdev_desc *desc;
    1046             : 
    1047          39 :         desc = calloc(1, sizeof(*desc));
    1048          39 :         if (desc == NULL) {
    1049           0 :                 SPDK_ERRLOG("Failed to allocate memory for fsdev descriptor\n");
    1050           0 :                 return -ENOMEM;
    1051             :         }
    1052             : 
    1053          39 :         desc->callback.event_fn = event_cb;
    1054          39 :         desc->callback.ctx = event_ctx;
    1055          39 :         spdk_spin_init(&desc->spinlock);
    1056          39 :         *_desc = desc;
    1057          39 :         return 0;
    1058             : }
    1059             : 
    1060             : int
    1061          39 : spdk_fsdev_open(const char *fsdev_name, spdk_fsdev_event_cb_t event_cb, void *event_ctx,
    1062             :                 struct spdk_fsdev_desc **_desc)
    1063             : {
    1064          39 :         struct spdk_fsdev_desc *desc;
    1065             :         struct spdk_fsdev *fsdev;
    1066             :         int rc;
    1067             : 
    1068          39 :         if (event_cb == NULL) {
    1069           0 :                 SPDK_ERRLOG("Missing event callback function\n");
    1070           0 :                 return -EINVAL;
    1071             :         }
    1072             : 
    1073          39 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
    1074             : 
    1075          39 :         fsdev = fsdev_get_by_name(fsdev_name);
    1076          39 :         if (fsdev == NULL) {
    1077           0 :                 SPDK_NOTICELOG("Currently unable to find fsdev with name: %s\n", fsdev_name);
    1078           0 :                 spdk_spin_unlock(&g_fsdev_mgr.spinlock);
    1079           0 :                 return -ENODEV;
    1080             :         }
    1081             : 
    1082          39 :         rc = fsdev_desc_alloc(fsdev, event_cb, event_ctx, &desc);
    1083          39 :         if (rc != 0) {
    1084           0 :                 spdk_spin_unlock(&g_fsdev_mgr.spinlock);
    1085           0 :                 return rc;
    1086             :         }
    1087             : 
    1088          39 :         rc = fsdev_open(fsdev, desc);
    1089          39 :         if (rc != 0) {
    1090           0 :                 fsdev_desc_free(desc);
    1091           0 :                 desc = NULL;
    1092             :         }
    1093             : 
    1094          39 :         *_desc = desc;
    1095          39 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
    1096          39 :         return rc;
    1097             : }
    1098             : 
    1099             : static void
    1100          39 : fsdev_close(struct spdk_fsdev *fsdev, struct spdk_fsdev_desc *desc)
    1101             : {
    1102             :         int rc;
    1103             : 
    1104          39 :         spdk_spin_lock(&fsdev->internal.spinlock);
    1105          39 :         spdk_spin_lock(&desc->spinlock);
    1106             : 
    1107          39 :         TAILQ_REMOVE(&fsdev->internal.open_descs, desc, link);
    1108          39 :         desc->closed = true;
    1109          39 :         if (0 == desc->refs) {
    1110          39 :                 spdk_spin_unlock(&desc->spinlock);
    1111          39 :                 fsdev_desc_free(desc);
    1112             :         } else {
    1113           0 :                 spdk_spin_unlock(&desc->spinlock);
    1114             :         }
    1115             : 
    1116          39 :         if (fsdev->internal.status == SPDK_FSDEV_STATUS_REMOVING &&
    1117           0 :             TAILQ_EMPTY(&fsdev->internal.open_descs)) {
    1118           0 :                 rc = fsdev_unregister_unsafe(fsdev);
    1119           0 :                 spdk_spin_unlock(&fsdev->internal.spinlock);
    1120             : 
    1121           0 :                 if (rc == 0) {
    1122           0 :                         spdk_io_device_unregister(__fsdev_to_io_dev(fsdev), fsdev_destroy_cb);
    1123             :                 }
    1124             :         } else {
    1125          39 :                 spdk_spin_unlock(&fsdev->internal.spinlock);
    1126             :         }
    1127          39 : }
    1128             : 
    1129             : void
    1130          39 : spdk_fsdev_close(struct spdk_fsdev_desc *desc)
    1131             : {
    1132          39 :         struct spdk_fsdev *fsdev = spdk_fsdev_desc_get_fsdev(desc);
    1133             : 
    1134          39 :         SPDK_DEBUGLOG(fsdev, "Closing descriptor %p for fsdev %s on thread %p\n",
    1135             :                       desc, fsdev->name, spdk_get_thread());
    1136          39 :         assert(desc->thread == spdk_get_thread());
    1137          39 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
    1138          39 :         fsdev_close(fsdev, desc);
    1139          39 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
    1140          39 : }
    1141             : 
    1142             : int
    1143          39 : spdk_fsdev_register(struct spdk_fsdev *fsdev)
    1144             : {
    1145             :         int rc;
    1146             : 
    1147          39 :         rc = fsdev_register(fsdev);
    1148          39 :         if (rc != 0) {
    1149           0 :                 return rc;
    1150             :         }
    1151             : 
    1152          39 :         spdk_notify_send("fsdev_register", spdk_fsdev_get_name(fsdev));
    1153          39 :         return rc;
    1154             : }
    1155             : 
    1156             : struct spdk_fsdev *
    1157         116 : spdk_fsdev_desc_get_fsdev(struct spdk_fsdev_desc *desc)
    1158             : {
    1159         116 :         assert(desc != NULL);
    1160         116 :         return desc->fsdev;
    1161             : }
    1162             : 
    1163             : void
    1164           1 : spdk_fsdev_module_list_add(struct spdk_fsdev_module *fsdev_module)
    1165             : {
    1166             : 
    1167           1 :         if (spdk_fsdev_module_list_find(fsdev_module->name)) {
    1168           0 :                 SPDK_ERRLOG("ERROR: module '%s' already registered.\n", fsdev_module->name);
    1169           0 :                 assert(false);
    1170             :         }
    1171             : 
    1172           1 :         TAILQ_INSERT_TAIL(&g_fsdev_mgr.fsdev_modules, fsdev_module, internal.tailq);
    1173           1 : }
    1174             : 
    1175             : struct spdk_fsdev_module *
    1176           1 : spdk_fsdev_module_list_find(const char *name)
    1177             : {
    1178             :         struct spdk_fsdev_module *fsdev_module;
    1179             : 
    1180           1 :         TAILQ_FOREACH(fsdev_module, &g_fsdev_mgr.fsdev_modules, internal.tailq) {
    1181           0 :                 if (strcmp(name, fsdev_module->name) == 0) {
    1182           0 :                         break;
    1183             :                 }
    1184             :         }
    1185             : 
    1186           1 :         return fsdev_module;
    1187             : }
    1188             : 
    1189           1 : SPDK_LOG_REGISTER_COMPONENT(fsdev)

Generated by: LCOV version 1.15