LCOV - code coverage report
Current view: top level - lib/fsdev - fsdev.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 383 542 70.7 %
Date: 2024-08-13 06:03:55 Functions: 50 64 78.1 %

          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          38 : fsdev_name_cmp(struct spdk_fsdev_name *name1, struct spdk_fsdev_name *name2)
      32             : {
      33          38 :         return strcmp(name1->name, name2->name);
      34             : }
      35             : 
      36         152 : 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          38 : fsdev_get_by_name(const char *fsdev_name)
     154             : {
     155          38 :         struct spdk_fsdev_name find;
     156             :         struct spdk_fsdev_name *res;
     157             : 
     158          38 :         find.name = (char *)fsdev_name;
     159          38 :         res = RB_FIND(fsdev_name_tree, &g_fsdev_mgr.fsdev_names, &find);
     160          38 :         if (res != NULL) {
     161          38 :                 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          35 : fsdev_mgmt_channel_destroy(void *io_device, void *ctx_buf)
     220             : {
     221          35 :         struct spdk_fsdev_mgmt_channel *ch = ctx_buf;
     222             :         struct spdk_fsdev_io *fsdev_io;
     223             : 
     224          35 :         if (!TAILQ_EMPTY(&ch->shared_resources)) {
     225           0 :                 SPDK_ERRLOG("Module channel list wasn't empty on mgmt channel free\n");
     226             :         }
     227             : 
     228       17955 :         while (!STAILQ_EMPTY(&ch->per_thread_cache)) {
     229       17920 :                 fsdev_io = STAILQ_FIRST(&ch->per_thread_cache);
     230       17920 :                 STAILQ_REMOVE_HEAD(&ch->per_thread_cache, internal.buf_link);
     231       17920 :                 ch->per_thread_cache_count--;
     232       17920 :                 spdk_mempool_put(g_fsdev_mgr.fsdev_io_pool, (void *)fsdev_io);
     233             :         }
     234             : 
     235          35 :         assert(ch->per_thread_cache_count == 0);
     236          35 :         return;
     237             : }
     238             : 
     239             : static int
     240          35 : fsdev_mgmt_channel_create(void *io_device, void *ctx_buf)
     241             : {
     242          35 :         struct spdk_fsdev_mgmt_channel *ch = ctx_buf;
     243             :         struct spdk_fsdev_io *fsdev_io;
     244             :         uint32_t i;
     245             : 
     246          35 :         STAILQ_INIT(&ch->per_thread_cache);
     247          35 :         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          35 :         ch->per_thread_cache_count = 0;
     251       17955 :         for (i = 0; i < ch->fsdev_io_cache_size; i++) {
     252       17920 :                 fsdev_io = spdk_mempool_get(g_fsdev_mgr.fsdev_io_pool);
     253       17920 :                 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       17920 :                 ch->per_thread_cache_count++;
     260       17920 :                 STAILQ_INSERT_HEAD(&ch->per_thread_cache, fsdev_io, internal.buf_link);
     261             :         }
     262             : 
     263          35 :         TAILQ_INIT(&ch->shared_resources);
     264          35 :         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_SOCKET_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          34 : fsdev_channel_get_io(struct spdk_fsdev_channel *channel)
     444             : {
     445          34 :         struct spdk_fsdev_mgmt_channel *ch = channel->shared_resource->mgmt_ch;
     446             :         struct spdk_fsdev_io *fsdev_io;
     447             : 
     448          34 :         if (ch->per_thread_cache_count > 0) {
     449          34 :                 fsdev_io = STAILQ_FIRST(&ch->per_thread_cache);
     450          34 :                 STAILQ_REMOVE_HEAD(&ch->per_thread_cache, internal.buf_link);
     451          34 :                 ch->per_thread_cache_count--;
     452             :         } else {
     453           0 :                 fsdev_io = spdk_mempool_get(g_fsdev_mgr.fsdev_io_pool);
     454             :         }
     455             : 
     456          34 :         return fsdev_io;
     457             : }
     458             : 
     459             : void
     460          34 : spdk_fsdev_free_io(struct spdk_fsdev_io *fsdev_io)
     461             : {
     462             :         struct spdk_fsdev_mgmt_channel *ch;
     463             : 
     464          34 :         assert(fsdev_io != NULL);
     465             : 
     466          34 :         ch = fsdev_io->internal.ch->shared_resource->mgmt_ch;
     467             : 
     468          34 :         if (ch->per_thread_cache_count < ch->fsdev_io_cache_size) {
     469          34 :                 ch->per_thread_cache_count++;
     470          34 :                 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          34 : }
     475             : 
     476             : void
     477          34 : fsdev_io_submit(struct spdk_fsdev_io *fsdev_io)
     478             : {
     479          34 :         struct spdk_fsdev *fsdev = fsdev_io->fsdev;
     480          34 :         struct spdk_fsdev_channel *ch = fsdev_io->internal.ch;
     481          34 :         struct spdk_fsdev_shared_resource *shared_resource = ch->shared_resource;
     482             : 
     483          34 :         TAILQ_INSERT_TAIL(&ch->io_submitted, fsdev_io, internal.ch_link);
     484             : 
     485          34 :         ch->io_outstanding++;
     486          34 :         shared_resource->io_outstanding++;
     487          34 :         fsdev_io->internal.in_submit_request = true;
     488          34 :         fsdev->fn_table->submit_request(ch->channel, fsdev_io);
     489          34 :         fsdev_io->internal.in_submit_request = false;
     490          34 : }
     491             : 
     492             : static void
     493          35 : fsdev_channel_destroy_resource(struct spdk_fsdev_channel *ch)
     494             : {
     495             :         struct spdk_fsdev_shared_resource *shared_resource;
     496             : 
     497          35 :         spdk_put_io_channel(ch->channel);
     498             : 
     499          35 :         shared_resource = ch->shared_resource;
     500             : 
     501          35 :         assert(TAILQ_EMPTY(&ch->io_submitted));
     502          35 :         assert(ch->io_outstanding == 0);
     503          35 :         assert(shared_resource->ref > 0);
     504          35 :         shared_resource->ref--;
     505          35 :         if (shared_resource->ref == 0) {
     506          35 :                 assert(shared_resource->io_outstanding == 0);
     507          35 :                 TAILQ_REMOVE(&shared_resource->mgmt_ch->shared_resources, shared_resource, link);
     508          35 :                 spdk_put_io_channel(spdk_io_channel_from_ctx(shared_resource->mgmt_ch));
     509          35 :                 free(shared_resource);
     510             :         }
     511          35 : }
     512             : 
     513             : static void
     514          38 : fsdev_desc_free(struct spdk_fsdev_desc *desc)
     515             : {
     516          38 :         spdk_spin_destroy(&desc->spinlock);
     517          38 :         free(desc);
     518          38 : }
     519             : 
     520             : 
     521             : static int
     522          35 : fsdev_channel_create(void *io_device, void *ctx_buf)
     523             : {
     524          35 :         struct spdk_fsdev               *fsdev = __fsdev_from_io_dev(io_device);
     525          35 :         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          35 :         ch->fsdev = fsdev;
     531          35 :         ch->channel = fsdev->fn_table->get_io_channel(fsdev->ctxt);
     532          35 :         if (!ch->channel) {
     533           0 :                 return -1;
     534             :         }
     535             : 
     536          35 :         mgmt_io_ch = spdk_get_io_channel(&g_fsdev_mgr);
     537          35 :         if (!mgmt_io_ch) {
     538           0 :                 spdk_put_io_channel(ch->channel);
     539           0 :                 return -1;
     540             :         }
     541             : 
     542          35 :         mgmt_ch = __io_ch_to_fsdev_mgmt_ch(mgmt_io_ch);
     543          35 :         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          35 :         if (shared_resource == NULL) {
     552          35 :                 shared_resource = calloc(1, sizeof(*shared_resource));
     553          35 :                 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          35 :                 shared_resource->mgmt_ch = mgmt_ch;
     560          35 :                 shared_resource->io_outstanding = 0;
     561          35 :                 shared_resource->shared_ch = ch->channel;
     562          35 :                 shared_resource->ref = 1;
     563          35 :                 TAILQ_INSERT_TAIL(&mgmt_ch->shared_resources, shared_resource, link);
     564             :         }
     565             : 
     566          35 :         ch->io_outstanding = 0;
     567          35 :         ch->shared_resource = shared_resource;
     568          35 :         TAILQ_INIT(&ch->io_submitted);
     569          35 :         return 0;
     570             : }
     571             : 
     572             : static void
     573          35 : fsdev_channel_destroy(void *io_device, void *ctx_buf)
     574             : {
     575          35 :         struct spdk_fsdev_channel *ch = ctx_buf;
     576             : 
     577          35 :         SPDK_DEBUGLOG(fsdev, "Destroying channel %p for fsdev %s on thread %p\n",
     578             :                       ch, ch->fsdev->name,
     579             :                       spdk_get_thread());
     580          35 :         fsdev_channel_destroy_resource(ch);
     581          35 : }
     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          38 : 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          38 :         fsdev_name->name = strdup(name);
     593          38 :         if (fsdev_name->name == NULL) {
     594           0 :                 SPDK_ERRLOG("Unable to allocate fsdev name\n");
     595           0 :                 return -ENOMEM;
     596             :         }
     597             : 
     598          38 :         fsdev_name->fsdev = fsdev;
     599             : 
     600          38 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
     601          38 :         tmp = RB_INSERT(fsdev_name_tree, &g_fsdev_mgr.fsdev_names, fsdev_name);
     602          38 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
     603          38 :         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          38 :         return 0;
     610             : }
     611             : 
     612             : static void
     613          38 : fsdev_name_del_unsafe(struct spdk_fsdev_name *fsdev_name)
     614             : {
     615          38 :         RB_REMOVE(fsdev_name_tree, &g_fsdev_mgr.fsdev_names, fsdev_name);
     616          38 :         free(fsdev_name->name);
     617          38 : }
     618             : 
     619             : struct spdk_io_channel *
     620          35 : spdk_fsdev_get_io_channel(struct spdk_fsdev_desc *desc)
     621             : {
     622          35 :         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             : static int
     701           2 : fsdev_set_open_opts(struct spdk_fsdev *fsdev, struct spdk_fsdev_open_opts *opts)
     702             : {
     703             :         int res;
     704             : 
     705           2 :         assert(opts);
     706             : 
     707           2 :         if (!opts->opts_size) {
     708           0 :                 SPDK_ERRLOG("opts_size should not be zero value\n");
     709           0 :                 return -EINVAL;
     710             :         }
     711             : 
     712           2 :         if (!fsdev->fn_table->negotiate_opts) {
     713           0 :                 SPDK_ERRLOG("negotiate_opts is NULL for %s\n", spdk_fsdev_get_name(fsdev));
     714           0 :                 return -ENOTSUP;
     715             :         }
     716             : 
     717           2 :         res = fsdev->fn_table->negotiate_opts(fsdev->ctxt, opts);
     718           2 :         if (res) {
     719           1 :                 SPDK_ERRLOG("negotiate_opts failed with %d for %s\n", res, spdk_fsdev_get_name(fsdev));
     720           1 :                 return res;
     721             :         }
     722             : 
     723             : #define SET_FIELD(field) \
     724             :         if (offsetof(struct spdk_fsdev_open_opts, field) + sizeof(opts->field) <= opts->opts_size) { \
     725             :                 fsdev->opts.field = opts->field; \
     726             :         }
     727             : 
     728           1 :         SET_FIELD(writeback_cache_enabled);
     729           1 :         SET_FIELD(max_write);
     730             : 
     731             :         /* Do not remove this statement, you should always update this statement when you adding a new field,
     732             :                 * and do not forget to add the SET_FIELD statement for your added field. */
     733             :         SPDK_STATIC_ASSERT(sizeof(struct spdk_fsdev_open_opts) == 9, "Incorrect size");
     734             : #undef SET_FIELD
     735             : 
     736           1 :         return 0;
     737             : }
     738             : 
     739             : int
     740           0 : spdk_fsdev_get_memory_domains(struct spdk_fsdev *fsdev, struct spdk_memory_domain **domains,
     741             :                               int array_size)
     742             : {
     743           0 :         if (!fsdev) {
     744           0 :                 return -EINVAL;
     745             :         }
     746             : 
     747           0 :         if (fsdev->fn_table->get_memory_domains) {
     748           0 :                 return fsdev->fn_table->get_memory_domains(fsdev->ctxt, domains, array_size);
     749             :         }
     750             : 
     751           0 :         return 0;
     752             : }
     753             : 
     754             : const char *
     755           3 : spdk_fsdev_get_module_name(const struct spdk_fsdev *fsdev)
     756             : {
     757           3 :         return fsdev->module->name;
     758             : }
     759             : 
     760             : const char *
     761          80 : spdk_fsdev_get_name(const struct spdk_fsdev *fsdev)
     762             : {
     763          80 :         return fsdev->name;
     764             : }
     765             : 
     766             : static inline void
     767          68 : fsdev_io_complete(void *ctx)
     768             : {
     769          68 :         struct spdk_fsdev_io *fsdev_io = ctx;
     770          68 :         struct spdk_fsdev_channel *fsdev_ch = fsdev_io->internal.ch;
     771             : 
     772          68 :         if (spdk_unlikely(fsdev_io->internal.in_submit_request)) {
     773             :                 /*
     774             :                  * Defer completion to avoid potential infinite recursion if the
     775             :                  * user's completion callback issues a new I/O.
     776             :                  */
     777          34 :                 spdk_thread_send_msg(spdk_fsdev_io_get_thread(fsdev_io),
     778             :                                      fsdev_io_complete, fsdev_io);
     779          34 :                 return;
     780             :         }
     781             : 
     782          34 :         TAILQ_REMOVE(&fsdev_ch->io_submitted, fsdev_io, internal.ch_link);
     783             : 
     784          34 :         assert(fsdev_io->internal.cb_fn != NULL);
     785          34 :         assert(spdk_get_thread() == spdk_fsdev_io_get_thread(fsdev_io));
     786          34 :         fsdev_io->internal.cb_fn(fsdev_io, fsdev_io->internal.cb_arg);
     787             : }
     788             : 
     789             : 
     790             : void
     791          34 : spdk_fsdev_io_complete(struct spdk_fsdev_io *fsdev_io, int status)
     792             : {
     793          34 :         struct spdk_fsdev_channel *fsdev_ch = fsdev_io->internal.ch;
     794          34 :         struct spdk_fsdev_shared_resource *shared_resource = fsdev_ch->shared_resource;
     795             : 
     796          34 :         assert(status <= 0);
     797          34 :         fsdev_io->internal.status = status;
     798          34 :         assert(fsdev_ch->io_outstanding > 0);
     799          34 :         assert(shared_resource->io_outstanding > 0);
     800          34 :         fsdev_ch->io_outstanding--;
     801          34 :         shared_resource->io_outstanding--;
     802          34 :         fsdev_io_complete(fsdev_io);
     803          34 : }
     804             : 
     805             : struct spdk_thread *
     806          68 : spdk_fsdev_io_get_thread(struct spdk_fsdev_io *fsdev_io)
     807             : {
     808          68 :         return spdk_io_channel_get_thread(fsdev_io->internal.ch->channel);
     809             : }
     810             : 
     811             : struct spdk_io_channel *
     812           0 : spdk_fsdev_io_get_io_channel(struct spdk_fsdev_io *fsdev_io)
     813             : {
     814           0 :         return fsdev_io->internal.ch->channel;
     815             : }
     816             : 
     817             : static int
     818          38 : fsdev_register(struct spdk_fsdev *fsdev)
     819             : {
     820             :         char *fsdev_name;
     821             :         int ret;
     822             : 
     823          38 :         assert(fsdev->module != NULL);
     824             : 
     825          38 :         if (!fsdev->name) {
     826           0 :                 SPDK_ERRLOG("Fsdev name is NULL\n");
     827           0 :                 return -EINVAL;
     828             :         }
     829             : 
     830          38 :         if (!strlen(fsdev->name)) {
     831           0 :                 SPDK_ERRLOG("Fsdev name must not be an empty string\n");
     832           0 :                 return -EINVAL;
     833             :         }
     834             : 
     835             :         /* Users often register their own I/O devices using the fsdev name. In
     836             :          * order to avoid conflicts, prepend fsdev_. */
     837          38 :         fsdev_name = spdk_sprintf_alloc("fsdev_%s", fsdev->name);
     838          38 :         if (!fsdev_name) {
     839           0 :                 SPDK_ERRLOG("Unable to allocate memory for internal fsdev name.\n");
     840           0 :                 return -ENOMEM;
     841             :         }
     842             : 
     843          38 :         fsdev->internal.status = SPDK_FSDEV_STATUS_READY;
     844          38 :         TAILQ_INIT(&fsdev->internal.open_descs);
     845             : 
     846          38 :         ret = fsdev_name_add(&fsdev->internal.fsdev_name, fsdev, fsdev->name);
     847          38 :         if (ret != 0) {
     848           0 :                 free(fsdev_name);
     849           0 :                 return ret;
     850             :         }
     851             : 
     852          38 :         spdk_io_device_register(__fsdev_to_io_dev(fsdev),
     853             :                                 fsdev_channel_create, fsdev_channel_destroy,
     854             :                                 sizeof(struct spdk_fsdev_channel),
     855             :                                 fsdev_name);
     856             : 
     857          38 :         free(fsdev_name);
     858             : 
     859          38 :         spdk_spin_init(&fsdev->internal.spinlock);
     860             : 
     861          38 :         SPDK_DEBUGLOG(fsdev, "Inserting fsdev %s into list\n", fsdev->name);
     862          38 :         TAILQ_INSERT_TAIL(&g_fsdev_mgr.fsdevs, fsdev, internal.link);
     863          38 :         return 0;
     864             : }
     865             : 
     866             : static void
     867          38 : fsdev_destroy_cb(void *io_device)
     868             : {
     869             :         int                     rc;
     870             :         struct spdk_fsdev       *fsdev;
     871             :         spdk_fsdev_unregister_cb cb_fn;
     872             :         void                    *cb_arg;
     873             : 
     874          38 :         fsdev = __fsdev_from_io_dev(io_device);
     875          38 :         cb_fn = fsdev->internal.unregister_cb;
     876          38 :         cb_arg = fsdev->internal.unregister_ctx;
     877             : 
     878          38 :         spdk_spin_destroy(&fsdev->internal.spinlock);
     879             : 
     880          38 :         rc = fsdev->fn_table->destruct(fsdev->ctxt);
     881          38 :         if (rc < 0) {
     882           0 :                 SPDK_ERRLOG("destruct failed\n");
     883             :         }
     884          38 :         if (rc <= 0 && cb_fn != NULL) {
     885          38 :                 cb_fn(cb_arg, rc);
     886             :         }
     887          38 : }
     888             : 
     889             : void
     890           0 : spdk_fsdev_destruct_done(struct spdk_fsdev *fsdev, int fsdeverrno)
     891             : {
     892           0 :         if (fsdev->internal.unregister_cb != NULL) {
     893           0 :                 fsdev->internal.unregister_cb(fsdev->internal.unregister_ctx, fsdeverrno);
     894             :         }
     895           0 : }
     896             : 
     897             : static void
     898           0 : _remove_notify(void *arg)
     899             : {
     900           0 :         struct spdk_fsdev_desc *desc = arg;
     901             : 
     902           0 :         spdk_spin_lock(&desc->spinlock);
     903           0 :         desc->refs--;
     904             : 
     905           0 :         if (!desc->closed) {
     906           0 :                 spdk_spin_unlock(&desc->spinlock);
     907           0 :                 desc->callback.event_fn(SPDK_FSDEV_EVENT_REMOVE, desc->fsdev, desc->callback.ctx);
     908           0 :                 return;
     909           0 :         } else if (0 == desc->refs) {
     910             :                 /* This descriptor was closed after this remove_notify message was sent.
     911             :                  * spdk_fsdev_close() could not free the descriptor since this message was
     912             :                  * in flight, so we free it now using fsdev_desc_free().
     913             :                  */
     914           0 :                 spdk_spin_unlock(&desc->spinlock);
     915           0 :                 fsdev_desc_free(desc);
     916           0 :                 return;
     917             :         }
     918           0 :         spdk_spin_unlock(&desc->spinlock);
     919             : }
     920             : 
     921             : /* Must be called while holding g_fsdev_mgr.mutex and fsdev->internal.spinlock.
     922             :  * returns: 0 - fsdev removed and ready to be destructed.
     923             :  *          -EBUSY - fsdev can't be destructed yet.  */
     924             : static int
     925          38 : fsdev_unregister_unsafe(struct spdk_fsdev *fsdev)
     926             : {
     927             :         struct spdk_fsdev_desc  *desc, *tmp;
     928          38 :         int                     rc = 0;
     929             : 
     930             :         /* Notify each descriptor about hotremoval */
     931          38 :         TAILQ_FOREACH_SAFE(desc, &fsdev->internal.open_descs, link, tmp) {
     932           0 :                 rc = -EBUSY;
     933           0 :                 spdk_spin_lock(&desc->spinlock);
     934             :                 /*
     935             :                  * Defer invocation of the event_cb to a separate message that will
     936             :                  *  run later on its thread.  This ensures this context unwinds and
     937             :                  *  we don't recursively unregister this fsdev again if the event_cb
     938             :                  *  immediately closes its descriptor.
     939             :                  */
     940           0 :                 desc->refs++;
     941           0 :                 spdk_thread_send_msg(desc->thread, _remove_notify, desc);
     942           0 :                 spdk_spin_unlock(&desc->spinlock);
     943             :         }
     944             : 
     945             :         /* If there are no descriptors, proceed removing the fsdev */
     946          38 :         if (rc == 0) {
     947          38 :                 TAILQ_REMOVE(&g_fsdev_mgr.fsdevs, fsdev, internal.link);
     948          38 :                 SPDK_DEBUGLOG(fsdev, "Removing fsdev %s from list done\n", fsdev->name);
     949          38 :                 fsdev_name_del_unsafe(&fsdev->internal.fsdev_name);
     950          38 :                 spdk_notify_send("fsdev_unregister", spdk_fsdev_get_name(fsdev));
     951             :         }
     952             : 
     953          38 :         return rc;
     954             : }
     955             : 
     956             : static void
     957          38 : fsdev_unregister(struct spdk_fsdev *fsdev, void *_ctx, int status)
     958             : {
     959             :         int rc;
     960             : 
     961          38 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
     962          38 :         spdk_spin_lock(&fsdev->internal.spinlock);
     963             :         /*
     964             :          * Set the status to REMOVING after completing to abort channels. Otherwise,
     965             :          * the last spdk_fsdev_close() may call spdk_io_device_unregister() while
     966             :          * spdk_fsdev_for_each_channel() is executed and spdk_io_device_unregister()
     967             :          * may fail.
     968             :          */
     969          38 :         fsdev->internal.status = SPDK_FSDEV_STATUS_REMOVING;
     970          38 :         rc = fsdev_unregister_unsafe(fsdev);
     971          38 :         spdk_spin_unlock(&fsdev->internal.spinlock);
     972          38 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
     973             : 
     974          38 :         if (rc == 0) {
     975          38 :                 spdk_io_device_unregister(__fsdev_to_io_dev(fsdev), fsdev_destroy_cb);
     976             :         }
     977          38 : }
     978             : 
     979             : void
     980          38 : spdk_fsdev_unregister(struct spdk_fsdev *fsdev, spdk_fsdev_unregister_cb cb_fn, void *cb_arg)
     981             : {
     982             :         struct spdk_thread      *thread;
     983             : 
     984          38 :         SPDK_DEBUGLOG(fsdev, "Removing fsdev %s from list\n", fsdev->name);
     985             : 
     986          38 :         thread = spdk_get_thread();
     987          38 :         if (!thread) {
     988             :                 /* The user called this from a non-SPDK thread. */
     989           0 :                 if (cb_fn != NULL) {
     990           0 :                         cb_fn(cb_arg, -ENOTSUP);
     991             :                 }
     992           0 :                 return;
     993             :         }
     994             : 
     995          38 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
     996          38 :         if (fsdev->internal.status == SPDK_FSDEV_STATUS_UNREGISTERING ||
     997          38 :             fsdev->internal.status == SPDK_FSDEV_STATUS_REMOVING) {
     998           0 :                 spdk_spin_unlock(&g_fsdev_mgr.spinlock);
     999           0 :                 if (cb_fn) {
    1000           0 :                         cb_fn(cb_arg, -EBUSY);
    1001             :                 }
    1002           0 :                 return;
    1003             :         }
    1004             : 
    1005          38 :         spdk_spin_lock(&fsdev->internal.spinlock);
    1006          38 :         fsdev->internal.status = SPDK_FSDEV_STATUS_UNREGISTERING;
    1007          38 :         fsdev->internal.unregister_cb = cb_fn;
    1008          38 :         fsdev->internal.unregister_ctx = cb_arg;
    1009          38 :         spdk_spin_unlock(&fsdev->internal.spinlock);
    1010          38 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
    1011             : 
    1012             :         /* @todo: bdev aborts IOs on all channels here. */
    1013          38 :         fsdev_unregister(fsdev, fsdev, 0);
    1014             : }
    1015             : 
    1016             : static void
    1017           0 : _tmp_fsdev_event_cb(enum spdk_fsdev_event_type type, struct spdk_fsdev *fsdev, void *ctx)
    1018             : {
    1019           0 :         SPDK_NOTICELOG("Unexpected fsdev event type: %d\n", type);
    1020           0 : }
    1021             : 
    1022             : int
    1023           0 : spdk_fsdev_unregister_by_name(const char *fsdev_name, struct spdk_fsdev_module *module,
    1024             :                               spdk_fsdev_unregister_cb cb_fn, void *cb_arg)
    1025             : {
    1026           0 :         struct spdk_fsdev_desc *desc;
    1027             :         struct spdk_fsdev *fsdev;
    1028             :         int rc;
    1029             : 
    1030           0 :         rc = spdk_fsdev_open(fsdev_name, _tmp_fsdev_event_cb, NULL, NULL, &desc);
    1031           0 :         if (rc != 0) {
    1032           0 :                 SPDK_ERRLOG("Failed to open fsdev with name: %s\n", fsdev_name);
    1033           0 :                 return rc;
    1034             :         }
    1035             : 
    1036           0 :         fsdev = spdk_fsdev_desc_get_fsdev(desc);
    1037             : 
    1038           0 :         if (fsdev->module != module) {
    1039           0 :                 spdk_fsdev_close(desc);
    1040           0 :                 SPDK_ERRLOG("Fsdev %s was not registered by the specified module.\n",
    1041             :                             fsdev_name);
    1042           0 :                 return -ENODEV;
    1043             :         }
    1044             : 
    1045           0 :         spdk_fsdev_unregister(fsdev, cb_fn, cb_arg);
    1046           0 :         spdk_fsdev_close(desc);
    1047             : 
    1048           0 :         return 0;
    1049             : }
    1050             : 
    1051             : static int
    1052          37 : fsdev_open(struct spdk_fsdev *fsdev, struct spdk_fsdev_desc *desc)
    1053             : {
    1054             :         struct spdk_thread *thread;
    1055             : 
    1056          37 :         thread = spdk_get_thread();
    1057          37 :         if (!thread) {
    1058           0 :                 SPDK_ERRLOG("Cannot open fsdev from non-SPDK thread.\n");
    1059           0 :                 return -ENOTSUP;
    1060             :         }
    1061             : 
    1062          37 :         SPDK_DEBUGLOG(fsdev, "Opening descriptor %p for fsdev %s on thread %p\n",
    1063             :                       desc, fsdev->name, spdk_get_thread());
    1064             : 
    1065          37 :         desc->fsdev = fsdev;
    1066          37 :         desc->thread = thread;
    1067             : 
    1068          37 :         spdk_spin_lock(&fsdev->internal.spinlock);
    1069          37 :         if (fsdev->internal.status == SPDK_FSDEV_STATUS_UNREGISTERING ||
    1070          37 :             fsdev->internal.status == SPDK_FSDEV_STATUS_REMOVING) {
    1071           0 :                 spdk_spin_unlock(&fsdev->internal.spinlock);
    1072           0 :                 return -ENODEV;
    1073             :         }
    1074             : 
    1075          37 :         TAILQ_INSERT_TAIL(&fsdev->internal.open_descs, desc, link);
    1076          37 :         spdk_spin_unlock(&fsdev->internal.spinlock);
    1077          37 :         return 0;
    1078             : }
    1079             : 
    1080             : static int
    1081          38 : fsdev_desc_alloc(struct spdk_fsdev *fsdev, spdk_fsdev_event_cb_t event_cb, void *event_ctx,
    1082             :                  struct spdk_fsdev_desc **_desc)
    1083             : {
    1084             :         struct spdk_fsdev_desc *desc;
    1085             : 
    1086          38 :         desc = calloc(1, sizeof(*desc));
    1087          38 :         if (desc == NULL) {
    1088           0 :                 SPDK_ERRLOG("Failed to allocate memory for fsdev descriptor\n");
    1089           0 :                 return -ENOMEM;
    1090             :         }
    1091             : 
    1092          38 :         desc->callback.event_fn = event_cb;
    1093          38 :         desc->callback.ctx = event_ctx;
    1094          38 :         spdk_spin_init(&desc->spinlock);
    1095          38 :         *_desc = desc;
    1096          38 :         return 0;
    1097             : }
    1098             : 
    1099             : int
    1100          38 : spdk_fsdev_open(const char *fsdev_name, spdk_fsdev_event_cb_t event_cb,
    1101             :                 void *event_ctx, struct spdk_fsdev_open_opts *opts, struct spdk_fsdev_desc **_desc)
    1102             : {
    1103          38 :         struct spdk_fsdev_desc *desc;
    1104             :         struct spdk_fsdev *fsdev;
    1105             :         int rc;
    1106             : 
    1107          38 :         if (event_cb == NULL) {
    1108           0 :                 SPDK_ERRLOG("Missing event callback function\n");
    1109           0 :                 return -EINVAL;
    1110             :         }
    1111             : 
    1112          38 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
    1113             : 
    1114          38 :         fsdev = fsdev_get_by_name(fsdev_name);
    1115          38 :         if (fsdev == NULL) {
    1116           0 :                 SPDK_NOTICELOG("Currently unable to find fsdev with name: %s\n", fsdev_name);
    1117           0 :                 spdk_spin_unlock(&g_fsdev_mgr.spinlock);
    1118           0 :                 return -ENODEV;
    1119             :         }
    1120             : 
    1121          38 :         rc = fsdev_desc_alloc(fsdev, event_cb, event_ctx, &desc);
    1122          38 :         if (rc != 0) {
    1123           0 :                 spdk_spin_unlock(&g_fsdev_mgr.spinlock);
    1124           0 :                 return rc;
    1125             :         }
    1126             : 
    1127          38 :         if (opts) {
    1128           2 :                 rc = fsdev_set_open_opts(fsdev, opts);
    1129           2 :                 if (rc != 0) {
    1130           1 :                         SPDK_NOTICELOG("%s: fsdev_set_open_opts failed with %d\n", fsdev_name, rc);
    1131           1 :                         fsdev_desc_free(desc);
    1132           1 :                         *_desc = NULL;
    1133           1 :                         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
    1134           1 :                         return rc;
    1135             :                 }
    1136             :         }
    1137             : 
    1138          37 :         rc = fsdev_open(fsdev, desc);
    1139          37 :         if (rc != 0) {
    1140           0 :                 fsdev_desc_free(desc);
    1141           0 :                 desc = NULL;
    1142             :         }
    1143             : 
    1144          37 :         *_desc = desc;
    1145          37 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
    1146          37 :         return rc;
    1147             : }
    1148             : 
    1149             : static void
    1150          37 : fsdev_close(struct spdk_fsdev *fsdev, struct spdk_fsdev_desc *desc)
    1151             : {
    1152             :         int rc;
    1153             : 
    1154          37 :         spdk_spin_lock(&fsdev->internal.spinlock);
    1155          37 :         spdk_spin_lock(&desc->spinlock);
    1156             : 
    1157          37 :         TAILQ_REMOVE(&fsdev->internal.open_descs, desc, link);
    1158          37 :         desc->closed = true;
    1159          37 :         if (0 == desc->refs) {
    1160          37 :                 spdk_spin_unlock(&desc->spinlock);
    1161          37 :                 fsdev_desc_free(desc);
    1162             :         } else {
    1163           0 :                 spdk_spin_unlock(&desc->spinlock);
    1164             :         }
    1165             : 
    1166          37 :         if (fsdev->internal.status == SPDK_FSDEV_STATUS_REMOVING &&
    1167           0 :             TAILQ_EMPTY(&fsdev->internal.open_descs)) {
    1168           0 :                 rc = fsdev_unregister_unsafe(fsdev);
    1169           0 :                 spdk_spin_unlock(&fsdev->internal.spinlock);
    1170             : 
    1171           0 :                 if (rc == 0) {
    1172           0 :                         spdk_io_device_unregister(__fsdev_to_io_dev(fsdev), fsdev_destroy_cb);
    1173             :                 }
    1174             :         } else {
    1175          37 :                 spdk_spin_unlock(&fsdev->internal.spinlock);
    1176             :         }
    1177          37 : }
    1178             : 
    1179             : void
    1180          37 : spdk_fsdev_close(struct spdk_fsdev_desc *desc)
    1181             : {
    1182          37 :         struct spdk_fsdev *fsdev = spdk_fsdev_desc_get_fsdev(desc);
    1183             : 
    1184          37 :         SPDK_DEBUGLOG(fsdev, "Closing descriptor %p for fsdev %s on thread %p\n",
    1185             :                       desc, fsdev->name, spdk_get_thread());
    1186          37 :         assert(desc->thread == spdk_get_thread());
    1187          37 :         spdk_spin_lock(&g_fsdev_mgr.spinlock);
    1188          37 :         fsdev_close(fsdev, desc);
    1189          37 :         spdk_spin_unlock(&g_fsdev_mgr.spinlock);
    1190          37 : }
    1191             : 
    1192             : int
    1193          38 : spdk_fsdev_register(struct spdk_fsdev *fsdev)
    1194             : {
    1195             :         int rc;
    1196             : 
    1197          38 :         rc = fsdev_register(fsdev);
    1198          38 :         if (rc != 0) {
    1199           0 :                 return rc;
    1200             :         }
    1201             : 
    1202          38 :         spdk_notify_send("fsdev_register", spdk_fsdev_get_name(fsdev));
    1203          38 :         return rc;
    1204             : }
    1205             : 
    1206             : struct spdk_fsdev *
    1207         109 : spdk_fsdev_desc_get_fsdev(struct spdk_fsdev_desc *desc)
    1208             : {
    1209         109 :         assert(desc != NULL);
    1210         109 :         return desc->fsdev;
    1211             : }
    1212             : 
    1213             : void
    1214           1 : spdk_fsdev_module_list_add(struct spdk_fsdev_module *fsdev_module)
    1215             : {
    1216             : 
    1217           1 :         if (spdk_fsdev_module_list_find(fsdev_module->name)) {
    1218           0 :                 SPDK_ERRLOG("ERROR: module '%s' already registered.\n", fsdev_module->name);
    1219           0 :                 assert(false);
    1220             :         }
    1221             : 
    1222           1 :         TAILQ_INSERT_TAIL(&g_fsdev_mgr.fsdev_modules, fsdev_module, internal.tailq);
    1223           1 : }
    1224             : 
    1225             : struct spdk_fsdev_module *
    1226           1 : spdk_fsdev_module_list_find(const char *name)
    1227             : {
    1228             :         struct spdk_fsdev_module *fsdev_module;
    1229             : 
    1230           1 :         TAILQ_FOREACH(fsdev_module, &g_fsdev_mgr.fsdev_modules, internal.tailq) {
    1231           0 :                 if (strcmp(name, fsdev_module->name) == 0) {
    1232           0 :                         break;
    1233             :                 }
    1234             :         }
    1235             : 
    1236           1 :         return fsdev_module;
    1237             : }
    1238             : 
    1239           1 : SPDK_LOG_REGISTER_COMPONENT(fsdev)

Generated by: LCOV version 1.15