LCOV - code coverage report
Current view: top level - lib/lvol - lvol.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 1093 1393 78.5 %
Date: 2024-12-05 11:28:15 Functions: 86 94 91.5 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2017 Intel Corporation.
       3             :  *   All rights reserved.
       4             :  *   Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       5             :  */
       6             : 
       7             : #include "spdk_internal/lvolstore.h"
       8             : #include "spdk/log.h"
       9             : #include "spdk/string.h"
      10             : #include "spdk/thread.h"
      11             : #include "spdk/blob_bdev.h"
      12             : #include "spdk/tree.h"
      13             : #include "spdk/util.h"
      14             : 
      15             : /* Default blob channel opts for lvol */
      16             : #define SPDK_LVOL_BLOB_OPTS_CHANNEL_OPS 512
      17             : 
      18             : #define LVOL_NAME "name"
      19             : 
      20           1 : SPDK_LOG_REGISTER_COMPONENT(lvol)
      21             : 
      22             : struct spdk_lvs_degraded_lvol_set {
      23             :         struct spdk_lvol_store                  *lvol_store;
      24             :         const void                              *esnap_id;
      25             :         uint32_t                                id_len;
      26             :         TAILQ_HEAD(degraded_lvols, spdk_lvol)   lvols;
      27             :         RB_ENTRY(spdk_lvs_degraded_lvol_set)    node;
      28             : };
      29             : 
      30             : static TAILQ_HEAD(, spdk_lvol_store) g_lvol_stores = TAILQ_HEAD_INITIALIZER(g_lvol_stores);
      31             : static pthread_mutex_t g_lvol_stores_mutex = PTHREAD_MUTEX_INITIALIZER;
      32             : 
      33             : static inline int lvs_opts_copy(const struct spdk_lvs_opts *src, struct spdk_lvs_opts *dst);
      34             : static int lvs_esnap_bs_dev_create(void *bs_ctx, void *blob_ctx, struct spdk_blob *blob,
      35             :                                    const void *esnap_id, uint32_t id_len,
      36             :                                    struct spdk_bs_dev **_bs_dev);
      37             : static struct spdk_lvol *lvs_get_lvol_by_blob_id(struct spdk_lvol_store *lvs, spdk_blob_id blob_id);
      38             : static void lvs_degraded_lvol_set_add(struct spdk_lvs_degraded_lvol_set *degraded_set,
      39             :                                       struct spdk_lvol *lvol);
      40             : static void lvs_degraded_lvol_set_remove(struct spdk_lvs_degraded_lvol_set *degraded_set,
      41             :                 struct spdk_lvol *lvol);
      42             : 
      43             : static int
      44          60 : add_lvs_to_list(struct spdk_lvol_store *lvs)
      45             : {
      46             :         struct spdk_lvol_store *tmp;
      47          60 :         bool name_conflict = false;
      48             : 
      49          60 :         pthread_mutex_lock(&g_lvol_stores_mutex);
      50          67 :         TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
      51           9 :                 if (!strncmp(lvs->name, tmp->name, SPDK_LVS_NAME_MAX)) {
      52           2 :                         name_conflict = true;
      53           2 :                         break;
      54             :                 }
      55           7 :         }
      56          60 :         if (!name_conflict) {
      57          58 :                 lvs->on_list = true;
      58          58 :                 TAILQ_INSERT_TAIL(&g_lvol_stores, lvs, link);
      59          58 :         }
      60          60 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
      61             : 
      62          60 :         return name_conflict ? -1 : 0;
      63             : }
      64             : 
      65             : static struct spdk_lvol_store *
      66          68 : lvs_alloc(void)
      67             : {
      68             :         struct spdk_lvol_store *lvs;
      69             : 
      70          68 :         lvs = calloc(1, sizeof(*lvs));
      71          68 :         if (lvs == NULL) {
      72           0 :                 return NULL;
      73             :         }
      74             : 
      75          68 :         TAILQ_INIT(&lvs->lvols);
      76          68 :         TAILQ_INIT(&lvs->pending_lvols);
      77          68 :         TAILQ_INIT(&lvs->retry_open_lvols);
      78             : 
      79          68 :         lvs->load_esnaps = false;
      80          68 :         RB_INIT(&lvs->degraded_lvol_sets_tree);
      81          68 :         lvs->thread = spdk_get_thread();
      82             : 
      83          68 :         return lvs;
      84          68 : }
      85             : 
      86             : static void
      87          68 : lvs_free(struct spdk_lvol_store *lvs)
      88             : {
      89          68 :         pthread_mutex_lock(&g_lvol_stores_mutex);
      90          68 :         if (lvs->on_list) {
      91          58 :                 TAILQ_REMOVE(&g_lvol_stores, lvs, link);
      92          58 :         }
      93          68 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
      94             : 
      95          68 :         assert(RB_EMPTY(&lvs->degraded_lvol_sets_tree));
      96             : 
      97          68 :         free(lvs);
      98          68 : }
      99             : 
     100             : static struct spdk_lvol *
     101          79 : lvol_alloc(struct spdk_lvol_store *lvs, const char *name, bool thin_provision,
     102             :            enum lvol_clear_method clear_method)
     103             : {
     104             :         struct spdk_lvol *lvol;
     105             : 
     106          79 :         lvol = calloc(1, sizeof(*lvol));
     107          79 :         if (lvol == NULL) {
     108           0 :                 return NULL;
     109             :         }
     110             : 
     111          79 :         lvol->lvol_store = lvs;
     112          79 :         lvol->clear_method = (enum blob_clear_method)clear_method;
     113          79 :         snprintf(lvol->name, sizeof(lvol->name), "%s", name);
     114          79 :         spdk_uuid_generate(&lvol->uuid);
     115          79 :         spdk_uuid_fmt_lower(lvol->uuid_str, sizeof(lvol->uuid_str), &lvol->uuid);
     116          79 :         spdk_uuid_fmt_lower(lvol->unique_id, sizeof(lvol->uuid_str), &lvol->uuid);
     117             : 
     118          79 :         TAILQ_INSERT_TAIL(&lvs->pending_lvols, lvol, link);
     119             : 
     120          79 :         return lvol;
     121          79 : }
     122             : 
     123             : static void
     124          86 : lvol_free(struct spdk_lvol *lvol)
     125             : {
     126          86 :         free(lvol);
     127          86 : }
     128             : 
     129             : static void
     130           6 : lvol_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     131             : {
     132           6 :         struct spdk_lvol_with_handle_req *req = cb_arg;
     133           6 :         struct spdk_lvol *lvol = req->lvol;
     134             : 
     135           6 :         if (lvolerrno != 0) {
     136           3 :                 SPDK_INFOLOG(lvol, "Failed to open lvol %s\n", lvol->unique_id);
     137           3 :                 goto end;
     138             :         }
     139             : 
     140           3 :         lvol->ref_count++;
     141           3 :         lvol->blob = blob;
     142             : end:
     143           6 :         req->cb_fn(req->cb_arg, lvol, lvolerrno);
     144           6 :         free(req);
     145           6 : }
     146             : 
     147             : void
     148           7 : spdk_lvol_open(struct spdk_lvol *lvol, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
     149             : {
     150             :         struct spdk_lvol_with_handle_req *req;
     151             :         struct spdk_blob_open_opts opts;
     152             : 
     153           7 :         assert(cb_fn != NULL);
     154             : 
     155           7 :         if (lvol == NULL) {
     156           0 :                 SPDK_ERRLOG("lvol does not exist\n");
     157           0 :                 cb_fn(cb_arg, NULL, -ENODEV);
     158           0 :                 return;
     159             :         }
     160             : 
     161           7 :         if (lvol->action_in_progress == true) {
     162           0 :                 SPDK_ERRLOG("Cannot open lvol - operations on lvol pending\n");
     163           0 :                 cb_fn(cb_arg, lvol, -EBUSY);
     164           0 :                 return;
     165             :         }
     166             : 
     167           7 :         if (lvol->ref_count > 0) {
     168           1 :                 lvol->ref_count++;
     169           1 :                 cb_fn(cb_arg, lvol, 0);
     170           1 :                 return;
     171             :         }
     172             : 
     173           6 :         req = calloc(1, sizeof(*req));
     174           6 :         if (req == NULL) {
     175           0 :                 SPDK_ERRLOG("Cannot alloc memory for request structure\n");
     176           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
     177           0 :                 return;
     178             :         }
     179             : 
     180           6 :         req->cb_fn = cb_fn;
     181           6 :         req->cb_arg = cb_arg;
     182           6 :         req->lvol = lvol;
     183             : 
     184           6 :         spdk_blob_open_opts_init(&opts, sizeof(opts));
     185           6 :         opts.clear_method = lvol->clear_method;
     186             : 
     187           6 :         spdk_bs_open_blob_ext(lvol->lvol_store->blobstore, lvol->blob_id, &opts, lvol_open_cb, req);
     188           7 : }
     189             : 
     190             : static void
     191           8 : bs_unload_with_error_cb(void *cb_arg, int lvolerrno)
     192             : {
     193           8 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     194             : 
     195           8 :         req->cb_fn(req->cb_arg, NULL, req->lvserrno);
     196           8 :         free(req);
     197           8 : }
     198             : 
     199             : static void
     200          28 : load_next_lvol(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     201             : {
     202          28 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     203          28 :         struct spdk_lvol_store *lvs = req->lvol_store;
     204          28 :         struct spdk_blob_store *bs = lvs->blobstore;
     205             :         struct spdk_lvol *lvol, *tmp;
     206             :         spdk_blob_id blob_id;
     207             :         const char *attr;
     208             :         size_t value_len;
     209             :         int rc;
     210             : 
     211          28 :         if (lvolerrno == -ENOENT) {
     212             :                 /* Finished iterating */
     213           8 :                 if (req->lvserrno == 0) {
     214           6 :                         lvs->load_esnaps = true;
     215           6 :                         req->cb_fn(req->cb_arg, lvs, req->lvserrno);
     216           6 :                         free(req);
     217           6 :                 } else {
     218           6 :                         TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
     219           4 :                                 TAILQ_REMOVE(&lvs->lvols, lvol, link);
     220           4 :                                 lvol_free(lvol);
     221           4 :                         }
     222           2 :                         lvs_free(lvs);
     223           2 :                         spdk_bs_unload(bs, bs_unload_with_error_cb, req);
     224             :                 }
     225           8 :                 return;
     226          20 :         } else if (lvolerrno < 0) {
     227           2 :                 SPDK_ERRLOG("Failed to fetch blobs list\n");
     228           2 :                 req->lvserrno = lvolerrno;
     229           2 :                 goto invalid;
     230             :         }
     231             : 
     232          18 :         blob_id = spdk_blob_get_id(blob);
     233             : 
     234          18 :         if (blob_id == lvs->super_blob_id) {
     235           8 :                 SPDK_INFOLOG(lvol, "found superblob %"PRIu64"\n", (uint64_t)blob_id);
     236           8 :                 spdk_bs_iter_next(bs, blob, load_next_lvol, req);
     237           8 :                 return;
     238             :         }
     239             : 
     240          10 :         lvol = calloc(1, sizeof(*lvol));
     241          10 :         if (!lvol) {
     242           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
     243           0 :                 req->lvserrno = -ENOMEM;
     244           0 :                 goto invalid;
     245             :         }
     246             : 
     247             :         /*
     248             :          * Do not store a reference to blob now because spdk_bs_iter_next() will close it.
     249             :          * Storing blob_id for future lookups is fine.
     250             :          */
     251          10 :         lvol->blob_id = blob_id;
     252          10 :         lvol->lvol_store = lvs;
     253             : 
     254          10 :         rc = spdk_blob_get_xattr_value(blob, "uuid", (const void **)&attr, &value_len);
     255          10 :         if (rc != 0 || value_len != SPDK_UUID_STRING_LEN || attr[SPDK_UUID_STRING_LEN - 1] != '\0' ||
     256          10 :             spdk_uuid_parse(&lvol->uuid, attr) != 0) {
     257           0 :                 SPDK_INFOLOG(lvol, "Missing or corrupt lvol uuid\n");
     258           0 :                 spdk_uuid_set_null(&lvol->uuid);
     259           0 :         }
     260          10 :         spdk_uuid_fmt_lower(lvol->uuid_str, sizeof(lvol->uuid_str), &lvol->uuid);
     261             : 
     262          10 :         if (!spdk_uuid_is_null(&lvol->uuid)) {
     263          10 :                 snprintf(lvol->unique_id, sizeof(lvol->unique_id), "%s", lvol->uuid_str);
     264          10 :         } else {
     265           0 :                 spdk_uuid_fmt_lower(lvol->unique_id, sizeof(lvol->unique_id), &lvol->lvol_store->uuid);
     266           0 :                 value_len = strlen(lvol->unique_id);
     267           0 :                 snprintf(lvol->unique_id + value_len, sizeof(lvol->unique_id) - value_len, "_%"PRIu64,
     268           0 :                          (uint64_t)blob_id);
     269             :         }
     270             : 
     271          10 :         rc = spdk_blob_get_xattr_value(blob, "name", (const void **)&attr, &value_len);
     272          10 :         if (rc != 0 || value_len > SPDK_LVOL_NAME_MAX) {
     273           0 :                 SPDK_ERRLOG("Cannot assign lvol name\n");
     274           0 :                 lvol_free(lvol);
     275           0 :                 req->lvserrno = -EINVAL;
     276           0 :                 goto invalid;
     277             :         }
     278             : 
     279          10 :         snprintf(lvol->name, sizeof(lvol->name), "%s", attr);
     280             : 
     281          10 :         TAILQ_INSERT_TAIL(&lvs->lvols, lvol, link);
     282             : 
     283          10 :         lvs->lvol_count++;
     284             : 
     285          10 :         SPDK_INFOLOG(lvol, "added lvol %s (%s)\n", lvol->unique_id, lvol->uuid_str);
     286             : 
     287             : invalid:
     288          12 :         spdk_bs_iter_next(bs, blob, load_next_lvol, req);
     289          28 : }
     290             : 
     291             : static void
     292           9 : close_super_cb(void *cb_arg, int lvolerrno)
     293             : {
     294           9 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     295           9 :         struct spdk_lvol_store *lvs = req->lvol_store;
     296           9 :         struct spdk_blob_store *bs = lvs->blobstore;
     297             : 
     298           9 :         if (lvolerrno != 0) {
     299           1 :                 SPDK_INFOLOG(lvol, "Could not close super blob\n");
     300           1 :                 lvs_free(lvs);
     301           1 :                 req->lvserrno = -ENODEV;
     302           1 :                 spdk_bs_unload(bs, bs_unload_with_error_cb, req);
     303           1 :                 return;
     304             :         }
     305             : 
     306             :         /* Start loading lvols */
     307           8 :         spdk_bs_iter_first(lvs->blobstore, load_next_lvol, req);
     308           9 : }
     309             : 
     310             : static void
     311           3 : close_super_blob_with_error_cb(void *cb_arg, int lvolerrno)
     312             : {
     313           3 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     314           3 :         struct spdk_lvol_store *lvs = req->lvol_store;
     315           3 :         struct spdk_blob_store *bs = lvs->blobstore;
     316             : 
     317           3 :         lvs_free(lvs);
     318             : 
     319           3 :         spdk_bs_unload(bs, bs_unload_with_error_cb, req);
     320           3 : }
     321             : 
     322             : static void
     323          13 : lvs_read_uuid(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     324             : {
     325          13 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     326          13 :         struct spdk_lvol_store *lvs = req->lvol_store;
     327          13 :         struct spdk_blob_store *bs = lvs->blobstore;
     328             :         const char *attr;
     329             :         size_t value_len;
     330             :         int rc;
     331             : 
     332          13 :         if (lvolerrno != 0) {
     333           1 :                 SPDK_INFOLOG(lvol, "Could not open super blob\n");
     334           1 :                 lvs_free(lvs);
     335           1 :                 req->lvserrno = -ENODEV;
     336           1 :                 spdk_bs_unload(bs, bs_unload_with_error_cb, req);
     337           1 :                 return;
     338             :         }
     339             : 
     340          12 :         rc = spdk_blob_get_xattr_value(blob, "uuid", (const void **)&attr, &value_len);
     341          12 :         if (rc != 0 || value_len != SPDK_UUID_STRING_LEN || attr[SPDK_UUID_STRING_LEN - 1] != '\0') {
     342           1 :                 SPDK_INFOLOG(lvol, "degraded_set or incorrect UUID\n");
     343           1 :                 req->lvserrno = -EINVAL;
     344           1 :                 spdk_blob_close(blob, close_super_blob_with_error_cb, req);
     345           1 :                 return;
     346             :         }
     347             : 
     348          11 :         if (spdk_uuid_parse(&lvs->uuid, attr)) {
     349           0 :                 SPDK_INFOLOG(lvol, "incorrect UUID '%s'\n", attr);
     350           0 :                 req->lvserrno = -EINVAL;
     351           0 :                 spdk_blob_close(blob, close_super_blob_with_error_cb, req);
     352           0 :                 return;
     353             :         }
     354             : 
     355          11 :         rc = spdk_blob_get_xattr_value(blob, "name", (const void **)&attr, &value_len);
     356          11 :         if (rc != 0 || value_len > SPDK_LVS_NAME_MAX) {
     357           1 :                 SPDK_INFOLOG(lvol, "degraded_set or invalid name\n");
     358           1 :                 req->lvserrno = -EINVAL;
     359           1 :                 spdk_blob_close(blob, close_super_blob_with_error_cb, req);
     360           1 :                 return;
     361             :         }
     362             : 
     363          10 :         snprintf(lvs->name, sizeof(lvs->name), "%s", attr);
     364             : 
     365          10 :         rc = add_lvs_to_list(lvs);
     366          10 :         if (rc) {
     367           1 :                 SPDK_INFOLOG(lvol, "lvolstore with name %s already exists\n", lvs->name);
     368           1 :                 req->lvserrno = -EEXIST;
     369           1 :                 spdk_blob_close(blob, close_super_blob_with_error_cb, req);
     370           1 :                 return;
     371             :         }
     372             : 
     373           9 :         lvs->super_blob_id = spdk_blob_get_id(blob);
     374             : 
     375           9 :         spdk_blob_close(blob, close_super_cb, req);
     376          13 : }
     377             : 
     378             : static void
     379          14 : lvs_open_super(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
     380             : {
     381          14 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     382          14 :         struct spdk_lvol_store *lvs = req->lvol_store;
     383          14 :         struct spdk_blob_store *bs = lvs->blobstore;
     384             : 
     385          14 :         if (lvolerrno != 0) {
     386           1 :                 SPDK_INFOLOG(lvol, "Super blob not found\n");
     387           1 :                 lvs_free(lvs);
     388           1 :                 req->lvserrno = -ENODEV;
     389           1 :                 spdk_bs_unload(bs, bs_unload_with_error_cb, req);
     390           1 :                 return;
     391             :         }
     392             : 
     393          13 :         spdk_bs_open_blob(bs, blobid, lvs_read_uuid, req);
     394          14 : }
     395             : 
     396             : static void
     397          15 : lvs_load_cb(void *cb_arg, struct spdk_blob_store *bs, int lvolerrno)
     398             : {
     399          15 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     400          15 :         struct spdk_lvol_store *lvs = req->lvol_store;
     401             : 
     402          15 :         if (lvolerrno != 0) {
     403           1 :                 req->cb_fn(req->cb_arg, NULL, lvolerrno);
     404           1 :                 lvs_free(lvs);
     405           1 :                 free(req);
     406           1 :                 return;
     407             :         }
     408             : 
     409          14 :         lvs->blobstore = bs;
     410          14 :         lvs->bs_dev = req->bs_dev;
     411             : 
     412          14 :         spdk_bs_get_super(bs, lvs_open_super, req);
     413          15 : }
     414             : 
     415             : static void
     416          67 : lvs_bs_opts_init(struct spdk_bs_opts *opts)
     417             : {
     418          67 :         spdk_bs_opts_init(opts, sizeof(*opts));
     419          67 :         opts->max_channel_ops = SPDK_LVOL_BLOB_OPTS_CHANNEL_OPS;
     420          67 : }
     421             : 
     422             : static void
     423          16 : lvs_load(struct spdk_bs_dev *bs_dev, const struct spdk_lvs_opts *_lvs_opts,
     424             :          spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
     425             : {
     426             :         struct spdk_lvs_with_handle_req *req;
     427          16 :         struct spdk_bs_opts bs_opts = {};
     428             :         struct spdk_lvs_opts lvs_opts;
     429             : 
     430          16 :         assert(cb_fn != NULL);
     431             : 
     432          16 :         if (bs_dev == NULL) {
     433           0 :                 SPDK_ERRLOG("Blobstore device does not exist\n");
     434           0 :                 cb_fn(cb_arg, NULL, -ENODEV);
     435           0 :                 return;
     436             :         }
     437             : 
     438          16 :         spdk_lvs_opts_init(&lvs_opts);
     439          16 :         if (_lvs_opts != NULL) {
     440           2 :                 if (lvs_opts_copy(_lvs_opts, &lvs_opts) != 0) {
     441           1 :                         SPDK_ERRLOG("Invalid options\n");
     442           1 :                         cb_fn(cb_arg, NULL, -EINVAL);
     443           1 :                         return;
     444             :                 }
     445           1 :         }
     446             : 
     447          15 :         req = calloc(1, sizeof(*req));
     448          15 :         if (req == NULL) {
     449           0 :                 SPDK_ERRLOG("Cannot alloc memory for request structure\n");
     450           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
     451           0 :                 return;
     452             :         }
     453             : 
     454          15 :         req->lvol_store = lvs_alloc();
     455          15 :         if (req->lvol_store == NULL) {
     456           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store\n");
     457           0 :                 free(req);
     458           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
     459           0 :                 return;
     460             :         }
     461          15 :         req->cb_fn = cb_fn;
     462          15 :         req->cb_arg = cb_arg;
     463          15 :         req->bs_dev = bs_dev;
     464             : 
     465          15 :         lvs_bs_opts_init(&bs_opts);
     466          15 :         snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "LVOLSTORE");
     467             : 
     468          15 :         if (lvs_opts.esnap_bs_dev_create != NULL) {
     469           1 :                 req->lvol_store->esnap_bs_dev_create = lvs_opts.esnap_bs_dev_create;
     470           1 :                 bs_opts.esnap_bs_dev_create = lvs_esnap_bs_dev_create;
     471           1 :                 bs_opts.esnap_ctx = req->lvol_store;
     472           1 :         }
     473             : 
     474          15 :         spdk_bs_load(bs_dev, &bs_opts, lvs_load_cb, req);
     475          16 : }
     476             : 
     477             : void
     478          14 : spdk_lvs_load(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
     479             : {
     480          14 :         lvs_load(bs_dev, NULL, cb_fn, cb_arg);
     481          14 : }
     482             : 
     483             : void
     484           2 : spdk_lvs_load_ext(struct spdk_bs_dev *bs_dev, const struct spdk_lvs_opts *opts,
     485             :                   spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
     486             : {
     487           2 :         lvs_load(bs_dev, opts, cb_fn, cb_arg);
     488           2 : }
     489             : 
     490             : static void
     491           0 : remove_bs_on_error_cb(void *cb_arg, int bserrno)
     492             : {
     493           0 : }
     494             : 
     495             : static void
     496           0 : exit_error_lvs_req(struct spdk_lvs_with_handle_req *req, struct spdk_lvol_store *lvs, int lvolerrno)
     497             : {
     498           0 :         req->cb_fn(req->cb_arg, NULL, lvolerrno);
     499           0 :         spdk_bs_destroy(lvs->blobstore, remove_bs_on_error_cb, NULL);
     500           0 :         lvs_free(lvs);
     501           0 :         free(req);
     502           0 : }
     503             : 
     504             : static void
     505          49 : super_create_close_cb(void *cb_arg, int lvolerrno)
     506             : {
     507          49 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     508          49 :         struct spdk_lvol_store *lvs = req->lvol_store;
     509             : 
     510          49 :         if (lvolerrno < 0) {
     511           0 :                 SPDK_ERRLOG("Lvol store init failed: could not close super blob\n");
     512           0 :                 exit_error_lvs_req(req, lvs, lvolerrno);
     513           0 :                 return;
     514             :         }
     515             : 
     516          49 :         req->cb_fn(req->cb_arg, lvs, lvolerrno);
     517          49 :         free(req);
     518          49 : }
     519             : 
     520             : static void
     521          49 : super_blob_set_cb(void *cb_arg, int lvolerrno)
     522             : {
     523          49 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     524          49 :         struct spdk_lvol_store *lvs = req->lvol_store;
     525          49 :         struct spdk_blob *blob = lvs->super_blob;
     526             : 
     527          49 :         if (lvolerrno < 0) {
     528           0 :                 SPDK_ERRLOG("Lvol store init failed: could not set uuid for super blob\n");
     529           0 :                 exit_error_lvs_req(req, lvs, lvolerrno);
     530           0 :                 return;
     531             :         }
     532             : 
     533          49 :         spdk_blob_close(blob, super_create_close_cb, req);
     534          49 : }
     535             : 
     536             : static void
     537          49 : super_blob_init_cb(void *cb_arg, int lvolerrno)
     538             : {
     539          49 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     540          49 :         struct spdk_lvol_store *lvs = req->lvol_store;
     541          49 :         struct spdk_blob *blob = lvs->super_blob;
     542             :         char uuid[SPDK_UUID_STRING_LEN];
     543             : 
     544          49 :         if (lvolerrno < 0) {
     545           0 :                 SPDK_ERRLOG("Lvol store init failed: could not set super blob\n");
     546           0 :                 exit_error_lvs_req(req, lvs, lvolerrno);
     547           0 :                 return;
     548             :         }
     549             : 
     550          49 :         spdk_uuid_fmt_lower(uuid, sizeof(uuid), &lvs->uuid);
     551             : 
     552          49 :         spdk_blob_set_xattr(blob, "uuid", uuid, sizeof(uuid));
     553          49 :         spdk_blob_set_xattr(blob, "name", lvs->name, strnlen(lvs->name, SPDK_LVS_NAME_MAX) + 1);
     554          49 :         spdk_blob_sync_md(blob, super_blob_set_cb, req);
     555          49 : }
     556             : 
     557             : static void
     558          49 : super_blob_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     559             : {
     560          49 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     561          49 :         struct spdk_lvol_store *lvs = req->lvol_store;
     562             : 
     563          49 :         if (lvolerrno < 0) {
     564           0 :                 SPDK_ERRLOG("Lvol store init failed: could not open super blob\n");
     565           0 :                 exit_error_lvs_req(req, lvs, lvolerrno);
     566           0 :                 return;
     567             :         }
     568             : 
     569          49 :         lvs->super_blob = blob;
     570          49 :         lvs->super_blob_id = spdk_blob_get_id(blob);
     571             : 
     572          49 :         spdk_bs_set_super(lvs->blobstore, lvs->super_blob_id, super_blob_init_cb, req);
     573          49 : }
     574             : 
     575             : static void
     576          49 : super_blob_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
     577             : {
     578          49 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     579          49 :         struct spdk_lvol_store *lvs = req->lvol_store;
     580             :         struct spdk_blob_store *bs;
     581             : 
     582          49 :         if (lvolerrno < 0) {
     583           0 :                 SPDK_ERRLOG("Lvol store init failed: could not create super blob\n");
     584           0 :                 exit_error_lvs_req(req, lvs, lvolerrno);
     585           0 :                 return;
     586             :         }
     587             : 
     588          49 :         bs = req->lvol_store->blobstore;
     589             : 
     590          49 :         spdk_bs_open_blob(bs, blobid, super_blob_create_open_cb, req);
     591          49 : }
     592             : 
     593             : static void
     594          49 : lvs_init_cb(void *cb_arg, struct spdk_blob_store *bs, int lvserrno)
     595             : {
     596          49 :         struct spdk_lvs_with_handle_req *lvs_req = cb_arg;
     597          49 :         struct spdk_lvol_store *lvs = lvs_req->lvol_store;
     598             : 
     599          49 :         if (lvserrno != 0) {
     600           0 :                 assert(bs == NULL);
     601           0 :                 lvs_req->cb_fn(lvs_req->cb_arg, NULL, lvserrno);
     602           0 :                 SPDK_ERRLOG("Lvol store init failed: could not initialize blobstore\n");
     603           0 :                 lvs_free(lvs);
     604           0 :                 free(lvs_req);
     605           0 :                 return;
     606             :         }
     607             : 
     608          49 :         assert(bs != NULL);
     609          49 :         lvs->blobstore = bs;
     610             : 
     611          49 :         SPDK_INFOLOG(lvol, "Lvol store initialized\n");
     612             : 
     613             :         /* create super blob */
     614          49 :         spdk_bs_create_blob(lvs->blobstore, super_blob_create_cb, lvs_req);
     615          49 : }
     616             : 
     617             : void
     618         118 : spdk_lvs_opts_init(struct spdk_lvs_opts *o)
     619             : {
     620         118 :         memset(o, 0, sizeof(*o));
     621         118 :         o->cluster_sz = SPDK_LVS_OPTS_CLUSTER_SZ;
     622         118 :         o->clear_method = LVS_CLEAR_WITH_UNMAP;
     623         118 :         o->num_md_pages_per_cluster_ratio = 100;
     624         118 :         o->opts_size = sizeof(*o);
     625         118 : }
     626             : 
     627             : static inline int
     628          54 : lvs_opts_copy(const struct spdk_lvs_opts *src, struct spdk_lvs_opts *dst)
     629             : {
     630          54 :         if (src->opts_size == 0) {
     631           1 :                 SPDK_ERRLOG("opts_size should not be zero value\n");
     632           1 :                 return -1;
     633             :         }
     634             : #define FIELD_OK(field) \
     635             :         offsetof(struct spdk_lvs_opts, field) + sizeof(src->field) <= src->opts_size
     636             : 
     637             : #define SET_FIELD(field) \
     638             :         if (FIELD_OK(field)) { \
     639             :                 dst->field = src->field; \
     640             :         } \
     641             : 
     642          53 :         SET_FIELD(cluster_sz);
     643          53 :         SET_FIELD(clear_method);
     644          53 :         if (FIELD_OK(name)) {
     645          53 :                 memcpy(&dst->name, &src->name, sizeof(dst->name));
     646          53 :         }
     647          53 :         SET_FIELD(num_md_pages_per_cluster_ratio);
     648          53 :         SET_FIELD(opts_size);
     649          53 :         SET_FIELD(esnap_bs_dev_create);
     650          53 :         SET_FIELD(md_page_size);
     651             : 
     652          53 :         dst->opts_size = src->opts_size;
     653             : 
     654             :         /* You should not remove this statement, but need to update the assert statement
     655             :          * if you add a new field, and also add a corresponding SET_FIELD statement */
     656             :         SPDK_STATIC_ASSERT(sizeof(struct spdk_lvs_opts) == 92, "Incorrect size");
     657             : 
     658             : #undef FIELD_OK
     659             : #undef SET_FIELD
     660             : 
     661          53 :         return 0;
     662          54 : }
     663             : 
     664             : static void
     665          52 : setup_lvs_opts(struct spdk_bs_opts *bs_opts, struct spdk_lvs_opts *o, uint32_t total_clusters,
     666             :                void *esnap_ctx)
     667             : {
     668          52 :         assert(o != NULL);
     669          52 :         lvs_bs_opts_init(bs_opts);
     670          52 :         bs_opts->cluster_sz = o->cluster_sz;
     671          52 :         bs_opts->clear_method = (enum bs_clear_method)o->clear_method;
     672          52 :         bs_opts->num_md_pages = (o->num_md_pages_per_cluster_ratio * total_clusters) / 100;
     673          52 :         bs_opts->md_page_size = o->md_page_size;
     674          52 :         bs_opts->esnap_bs_dev_create = o->esnap_bs_dev_create;
     675          52 :         bs_opts->esnap_ctx = esnap_ctx;
     676          52 :         snprintf(bs_opts->bstype.bstype, sizeof(bs_opts->bstype.bstype), "LVOLSTORE");
     677          52 : }
     678             : 
     679             : int
     680          53 : spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o,
     681             :               spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
     682             : {
     683             :         struct spdk_lvol_store *lvs;
     684             :         struct spdk_lvs_with_handle_req *lvs_req;
     685          53 :         struct spdk_bs_opts opts = {};
     686             :         struct spdk_lvs_opts lvs_opts;
     687             :         uint32_t total_clusters;
     688             :         int rc, len;
     689             : 
     690          53 :         if (bs_dev == NULL) {
     691           1 :                 SPDK_ERRLOG("Blobstore device does not exist\n");
     692           1 :                 return -ENODEV;
     693             :         }
     694             : 
     695          52 :         if (o == NULL) {
     696           0 :                 SPDK_ERRLOG("spdk_lvs_opts not specified\n");
     697           0 :                 return -EINVAL;
     698             :         }
     699             : 
     700          52 :         spdk_lvs_opts_init(&lvs_opts);
     701          52 :         if (lvs_opts_copy(o, &lvs_opts) != 0) {
     702           0 :                 SPDK_ERRLOG("spdk_lvs_opts invalid\n");
     703           0 :                 return -EINVAL;
     704             :         }
     705             : 
     706          52 :         if (lvs_opts.cluster_sz < bs_dev->blocklen || (lvs_opts.cluster_sz % bs_dev->blocklen) != 0) {
     707           0 :                 SPDK_ERRLOG("Cluster size %" PRIu32 " is smaller than blocklen %" PRIu32
     708             :                             "Or not an integral multiple\n", lvs_opts.cluster_sz, bs_dev->blocklen);
     709           0 :                 return -EINVAL;
     710             :         }
     711          52 :         total_clusters = bs_dev->blockcnt / (lvs_opts.cluster_sz / bs_dev->blocklen);
     712             : 
     713          52 :         lvs = lvs_alloc();
     714          52 :         if (!lvs) {
     715           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store base pointer\n");
     716           0 :                 return -ENOMEM;
     717             :         }
     718             : 
     719          52 :         setup_lvs_opts(&opts, o, total_clusters, lvs);
     720             : 
     721          52 :         len = strnlen(lvs_opts.name, SPDK_LVS_NAME_MAX);
     722          52 :         if (len == 0 || len == SPDK_LVS_NAME_MAX) {
     723           2 :                 SPDK_ERRLOG("Name must be between 1 and %d characters\n", SPDK_LVS_NAME_MAX - 1);
     724           2 :                 lvs_free(lvs);
     725           2 :                 return -EINVAL;
     726             :         }
     727             : 
     728          50 :         spdk_uuid_generate(&lvs->uuid);
     729          50 :         snprintf(lvs->name, sizeof(lvs->name), "%s", lvs_opts.name);
     730             : 
     731          50 :         rc = add_lvs_to_list(lvs);
     732          50 :         if (rc) {
     733           1 :                 SPDK_ERRLOG("lvolstore with name %s already exists\n", lvs->name);
     734           1 :                 lvs_free(lvs);
     735           1 :                 return -EEXIST;
     736             :         }
     737             : 
     738          49 :         lvs_req = calloc(1, sizeof(*lvs_req));
     739          49 :         if (!lvs_req) {
     740           0 :                 lvs_free(lvs);
     741           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
     742           0 :                 return -ENOMEM;
     743             :         }
     744             : 
     745          49 :         assert(cb_fn != NULL);
     746          49 :         lvs_req->cb_fn = cb_fn;
     747          49 :         lvs_req->cb_arg = cb_arg;
     748          49 :         lvs_req->lvol_store = lvs;
     749          49 :         lvs->bs_dev = bs_dev;
     750             : 
     751          49 :         SPDK_INFOLOG(lvol, "Initializing lvol store\n");
     752          49 :         spdk_bs_init(bs_dev, &opts, lvs_init_cb, lvs_req);
     753             : 
     754          49 :         return 0;
     755          53 : }
     756             : 
     757             : static void
     758           2 : lvs_rename_cb(void *cb_arg, int lvolerrno)
     759             : {
     760           2 :         struct spdk_lvs_req *req = cb_arg;
     761             : 
     762           2 :         if (lvolerrno != 0) {
     763           1 :                 req->lvserrno = lvolerrno;
     764           1 :         }
     765           2 :         if (req->lvserrno != 0) {
     766           1 :                 SPDK_ERRLOG("Lvol store rename operation failed\n");
     767             :                 /* Lvs renaming failed, so we should 'clear' new_name.
     768             :                  * Otherwise it could cause a failure on the next attempt to change the name to 'new_name'  */
     769           2 :                 snprintf(req->lvol_store->new_name,
     770             :                          sizeof(req->lvol_store->new_name),
     771           1 :                          "%s", req->lvol_store->name);
     772           1 :         } else {
     773             :                 /* Update lvs name with new_name */
     774           2 :                 snprintf(req->lvol_store->name,
     775             :                          sizeof(req->lvol_store->name),
     776           1 :                          "%s", req->lvol_store->new_name);
     777             :         }
     778             : 
     779           2 :         req->cb_fn(req->cb_arg, req->lvserrno);
     780           2 :         free(req);
     781           2 : }
     782             : 
     783             : static void
     784           1 : lvs_rename_sync_cb(void *cb_arg, int lvolerrno)
     785             : {
     786           1 :         struct spdk_lvs_req *req = cb_arg;
     787           1 :         struct spdk_blob *blob = req->lvol_store->super_blob;
     788             : 
     789           1 :         if (lvolerrno < 0) {
     790           0 :                 req->lvserrno = lvolerrno;
     791           0 :         }
     792             : 
     793           1 :         spdk_blob_close(blob, lvs_rename_cb, req);
     794           1 : }
     795             : 
     796             : static void
     797           2 : lvs_rename_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     798             : {
     799           2 :         struct spdk_lvs_req *req = cb_arg;
     800             :         int rc;
     801             : 
     802           2 :         if (lvolerrno < 0) {
     803           1 :                 lvs_rename_cb(cb_arg, lvolerrno);
     804           1 :                 return;
     805             :         }
     806             : 
     807           2 :         rc = spdk_blob_set_xattr(blob, "name", req->lvol_store->new_name,
     808           1 :                                  strlen(req->lvol_store->new_name) + 1);
     809           1 :         if (rc < 0) {
     810           0 :                 req->lvserrno = rc;
     811           0 :                 lvs_rename_sync_cb(req, rc);
     812           0 :                 return;
     813             :         }
     814             : 
     815           1 :         req->lvol_store->super_blob = blob;
     816             : 
     817           1 :         spdk_blob_sync_md(blob, lvs_rename_sync_cb, req);
     818           2 : }
     819             : 
     820             : void
     821           5 : spdk_lvs_rename(struct spdk_lvol_store *lvs, const char *new_name,
     822             :                 spdk_lvs_op_complete cb_fn, void *cb_arg)
     823             : {
     824             :         struct spdk_lvs_req *req;
     825             :         struct spdk_lvol_store *tmp;
     826             : 
     827             :         /* Check if new name is current lvs name.
     828             :          * If so, return success immediately */
     829           5 :         if (strncmp(lvs->name, new_name, SPDK_LVS_NAME_MAX) == 0) {
     830           1 :                 cb_fn(cb_arg, 0);
     831           1 :                 return;
     832             :         }
     833             : 
     834             :         /* Check if new or new_name is already used in other lvs */
     835           4 :         pthread_mutex_lock(&g_lvol_stores_mutex);
     836           9 :         TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
     837           7 :                 if (!strncmp(new_name, tmp->name, SPDK_LVS_NAME_MAX) ||
     838           6 :                     !strncmp(new_name, tmp->new_name, SPDK_LVS_NAME_MAX)) {
     839           2 :                         pthread_mutex_unlock(&g_lvol_stores_mutex);
     840           2 :                         cb_fn(cb_arg, -EEXIST);
     841           2 :                         return;
     842             :                 }
     843           5 :         }
     844           2 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
     845             : 
     846           2 :         req = calloc(1, sizeof(*req));
     847           2 :         if (!req) {
     848           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
     849           0 :                 cb_fn(cb_arg, -ENOMEM);
     850           0 :                 return;
     851             :         }
     852           2 :         snprintf(lvs->new_name, sizeof(lvs->new_name), "%s", new_name);
     853           2 :         req->lvol_store = lvs;
     854           2 :         req->cb_fn = cb_fn;
     855           2 :         req->cb_arg = cb_arg;
     856             : 
     857           2 :         spdk_bs_open_blob(lvs->blobstore, lvs->super_blob_id, lvs_rename_open_cb, req);
     858           5 : }
     859             : 
     860             : static void
     861          27 : _lvs_unload_cb(void *cb_arg, int lvserrno)
     862             : {
     863          27 :         struct spdk_lvs_req *lvs_req = cb_arg;
     864             : 
     865          27 :         SPDK_INFOLOG(lvol, "Lvol store unloaded\n");
     866          27 :         assert(lvs_req->cb_fn != NULL);
     867          27 :         lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
     868          27 :         free(lvs_req);
     869          27 : }
     870             : 
     871             : int
     872          29 : spdk_lvs_unload(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn,
     873             :                 void *cb_arg)
     874             : {
     875             :         struct spdk_lvs_req *lvs_req;
     876             :         struct spdk_lvol *lvol, *tmp;
     877             : 
     878          29 :         if (lvs == NULL) {
     879           1 :                 SPDK_ERRLOG("Lvol store is NULL\n");
     880           1 :                 return -ENODEV;
     881             :         }
     882             : 
     883          52 :         TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
     884          25 :                 if (lvol->action_in_progress == true) {
     885           0 :                         SPDK_ERRLOG("Cannot unload lvol store - operations on lvols pending\n");
     886           0 :                         cb_fn(cb_arg, -EBUSY);
     887           0 :                         return -EBUSY;
     888          25 :                 } else if (lvol->ref_count != 0) {
     889           1 :                         SPDK_ERRLOG("Lvols still open on lvol store\n");
     890           1 :                         cb_fn(cb_arg, -EBUSY);
     891           1 :                         return -EBUSY;
     892             :                 }
     893          24 :         }
     894             : 
     895          51 :         TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
     896          24 :                 spdk_lvs_esnap_missing_remove(lvol);
     897          24 :                 TAILQ_REMOVE(&lvs->lvols, lvol, link);
     898          24 :                 lvol_free(lvol);
     899          24 :         }
     900             : 
     901          27 :         lvs_req = calloc(1, sizeof(*lvs_req));
     902          27 :         if (!lvs_req) {
     903           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
     904           0 :                 return -ENOMEM;
     905             :         }
     906             : 
     907          27 :         lvs_req->cb_fn = cb_fn;
     908          27 :         lvs_req->cb_arg = cb_arg;
     909             : 
     910          27 :         SPDK_INFOLOG(lvol, "Unloading lvol store\n");
     911          27 :         spdk_bs_unload(lvs->blobstore, _lvs_unload_cb, lvs_req);
     912          27 :         lvs_free(lvs);
     913             : 
     914          27 :         return 0;
     915          29 : }
     916             : 
     917             : static void
     918          28 : _lvs_destroy_cb(void *cb_arg, int lvserrno)
     919             : {
     920          28 :         struct spdk_lvs_destroy_req *lvs_req = cb_arg;
     921             : 
     922          28 :         SPDK_INFOLOG(lvol, "Lvol store destroyed\n");
     923          28 :         assert(lvs_req->cb_fn != NULL);
     924          28 :         lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
     925          28 :         free(lvs_req);
     926          28 : }
     927             : 
     928             : static void
     929          28 : _lvs_destroy_super_cb(void *cb_arg, int bserrno)
     930             : {
     931          28 :         struct spdk_lvs_destroy_req *lvs_req = cb_arg;
     932          28 :         struct spdk_lvol_store *lvs = lvs_req->lvs;
     933             : 
     934          28 :         assert(lvs != NULL);
     935             : 
     936          28 :         SPDK_INFOLOG(lvol, "Destroying lvol store\n");
     937          28 :         spdk_bs_destroy(lvs->blobstore, _lvs_destroy_cb, lvs_req);
     938          28 :         lvs_free(lvs);
     939          28 : }
     940             : 
     941             : int
     942          29 : spdk_lvs_destroy(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn,
     943             :                  void *cb_arg)
     944             : {
     945             :         struct spdk_lvs_destroy_req *lvs_req;
     946             :         struct spdk_lvol *iter_lvol, *tmp;
     947             : 
     948          29 :         if (lvs == NULL) {
     949           0 :                 SPDK_ERRLOG("Lvol store is NULL\n");
     950           0 :                 return -ENODEV;
     951             :         }
     952             : 
     953          32 :         TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
     954           4 :                 if (iter_lvol->action_in_progress == true) {
     955           0 :                         SPDK_ERRLOG("Cannot destroy lvol store - operations on lvols pending\n");
     956           0 :                         cb_fn(cb_arg, -EBUSY);
     957           0 :                         return -EBUSY;
     958           4 :                 } else if (iter_lvol->ref_count != 0) {
     959           1 :                         SPDK_ERRLOG("Lvols still open on lvol store\n");
     960           1 :                         cb_fn(cb_arg, -EBUSY);
     961           1 :                         return -EBUSY;
     962             :                 }
     963           3 :         }
     964             : 
     965          31 :         TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
     966           3 :                 free(iter_lvol);
     967           3 :         }
     968             : 
     969          28 :         lvs_req = calloc(1, sizeof(*lvs_req));
     970          28 :         if (!lvs_req) {
     971           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
     972           0 :                 return -ENOMEM;
     973             :         }
     974             : 
     975          28 :         lvs_req->cb_fn = cb_fn;
     976          28 :         lvs_req->cb_arg = cb_arg;
     977          28 :         lvs_req->lvs = lvs;
     978             : 
     979          28 :         SPDK_INFOLOG(lvol, "Deleting super blob\n");
     980          28 :         spdk_bs_delete_blob(lvs->blobstore, lvs->super_blob_id, _lvs_destroy_super_cb, lvs_req);
     981             : 
     982          28 :         return 0;
     983          29 : }
     984             : 
     985             : static void
     986          80 : lvol_close_blob_cb(void *cb_arg, int lvolerrno)
     987             : {
     988          80 :         struct spdk_lvol_req *req = cb_arg;
     989          80 :         struct spdk_lvol *lvol = req->lvol;
     990             : 
     991          80 :         if (lvolerrno < 0) {
     992           1 :                 SPDK_ERRLOG("Could not close blob on lvol\n");
     993           1 :                 goto end;
     994             :         }
     995             : 
     996          79 :         lvol->ref_count--;
     997          79 :         lvol->blob = NULL;
     998          79 :         SPDK_INFOLOG(lvol, "Lvol %s closed\n", lvol->unique_id);
     999             : 
    1000             : end:
    1001          80 :         lvol->action_in_progress = false;
    1002          80 :         req->cb_fn(req->cb_arg, lvolerrno);
    1003          80 :         free(req);
    1004          80 : }
    1005             : 
    1006             : bool
    1007           0 : spdk_lvol_deletable(struct spdk_lvol *lvol)
    1008             : {
    1009           0 :         size_t count = 0;
    1010             : 
    1011           0 :         spdk_blob_get_clones(lvol->lvol_store->blobstore, lvol->blob_id, NULL, &count);
    1012           0 :         return (count == 0);
    1013             : }
    1014             : 
    1015             : static void
    1016          56 : lvol_delete_blob_cb(void *cb_arg, int lvolerrno)
    1017             : {
    1018          56 :         struct spdk_lvol_req *req = cb_arg;
    1019          56 :         struct spdk_lvol *lvol = req->lvol;
    1020          56 :         struct spdk_lvol *clone_lvol = req->clone_lvol;
    1021             : 
    1022          56 :         if (lvolerrno < 0) {
    1023           1 :                 SPDK_ERRLOG("Could not remove blob on lvol gracefully - forced removal\n");
    1024           1 :         } else {
    1025          55 :                 SPDK_INFOLOG(lvol, "Lvol %s deleted\n", lvol->unique_id);
    1026             :         }
    1027             : 
    1028          56 :         if (lvol->degraded_set != NULL) {
    1029          12 :                 if (clone_lvol != NULL) {
    1030             :                         /*
    1031             :                          * A degraded esnap clone that has a blob clone has been deleted. clone_lvol
    1032             :                          * becomes an esnap clone and needs to be associated with the
    1033             :                          * spdk_lvs_degraded_lvol_set.
    1034             :                          */
    1035           1 :                         struct spdk_lvs_degraded_lvol_set *degraded_set = lvol->degraded_set;
    1036             : 
    1037           1 :                         lvs_degraded_lvol_set_remove(degraded_set, lvol);
    1038           1 :                         lvs_degraded_lvol_set_add(degraded_set, clone_lvol);
    1039           1 :                 } else {
    1040          11 :                         spdk_lvs_esnap_missing_remove(lvol);
    1041             :                 }
    1042          12 :         }
    1043             : 
    1044          56 :         TAILQ_REMOVE(&lvol->lvol_store->lvols, lvol, link);
    1045          56 :         lvol_free(lvol);
    1046          56 :         req->cb_fn(req->cb_arg, lvolerrno);
    1047          56 :         free(req);
    1048          56 : }
    1049             : 
    1050             : static void
    1051          75 : lvol_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
    1052             : {
    1053          75 :         struct spdk_lvol_with_handle_req *req = cb_arg;
    1054          75 :         struct spdk_lvol *lvol = req->lvol;
    1055             : 
    1056          75 :         TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
    1057             : 
    1058          75 :         if (lvolerrno < 0) {
    1059           0 :                 lvol_free(lvol);
    1060           0 :                 req->cb_fn(req->cb_arg, NULL, lvolerrno);
    1061           0 :                 free(req);
    1062           0 :                 return;
    1063             :         }
    1064             : 
    1065          75 :         lvol->blob = blob;
    1066          75 :         lvol->blob_id = spdk_blob_get_id(blob);
    1067             : 
    1068          75 :         TAILQ_INSERT_TAIL(&lvol->lvol_store->lvols, lvol, link);
    1069             : 
    1070          75 :         lvol->ref_count++;
    1071             : 
    1072          75 :         assert(req->cb_fn != NULL);
    1073          75 :         req->cb_fn(req->cb_arg, req->lvol, lvolerrno);
    1074          75 :         free(req);
    1075          75 : }
    1076             : 
    1077             : static void
    1078          76 : lvol_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
    1079             : {
    1080          76 :         struct spdk_lvol_with_handle_req *req = cb_arg;
    1081             :         struct spdk_blob_store *bs;
    1082             :         struct spdk_blob_open_opts opts;
    1083             : 
    1084          76 :         if (lvolerrno < 0) {
    1085           1 :                 TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
    1086           1 :                 lvol_free(req->lvol);
    1087           1 :                 assert(req->cb_fn != NULL);
    1088           1 :                 req->cb_fn(req->cb_arg, NULL, lvolerrno);
    1089           1 :                 free(req);
    1090           1 :                 return;
    1091             :         }
    1092             : 
    1093          75 :         spdk_blob_open_opts_init(&opts, sizeof(opts));
    1094          75 :         opts.clear_method = req->lvol->clear_method;
    1095             :         /*
    1096             :          * If the lvol that is being created is an esnap clone, the blobstore needs to be able to
    1097             :          * pass the lvol to the esnap_bs_dev_create callback. In order for that to happen, we need
    1098             :          * to pass it here.
    1099             :          *
    1100             :          * This does set ensap_ctx in cases where it's not needed, but we don't know that it's not
    1101             :          * needed until after the blob is open. When the blob is not an esnap clone, a reference to
    1102             :          * the value stored in opts.esnap_ctx is not retained by the blobstore.
    1103             :          */
    1104          75 :         opts.esnap_ctx = req->lvol;
    1105          75 :         bs = req->lvol->lvol_store->blobstore;
    1106             : 
    1107          75 :         if (req->origlvol != NULL && req->origlvol->degraded_set != NULL) {
    1108             :                 /*
    1109             :                  * A snapshot was created from a degraded esnap clone. The new snapshot is now a
    1110             :                  * degraded esnap clone. The previous clone is now a regular clone of a blob. Update
    1111             :                  * the set of directly-related clones to the missing external snapshot.
    1112             :                  */
    1113           1 :                 struct spdk_lvs_degraded_lvol_set *degraded_set = req->origlvol->degraded_set;
    1114             : 
    1115           1 :                 lvs_degraded_lvol_set_remove(degraded_set, req->origlvol);
    1116           1 :                 lvs_degraded_lvol_set_add(degraded_set, req->lvol);
    1117           1 :         }
    1118             : 
    1119          75 :         spdk_bs_open_blob_ext(bs, blobid, &opts, lvol_create_open_cb, req);
    1120          76 : }
    1121             : 
    1122             : static void
    1123           2 : lvol_get_xattr_value(void *xattr_ctx, const char *name,
    1124             :                      const void **value, size_t *value_len)
    1125             : {
    1126           2 :         struct spdk_lvol *lvol = xattr_ctx;
    1127             : 
    1128           2 :         if (!strcmp(LVOL_NAME, name)) {
    1129           1 :                 *value = lvol->name;
    1130           1 :                 *value_len = SPDK_LVOL_NAME_MAX;
    1131           1 :                 return;
    1132             :         }
    1133           1 :         if (!strcmp("uuid", name)) {
    1134           0 :                 *value = lvol->uuid_str;
    1135           0 :                 *value_len = sizeof(lvol->uuid_str);
    1136           0 :                 return;
    1137             :         }
    1138           1 :         *value = NULL;
    1139           1 :         *value_len = 0;
    1140           2 : }
    1141             : 
    1142             : static int
    1143          95 : lvs_verify_lvol_name(struct spdk_lvol_store *lvs, const char *name)
    1144             : {
    1145             :         struct spdk_lvol *tmp;
    1146             : 
    1147          95 :         if (name == NULL || strnlen(name, SPDK_LVOL_NAME_MAX) == 0) {
    1148           7 :                 SPDK_INFOLOG(lvol, "lvol name not provided.\n");
    1149           7 :                 return -EINVAL;
    1150             :         }
    1151             : 
    1152          88 :         if (strnlen(name, SPDK_LVOL_NAME_MAX) == SPDK_LVOL_NAME_MAX) {
    1153           2 :                 SPDK_ERRLOG("Name has no null terminator.\n");
    1154           2 :                 return -EINVAL;
    1155             :         }
    1156             : 
    1157         130 :         TAILQ_FOREACH(tmp, &lvs->lvols, link) {
    1158          52 :                 if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
    1159           8 :                         SPDK_ERRLOG("lvol with name %s already exists\n", name);
    1160           8 :                         return -EEXIST;
    1161             :                 }
    1162          44 :         }
    1163             : 
    1164          78 :         TAILQ_FOREACH(tmp, &lvs->pending_lvols, link) {
    1165           1 :                 if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
    1166           1 :                         SPDK_ERRLOG("lvol with name %s is being already created\n", name);
    1167           1 :                         return -EEXIST;
    1168             :                 }
    1169           0 :         }
    1170             : 
    1171          77 :         return 0;
    1172          95 : }
    1173             : 
    1174             : int
    1175          42 : spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
    1176             :                  bool thin_provision, enum lvol_clear_method clear_method, spdk_lvol_op_with_handle_complete cb_fn,
    1177             :                  void *cb_arg)
    1178             : {
    1179             :         struct spdk_lvol_with_handle_req *req;
    1180             :         struct spdk_blob_store *bs;
    1181             :         struct spdk_lvol *lvol;
    1182             :         struct spdk_blob_opts opts;
    1183          42 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1184             :         int rc;
    1185             : 
    1186          42 :         if (lvs == NULL) {
    1187           1 :                 SPDK_ERRLOG("lvol store does not exist\n");
    1188           1 :                 return -EINVAL;
    1189             :         }
    1190             : 
    1191          41 :         rc = lvs_verify_lvol_name(lvs, name);
    1192          41 :         if (rc < 0) {
    1193           7 :                 return rc;
    1194             :         }
    1195             : 
    1196          34 :         bs = lvs->blobstore;
    1197             : 
    1198          34 :         req = calloc(1, sizeof(*req));
    1199          34 :         if (!req) {
    1200           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1201           0 :                 return -ENOMEM;
    1202             :         }
    1203          34 :         req->cb_fn = cb_fn;
    1204          34 :         req->cb_arg = cb_arg;
    1205             : 
    1206          34 :         lvol = lvol_alloc(lvs, name, thin_provision, clear_method);
    1207          34 :         if (!lvol) {
    1208           0 :                 free(req);
    1209           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
    1210           0 :                 return -ENOMEM;
    1211             :         }
    1212             : 
    1213          34 :         req->lvol = lvol;
    1214          34 :         spdk_blob_opts_init(&opts, sizeof(opts));
    1215          34 :         opts.thin_provision = thin_provision;
    1216          34 :         opts.num_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(bs));
    1217          34 :         opts.clear_method = lvol->clear_method;
    1218          34 :         opts.xattrs.count = SPDK_COUNTOF(xattr_names);
    1219          34 :         opts.xattrs.names = xattr_names;
    1220          34 :         opts.xattrs.ctx = lvol;
    1221          34 :         opts.xattrs.get_value = lvol_get_xattr_value;
    1222             : 
    1223          34 :         spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
    1224             : 
    1225          34 :         return 0;
    1226          42 : }
    1227             : 
    1228             : int
    1229          38 : spdk_lvol_create_esnap_clone(const void *esnap_id, uint32_t id_len, uint64_t size_bytes,
    1230             :                              struct spdk_lvol_store *lvs, const char *clone_name,
    1231             :                              spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
    1232             : {
    1233             :         struct spdk_lvol_with_handle_req *req;
    1234             :         struct spdk_blob_store *bs;
    1235             :         struct spdk_lvol *lvol;
    1236             :         struct spdk_blob_opts opts;
    1237             :         uint64_t cluster_sz;
    1238          38 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1239             :         int rc;
    1240             : 
    1241          38 :         if (lvs == NULL) {
    1242           1 :                 SPDK_ERRLOG("lvol store does not exist\n");
    1243           1 :                 return -EINVAL;
    1244             :         }
    1245             : 
    1246          37 :         rc = lvs_verify_lvol_name(lvs, clone_name);
    1247          37 :         if (rc < 0) {
    1248           5 :                 return rc;
    1249             :         }
    1250             : 
    1251          32 :         bs = lvs->blobstore;
    1252             : 
    1253          32 :         cluster_sz = spdk_bs_get_cluster_size(bs);
    1254          32 :         if ((size_bytes % cluster_sz) != 0) {
    1255           1 :                 SPDK_ERRLOG("Cannot create '%s/%s': size %" PRIu64 " is not an integer multiple of "
    1256             :                             "cluster size %" PRIu64 "\n", lvs->name, clone_name, size_bytes,
    1257             :                             cluster_sz);
    1258           1 :                 return -EINVAL;
    1259             :         }
    1260             : 
    1261          31 :         req = calloc(1, sizeof(*req));
    1262          31 :         if (!req) {
    1263           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1264           0 :                 return -ENOMEM;
    1265             :         }
    1266          31 :         req->cb_fn = cb_fn;
    1267          31 :         req->cb_arg = cb_arg;
    1268             : 
    1269          31 :         lvol = lvol_alloc(lvs, clone_name, true, LVOL_CLEAR_WITH_DEFAULT);
    1270          31 :         if (!lvol) {
    1271           0 :                 free(req);
    1272           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
    1273           0 :                 return -ENOMEM;
    1274             :         }
    1275          31 :         req->lvol = lvol;
    1276             : 
    1277          31 :         spdk_blob_opts_init(&opts, sizeof(opts));
    1278          31 :         opts.esnap_id = esnap_id;
    1279          31 :         opts.esnap_id_len = id_len;
    1280          31 :         opts.thin_provision = true;
    1281          31 :         opts.num_clusters = spdk_divide_round_up(size_bytes, cluster_sz);
    1282          31 :         opts.clear_method = lvol->clear_method;
    1283          31 :         opts.xattrs.count = SPDK_COUNTOF(xattr_names);
    1284          31 :         opts.xattrs.names = xattr_names;
    1285          31 :         opts.xattrs.ctx = lvol;
    1286          31 :         opts.xattrs.get_value = lvol_get_xattr_value;
    1287             : 
    1288          31 :         spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
    1289             : 
    1290          31 :         return 0;
    1291          38 : }
    1292             : 
    1293             : void
    1294          11 : spdk_lvol_create_snapshot(struct spdk_lvol *origlvol, const char *snapshot_name,
    1295             :                           spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
    1296             : {
    1297             :         struct spdk_lvol_store *lvs;
    1298             :         struct spdk_lvol *newlvol;
    1299             :         struct spdk_blob *origblob;
    1300             :         struct spdk_lvol_with_handle_req *req;
    1301             :         struct spdk_blob_xattr_opts snapshot_xattrs;
    1302          11 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1303             :         int rc;
    1304             : 
    1305          11 :         if (origlvol == NULL) {
    1306           1 :                 SPDK_INFOLOG(lvol, "Lvol not provided.\n");
    1307           1 :                 cb_fn(cb_arg, NULL, -EINVAL);
    1308           1 :                 return;
    1309             :         }
    1310             : 
    1311          10 :         origblob = origlvol->blob;
    1312          10 :         lvs = origlvol->lvol_store;
    1313          10 :         if (lvs == NULL) {
    1314           0 :                 SPDK_ERRLOG("lvol store does not exist\n");
    1315           0 :                 cb_fn(cb_arg, NULL, -EINVAL);
    1316           0 :                 return;
    1317             :         }
    1318             : 
    1319          10 :         rc = lvs_verify_lvol_name(lvs, snapshot_name);
    1320          10 :         if (rc < 0) {
    1321           3 :                 cb_fn(cb_arg, NULL, rc);
    1322           3 :                 return;
    1323             :         }
    1324             : 
    1325           7 :         req = calloc(1, sizeof(*req));
    1326           7 :         if (!req) {
    1327           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1328           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1329           0 :                 return;
    1330             :         }
    1331             : 
    1332          14 :         newlvol = lvol_alloc(origlvol->lvol_store, snapshot_name, true,
    1333           7 :                              (enum lvol_clear_method)origlvol->clear_method);
    1334           7 :         if (!newlvol) {
    1335           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
    1336           0 :                 free(req);
    1337           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1338           0 :                 return;
    1339             :         }
    1340             : 
    1341           7 :         snapshot_xattrs.count = SPDK_COUNTOF(xattr_names);
    1342           7 :         snapshot_xattrs.ctx = newlvol;
    1343           7 :         snapshot_xattrs.names = xattr_names;
    1344           7 :         snapshot_xattrs.get_value = lvol_get_xattr_value;
    1345           7 :         req->lvol = newlvol;
    1346           7 :         req->origlvol = origlvol;
    1347           7 :         req->cb_fn = cb_fn;
    1348           7 :         req->cb_arg = cb_arg;
    1349             : 
    1350          14 :         spdk_bs_create_snapshot(lvs->blobstore, spdk_blob_get_id(origblob), &snapshot_xattrs,
    1351           7 :                                 lvol_create_cb, req);
    1352          11 : }
    1353             : 
    1354             : void
    1355           8 : spdk_lvol_create_clone(struct spdk_lvol *origlvol, const char *clone_name,
    1356             :                        spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
    1357             : {
    1358             :         struct spdk_lvol *newlvol;
    1359             :         struct spdk_lvol_with_handle_req *req;
    1360             :         struct spdk_lvol_store *lvs;
    1361             :         struct spdk_blob *origblob;
    1362             :         struct spdk_blob_xattr_opts clone_xattrs;
    1363           8 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1364             :         int rc;
    1365             : 
    1366           8 :         if (origlvol == NULL) {
    1367           1 :                 SPDK_INFOLOG(lvol, "Lvol not provided.\n");
    1368           1 :                 cb_fn(cb_arg, NULL, -EINVAL);
    1369           1 :                 return;
    1370             :         }
    1371             : 
    1372           7 :         origblob = origlvol->blob;
    1373           7 :         lvs = origlvol->lvol_store;
    1374           7 :         if (lvs == NULL) {
    1375           0 :                 SPDK_ERRLOG("lvol store does not exist\n");
    1376           0 :                 cb_fn(cb_arg, NULL, -EINVAL);
    1377           0 :                 return;
    1378             :         }
    1379             : 
    1380           7 :         rc = lvs_verify_lvol_name(lvs, clone_name);
    1381           7 :         if (rc < 0) {
    1382           3 :                 cb_fn(cb_arg, NULL, rc);
    1383           3 :                 return;
    1384             :         }
    1385             : 
    1386           4 :         req = calloc(1, sizeof(*req));
    1387           4 :         if (!req) {
    1388           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1389           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1390           0 :                 return;
    1391             :         }
    1392             : 
    1393           4 :         newlvol = lvol_alloc(lvs, clone_name, true, (enum lvol_clear_method)origlvol->clear_method);
    1394           4 :         if (!newlvol) {
    1395           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
    1396           0 :                 free(req);
    1397           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1398           0 :                 return;
    1399             :         }
    1400             : 
    1401           4 :         clone_xattrs.count = SPDK_COUNTOF(xattr_names);
    1402           4 :         clone_xattrs.ctx = newlvol;
    1403           4 :         clone_xattrs.names = xattr_names;
    1404           4 :         clone_xattrs.get_value = lvol_get_xattr_value;
    1405           4 :         req->lvol = newlvol;
    1406           4 :         req->cb_fn = cb_fn;
    1407           4 :         req->cb_arg = cb_arg;
    1408             : 
    1409           8 :         spdk_bs_create_clone(lvs->blobstore, spdk_blob_get_id(origblob), &clone_xattrs,
    1410             :                              lvol_create_cb,
    1411           4 :                              req);
    1412           8 : }
    1413             : 
    1414             : static void
    1415           4 : lvol_resize_done(void *cb_arg, int lvolerrno)
    1416             : {
    1417           4 :         struct spdk_lvol_req *req = cb_arg;
    1418             : 
    1419           4 :         req->cb_fn(req->cb_arg,  lvolerrno);
    1420           4 :         free(req);
    1421           4 : }
    1422             : 
    1423             : static void
    1424           6 : lvol_blob_resize_cb(void *cb_arg, int bserrno)
    1425             : {
    1426           6 :         struct spdk_lvol_req *req = cb_arg;
    1427           6 :         struct spdk_lvol *lvol = req->lvol;
    1428             : 
    1429           6 :         if (bserrno != 0) {
    1430           2 :                 req->cb_fn(req->cb_arg, bserrno);
    1431           2 :                 free(req);
    1432           2 :                 return;
    1433             :         }
    1434             : 
    1435           4 :         spdk_blob_sync_md(lvol->blob, lvol_resize_done, req);
    1436           6 : }
    1437             : 
    1438             : void
    1439           6 : spdk_lvol_resize(struct spdk_lvol *lvol, uint64_t sz,
    1440             :                  spdk_lvol_op_complete cb_fn, void *cb_arg)
    1441             : {
    1442           6 :         struct spdk_blob *blob = lvol->blob;
    1443           6 :         struct spdk_lvol_store *lvs = lvol->lvol_store;
    1444             :         struct spdk_lvol_req *req;
    1445           6 :         uint64_t new_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(lvs->blobstore));
    1446             : 
    1447           6 :         req = calloc(1, sizeof(*req));
    1448           6 :         if (!req) {
    1449           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1450           0 :                 cb_fn(cb_arg, -ENOMEM);
    1451           0 :                 return;
    1452             :         }
    1453           6 :         req->cb_fn = cb_fn;
    1454           6 :         req->cb_arg = cb_arg;
    1455           6 :         req->lvol = lvol;
    1456             : 
    1457           6 :         spdk_blob_resize(blob, new_clusters, lvol_blob_resize_cb, req);
    1458           6 : }
    1459             : 
    1460             : static void
    1461           1 : lvol_set_read_only_cb(void *cb_arg, int lvolerrno)
    1462             : {
    1463           1 :         struct spdk_lvol_req *req = cb_arg;
    1464             : 
    1465           1 :         req->cb_fn(req->cb_arg, lvolerrno);
    1466           1 :         free(req);
    1467           1 : }
    1468             : 
    1469             : void
    1470           1 : spdk_lvol_set_read_only(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
    1471             : {
    1472             :         struct spdk_lvol_req *req;
    1473             : 
    1474           1 :         req = calloc(1, sizeof(*req));
    1475           1 :         if (!req) {
    1476           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1477           0 :                 cb_fn(cb_arg, -ENOMEM);
    1478           0 :                 return;
    1479             :         }
    1480           1 :         req->cb_fn = cb_fn;
    1481           1 :         req->cb_arg = cb_arg;
    1482             : 
    1483           1 :         spdk_blob_set_read_only(lvol->blob);
    1484           1 :         spdk_blob_sync_md(lvol->blob, lvol_set_read_only_cb, req);
    1485           1 : }
    1486             : 
    1487             : static void
    1488           1 : lvol_rename_cb(void *cb_arg, int lvolerrno)
    1489             : {
    1490           1 :         struct spdk_lvol_req *req = cb_arg;
    1491             : 
    1492           1 :         if (lvolerrno != 0) {
    1493           0 :                 SPDK_ERRLOG("Lvol rename operation failed\n");
    1494           0 :         } else {
    1495           1 :                 snprintf(req->lvol->name, sizeof(req->lvol->name), "%s", req->name);
    1496             :         }
    1497             : 
    1498           1 :         req->cb_fn(req->cb_arg, lvolerrno);
    1499           1 :         free(req);
    1500           1 : }
    1501             : 
    1502             : void
    1503           2 : spdk_lvol_rename(struct spdk_lvol *lvol, const char *new_name,
    1504             :                  spdk_lvol_op_complete cb_fn, void *cb_arg)
    1505             : {
    1506             :         struct spdk_lvol *tmp;
    1507           2 :         struct spdk_blob *blob = lvol->blob;
    1508             :         struct spdk_lvol_req *req;
    1509             :         int rc;
    1510             : 
    1511             :         /* Check if new name is current lvol name.
    1512             :          * If so, return success immediately */
    1513           2 :         if (strncmp(lvol->name, new_name, SPDK_LVOL_NAME_MAX) == 0) {
    1514           0 :                 cb_fn(cb_arg, 0);
    1515           0 :                 return;
    1516             :         }
    1517             : 
    1518             :         /* Check if lvol with 'new_name' already exists in lvolstore */
    1519           4 :         TAILQ_FOREACH(tmp, &lvol->lvol_store->lvols, link) {
    1520           3 :                 if (strncmp(tmp->name, new_name, SPDK_LVOL_NAME_MAX) == 0) {
    1521           1 :                         SPDK_ERRLOG("Lvol %s already exists in lvol store %s\n", new_name, lvol->lvol_store->name);
    1522           1 :                         cb_fn(cb_arg, -EEXIST);
    1523           1 :                         return;
    1524             :                 }
    1525           2 :         }
    1526             : 
    1527           1 :         req = calloc(1, sizeof(*req));
    1528           1 :         if (!req) {
    1529           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1530           0 :                 cb_fn(cb_arg, -ENOMEM);
    1531           0 :                 return;
    1532             :         }
    1533           1 :         req->cb_fn = cb_fn;
    1534           1 :         req->cb_arg = cb_arg;
    1535           1 :         req->lvol = lvol;
    1536           1 :         snprintf(req->name, sizeof(req->name), "%s", new_name);
    1537             : 
    1538           1 :         rc = spdk_blob_set_xattr(blob, "name", new_name, strlen(new_name) + 1);
    1539           1 :         if (rc < 0) {
    1540           0 :                 free(req);
    1541           0 :                 cb_fn(cb_arg, rc);
    1542           0 :                 return;
    1543             :         }
    1544             : 
    1545           1 :         spdk_blob_sync_md(blob, lvol_rename_cb, req);
    1546           2 : }
    1547             : 
    1548             : void
    1549          57 : spdk_lvol_destroy(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
    1550             : {
    1551             :         struct spdk_lvol_req *req;
    1552             :         struct spdk_blob_store *bs;
    1553             :         struct spdk_lvol_store  *lvs;
    1554             :         spdk_blob_id    clone_id;
    1555          57 :         size_t          count = 1;
    1556             :         int             rc;
    1557             : 
    1558          57 :         assert(cb_fn != NULL);
    1559             : 
    1560          57 :         if (lvol == NULL) {
    1561           0 :                 SPDK_ERRLOG("lvol does not exist\n");
    1562           0 :                 cb_fn(cb_arg, -ENODEV);
    1563           0 :                 return;
    1564             :         }
    1565             : 
    1566          57 :         lvs = lvol->lvol_store;
    1567             : 
    1568          57 :         if (lvol->ref_count != 0) {
    1569           1 :                 SPDK_ERRLOG("Cannot destroy lvol %s because it is still open\n", lvol->unique_id);
    1570           1 :                 cb_fn(cb_arg, -EBUSY);
    1571           1 :                 return;
    1572             :         }
    1573             : 
    1574          56 :         req = calloc(1, sizeof(*req));
    1575          56 :         if (!req) {
    1576           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1577           0 :                 cb_fn(cb_arg, -ENOMEM);
    1578           0 :                 return;
    1579             :         }
    1580             : 
    1581          56 :         req->cb_fn = cb_fn;
    1582          56 :         req->cb_arg = cb_arg;
    1583          56 :         req->lvol = lvol;
    1584          56 :         bs = lvol->lvol_store->blobstore;
    1585             : 
    1586          56 :         rc = spdk_blob_get_clones(lvs->blobstore, lvol->blob_id, &clone_id, &count);
    1587          56 :         if (rc == 0 && count == 1) {
    1588           1 :                 req->clone_lvol = lvs_get_lvol_by_blob_id(lvs, clone_id);
    1589          56 :         } else if (rc == -ENOMEM) {
    1590           0 :                 SPDK_INFOLOG(lvol, "lvol %s: cannot destroy: has %" PRIu64 " clones\n",
    1591             :                              lvol->unique_id, count);
    1592           0 :                 free(req);
    1593           0 :                 assert(count > 1);
    1594           0 :                 cb_fn(cb_arg, -EBUSY);
    1595           0 :                 return;
    1596             :         }
    1597             : 
    1598          56 :         lvol->action_in_progress = true;
    1599             : 
    1600          56 :         spdk_bs_delete_blob(bs, lvol->blob_id, lvol_delete_blob_cb, req);
    1601          57 : }
    1602             : 
    1603             : void
    1604          84 : spdk_lvol_close(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
    1605             : {
    1606             :         struct spdk_lvol_req *req;
    1607             : 
    1608          84 :         assert(cb_fn != NULL);
    1609             : 
    1610          84 :         if (lvol == NULL) {
    1611           1 :                 SPDK_ERRLOG("lvol does not exist\n");
    1612           1 :                 cb_fn(cb_arg, -ENODEV);
    1613           1 :                 return;
    1614             :         }
    1615             : 
    1616          83 :         if (lvol->ref_count > 1) {
    1617           1 :                 lvol->ref_count--;
    1618           1 :                 cb_fn(cb_arg, 0);
    1619           1 :                 return;
    1620          82 :         } else if (lvol->ref_count == 0) {
    1621           2 :                 cb_fn(cb_arg, -EINVAL);
    1622           2 :                 return;
    1623             :         }
    1624             : 
    1625          80 :         req = calloc(1, sizeof(*req));
    1626          80 :         if (!req) {
    1627           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1628           0 :                 cb_fn(cb_arg, -ENOMEM);
    1629           0 :                 return;
    1630             :         }
    1631             : 
    1632          80 :         req->cb_fn = cb_fn;
    1633          80 :         req->cb_arg = cb_arg;
    1634          80 :         req->lvol = lvol;
    1635             : 
    1636          80 :         lvol->action_in_progress = true;
    1637             : 
    1638          80 :         spdk_blob_close(lvol->blob, lvol_close_blob_cb, req);
    1639          84 : }
    1640             : 
    1641             : struct spdk_io_channel *
    1642           0 : spdk_lvol_get_io_channel(struct spdk_lvol *lvol)
    1643             : {
    1644           0 :         return spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    1645             : }
    1646             : 
    1647             : static void
    1648           4 : lvol_inflate_cb(void *cb_arg, int lvolerrno)
    1649             : {
    1650           4 :         struct spdk_lvol_req *req = cb_arg;
    1651             : 
    1652           4 :         spdk_bs_free_io_channel(req->channel);
    1653             : 
    1654           4 :         if (lvolerrno < 0) {
    1655           2 :                 SPDK_ERRLOG("Could not inflate lvol\n");
    1656           2 :         }
    1657             : 
    1658           4 :         req->cb_fn(req->cb_arg, lvolerrno);
    1659           4 :         free(req);
    1660           4 : }
    1661             : 
    1662             : void
    1663           2 : spdk_lvol_inflate(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
    1664             : {
    1665             :         struct spdk_lvol_req *req;
    1666             :         spdk_blob_id blob_id;
    1667             : 
    1668           2 :         assert(cb_fn != NULL);
    1669             : 
    1670           2 :         if (lvol == NULL) {
    1671           0 :                 SPDK_ERRLOG("Lvol does not exist\n");
    1672           0 :                 cb_fn(cb_arg, -ENODEV);
    1673           0 :                 return;
    1674             :         }
    1675             : 
    1676           2 :         req = calloc(1, sizeof(*req));
    1677           2 :         if (!req) {
    1678           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1679           0 :                 cb_fn(cb_arg, -ENOMEM);
    1680           0 :                 return;
    1681             :         }
    1682             : 
    1683           2 :         req->cb_fn = cb_fn;
    1684           2 :         req->cb_arg = cb_arg;
    1685           2 :         req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    1686           2 :         if (req->channel == NULL) {
    1687           0 :                 SPDK_ERRLOG("Cannot alloc io channel for lvol inflate request\n");
    1688           0 :                 free(req);
    1689           0 :                 cb_fn(cb_arg, -ENOMEM);
    1690           0 :                 return;
    1691             :         }
    1692             : 
    1693           2 :         blob_id = spdk_blob_get_id(lvol->blob);
    1694           4 :         spdk_bs_inflate_blob(lvol->lvol_store->blobstore, req->channel, blob_id, lvol_inflate_cb,
    1695           2 :                              req);
    1696           2 : }
    1697             : 
    1698             : void
    1699           2 : spdk_lvol_decouple_parent(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
    1700             : {
    1701             :         struct spdk_lvol_req *req;
    1702             :         spdk_blob_id blob_id;
    1703             : 
    1704           2 :         assert(cb_fn != NULL);
    1705             : 
    1706           2 :         if (lvol == NULL) {
    1707           0 :                 SPDK_ERRLOG("Lvol does not exist\n");
    1708           0 :                 cb_fn(cb_arg, -ENODEV);
    1709           0 :                 return;
    1710             :         }
    1711             : 
    1712           2 :         req = calloc(1, sizeof(*req));
    1713           2 :         if (!req) {
    1714           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1715           0 :                 cb_fn(cb_arg, -ENOMEM);
    1716           0 :                 return;
    1717             :         }
    1718             : 
    1719           2 :         req->cb_fn = cb_fn;
    1720           2 :         req->cb_arg = cb_arg;
    1721           2 :         req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    1722           2 :         if (req->channel == NULL) {
    1723           0 :                 SPDK_ERRLOG("Cannot alloc io channel for lvol inflate request\n");
    1724           0 :                 free(req);
    1725           0 :                 cb_fn(cb_arg, -ENOMEM);
    1726           0 :                 return;
    1727             :         }
    1728             : 
    1729           2 :         blob_id = spdk_blob_get_id(lvol->blob);
    1730           4 :         spdk_bs_blob_decouple_parent(lvol->lvol_store->blobstore, req->channel, blob_id,
    1731           2 :                                      lvol_inflate_cb, req);
    1732           2 : }
    1733             : 
    1734             : static void
    1735           0 : lvs_grow_live_cb(void *cb_arg, int lvolerrno)
    1736             : {
    1737           0 :         struct spdk_lvs_req *req = (struct spdk_lvs_req *)cb_arg;
    1738             : 
    1739           0 :         if (req->cb_fn) {
    1740           0 :                 req->cb_fn(req->cb_arg, lvolerrno);
    1741           0 :         }
    1742           0 :         free(req);
    1743           0 :         return;
    1744             : }
    1745             : 
    1746             : void
    1747           0 : spdk_lvs_grow_live(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, void *cb_arg)
    1748             : {
    1749             :         struct spdk_lvs_req *req;
    1750             : 
    1751           0 :         req = calloc(1, sizeof(*req));
    1752           0 :         if (req == NULL) {
    1753           0 :                 SPDK_ERRLOG("Cannot alloc memory for request structure\n");
    1754           0 :                 if (cb_fn) {
    1755           0 :                         cb_fn(cb_arg, -ENOMEM);
    1756           0 :                 }
    1757           0 :                 return;
    1758             :         }
    1759             : 
    1760           0 :         req->cb_fn = cb_fn;
    1761           0 :         req->cb_arg = cb_arg;
    1762           0 :         req->lvol_store = lvs;
    1763             : 
    1764           0 :         spdk_bs_grow_live(lvs->blobstore, lvs_grow_live_cb, req);
    1765           0 : }
    1766             : 
    1767             : void
    1768           0 : spdk_lvs_grow(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
    1769             : {
    1770             :         struct spdk_lvs_with_handle_req *req;
    1771           0 :         struct spdk_bs_opts opts = {};
    1772             : 
    1773           0 :         assert(cb_fn != NULL);
    1774             : 
    1775           0 :         if (bs_dev == NULL) {
    1776           0 :                 SPDK_ERRLOG("Blobstore device does not exist\n");
    1777           0 :                 cb_fn(cb_arg, NULL, -ENODEV);
    1778           0 :                 return;
    1779             :         }
    1780             : 
    1781           0 :         req = calloc(1, sizeof(*req));
    1782           0 :         if (req == NULL) {
    1783           0 :                 SPDK_ERRLOG("Cannot alloc memory for request structure\n");
    1784           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1785           0 :                 return;
    1786             :         }
    1787             : 
    1788           0 :         req->lvol_store = lvs_alloc();
    1789           0 :         if (req->lvol_store == NULL) {
    1790           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store\n");
    1791           0 :                 free(req);
    1792           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1793           0 :                 return;
    1794             :         }
    1795           0 :         req->cb_fn = cb_fn;
    1796           0 :         req->cb_arg = cb_arg;
    1797           0 :         req->bs_dev = bs_dev;
    1798             : 
    1799           0 :         lvs_bs_opts_init(&opts);
    1800           0 :         snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "LVOLSTORE");
    1801             : 
    1802           0 :         spdk_bs_grow(bs_dev, &opts, lvs_load_cb, req);
    1803           0 : }
    1804             : 
    1805             : static struct spdk_lvol *
    1806           5 : lvs_get_lvol_by_blob_id(struct spdk_lvol_store *lvs, spdk_blob_id blob_id)
    1807             : {
    1808             :         struct spdk_lvol *lvol;
    1809             : 
    1810           7 :         TAILQ_FOREACH(lvol, &lvs->lvols, link) {
    1811           7 :                 if (lvol->blob_id == blob_id) {
    1812           5 :                         return lvol;
    1813             :                 }
    1814           2 :         }
    1815           0 :         return NULL;
    1816           5 : }
    1817             : 
    1818             : static int
    1819           6 : lvs_esnap_bs_dev_create(void *bs_ctx, void *blob_ctx, struct spdk_blob *blob,
    1820             :                         const void *esnap_id, uint32_t id_len,
    1821             :                         struct spdk_bs_dev **bs_dev)
    1822             : {
    1823           6 :         struct spdk_lvol_store  *lvs = bs_ctx;
    1824           6 :         struct spdk_lvol        *lvol = blob_ctx;
    1825           6 :         spdk_blob_id            blob_id = spdk_blob_get_id(blob);
    1826             : 
    1827           6 :         if (lvs == NULL) {
    1828           2 :                 if (lvol == NULL || lvol->lvol_store == NULL) {
    1829           1 :                         SPDK_ERRLOG("Blob 0x%" PRIx64 ": no lvs context nor lvol context\n",
    1830             :                                     blob_id);
    1831           1 :                         return -EINVAL;
    1832             :                 }
    1833           1 :                 lvs = lvol->lvol_store;
    1834           1 :         }
    1835             : 
    1836             :         /*
    1837             :          * When spdk_lvs_load() is called, it iterates through all blobs in its blobstore building
    1838             :          * up a list of lvols (lvs->lvols). During this initial iteration, each blob is opened,
    1839             :          * passed to load_next_lvol(), then closed. There is no need to open the external snapshot
    1840             :          * during this phase. Once the blobstore is loaded, lvs->load_esnaps is set to true so that
    1841             :          * future lvol opens cause the external snapshot to be loaded.
    1842             :          */
    1843           5 :         if (!lvs->load_esnaps) {
    1844           4 :                 *bs_dev = NULL;
    1845           4 :                 return 0;
    1846             :         }
    1847             : 
    1848           1 :         if (lvol == NULL) {
    1849           0 :                 spdk_blob_id blob_id = spdk_blob_get_id(blob);
    1850             : 
    1851             :                 /*
    1852             :                  * If spdk_bs_blob_open() is used instead of spdk_bs_blob_open_ext() the lvol will
    1853             :                  * not have been passed in. The same is true if the open happens spontaneously due
    1854             :                  * to blobstore activity.
    1855             :                  */
    1856           0 :                 lvol = lvs_get_lvol_by_blob_id(lvs, blob_id);
    1857           0 :                 if (lvol == NULL) {
    1858           0 :                         SPDK_ERRLOG("lvstore %s: no lvol for blob 0x%" PRIx64 "\n",
    1859             :                                     lvs->name, blob_id);
    1860           0 :                         return -ENODEV;
    1861             :                 }
    1862           0 :         }
    1863             : 
    1864           1 :         return lvs->esnap_bs_dev_create(lvs, lvol, blob, esnap_id, id_len, bs_dev);
    1865           6 : }
    1866             : 
    1867             : /*
    1868             :  * The theory of missing external snapshots
    1869             :  *
    1870             :  * The lvs->esnap_bs_dev_create() callback may be unable to create an external snapshot bs_dev when
    1871             :  * it is called. This can happen, for instance, as when the device containing the lvolstore is
    1872             :  * examined prior to spdk_bdev_register() being called on a bdev that acts as an external snapshot.
    1873             :  * In such a case, the esnap_bs_dev_create() callback will call spdk_lvs_esnap_missing_add().
    1874             :  *
    1875             :  * Missing external snapshots are tracked in a per-lvolstore tree, lvs->degraded_lvol_sets_tree.
    1876             :  * Each tree node (struct spdk_lvs_degraded_lvol_set) contains a tailq of lvols that are missing
    1877             :  * that particular external snapshot.
    1878             :  *
    1879             :  * When a potential missing snapshot becomes available, spdk_lvs_notify_hotplug() may be called to
    1880             :  * notify this library that it is available. It will then iterate through the active lvolstores and
    1881             :  * search each lvs->degraded_lvol_sets_tree for a set of degraded lvols that are missing an external
    1882             :  * snapshot matching the id passed in the notification. The lvols in the tailq on each matching tree
    1883             :  * node are then asked to create an external snapshot bs_dev using the esnap_bs_dev_create()
    1884             :  * callback that the consumer registered with the lvolstore. If lvs->esnap_bs_dev_create() returns
    1885             :  * 0, the lvol is removed from the spdk_lvs_degraded_lvol_set's lvol tailq. When this tailq becomes
    1886             :  * empty, the degraded lvol set node for this missing external snapshot is removed.
    1887             :  */
    1888             : static int
    1889          93 : lvs_esnap_name_cmp(struct spdk_lvs_degraded_lvol_set *m1, struct spdk_lvs_degraded_lvol_set *m2)
    1890             : {
    1891          93 :         if (m1->id_len == m2->id_len) {
    1892          93 :                 return memcmp(m1->esnap_id, m2->esnap_id, m1->id_len);
    1893             :         }
    1894           0 :         return (m1->id_len > m2->id_len) ? 1 : -1;
    1895          93 : }
    1896             : 
    1897         265 : RB_GENERATE_STATIC(degraded_lvol_sets_tree, spdk_lvs_degraded_lvol_set, node, lvs_esnap_name_cmp)
    1898             : 
    1899             : static void
    1900          38 : lvs_degraded_lvol_set_add(struct spdk_lvs_degraded_lvol_set *degraded_set, struct spdk_lvol *lvol)
    1901             : {
    1902          38 :         assert(lvol->lvol_store->thread == spdk_get_thread());
    1903             : 
    1904          38 :         lvol->degraded_set = degraded_set;
    1905          38 :         TAILQ_INSERT_TAIL(&degraded_set->lvols, lvol, degraded_link);
    1906          38 : }
    1907             : 
    1908             : static void
    1909          13 : lvs_degraded_lvol_set_remove(struct spdk_lvs_degraded_lvol_set *degraded_set,
    1910             :                              struct spdk_lvol *lvol)
    1911             : {
    1912          13 :         assert(lvol->lvol_store->thread == spdk_get_thread());
    1913             : 
    1914          13 :         lvol->degraded_set = NULL;
    1915          13 :         TAILQ_REMOVE(&degraded_set->lvols, lvol, degraded_link);
    1916             :         /* degraded_set->lvols may be empty. Caller should check if not immediately adding a new
    1917             :          * lvol. */
    1918          13 : }
    1919             : 
    1920             : /*
    1921             :  * Record in lvs->degraded_lvol_sets_tree that a bdev of the specified name is needed by the
    1922             :  * specified lvol.
    1923             :  */
    1924             : int
    1925          36 : spdk_lvs_esnap_missing_add(struct spdk_lvol_store *lvs, struct spdk_lvol *lvol,
    1926             :                            const void *esnap_id, uint32_t id_len)
    1927             : {
    1928             :         struct spdk_lvs_degraded_lvol_set find, *degraded_set;
    1929             : 
    1930          36 :         assert(lvs->thread == spdk_get_thread());
    1931             : 
    1932          36 :         find.esnap_id = esnap_id;
    1933          36 :         find.id_len = id_len;
    1934          36 :         degraded_set = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
    1935          36 :         if (degraded_set == NULL) {
    1936          16 :                 degraded_set = calloc(1, sizeof(*degraded_set));
    1937          16 :                 if (degraded_set == NULL) {
    1938           0 :                         SPDK_ERRLOG("lvol %s: cannot create degraded_set node: out of memory\n",
    1939             :                                     lvol->unique_id);
    1940           0 :                         return -ENOMEM;
    1941             :                 }
    1942          16 :                 degraded_set->esnap_id = calloc(1, id_len);
    1943          16 :                 if (degraded_set->esnap_id == NULL) {
    1944           0 :                         free(degraded_set);
    1945           0 :                         SPDK_ERRLOG("lvol %s: cannot create degraded_set node: out of memory\n",
    1946             :                                     lvol->unique_id);
    1947           0 :                         return -ENOMEM;
    1948             :                 }
    1949          16 :                 memcpy((void *)degraded_set->esnap_id, esnap_id, id_len);
    1950          16 :                 degraded_set->id_len = id_len;
    1951          16 :                 degraded_set->lvol_store = lvs;
    1952          16 :                 TAILQ_INIT(&degraded_set->lvols);
    1953          16 :                 RB_INSERT(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
    1954          16 :         }
    1955             : 
    1956          36 :         lvs_degraded_lvol_set_add(degraded_set, lvol);
    1957             : 
    1958          36 :         return 0;
    1959          36 : }
    1960             : 
    1961             : /*
    1962             :  * Remove the record of the specified lvol needing a degraded_set bdev.
    1963             :  */
    1964             : void
    1965          35 : spdk_lvs_esnap_missing_remove(struct spdk_lvol *lvol)
    1966             : {
    1967          35 :         struct spdk_lvol_store          *lvs = lvol->lvol_store;
    1968          35 :         struct spdk_lvs_degraded_lvol_set       *degraded_set = lvol->degraded_set;
    1969             : 
    1970          35 :         assert(lvs->thread == spdk_get_thread());
    1971             : 
    1972          35 :         if (degraded_set == NULL) {
    1973          24 :                 return;
    1974             :         }
    1975             : 
    1976          11 :         lvs_degraded_lvol_set_remove(degraded_set, lvol);
    1977             : 
    1978          11 :         if (!TAILQ_EMPTY(&degraded_set->lvols)) {
    1979           1 :                 return;
    1980             :         }
    1981             : 
    1982          10 :         RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
    1983             : 
    1984          10 :         free((char *)degraded_set->esnap_id);
    1985          10 :         free(degraded_set);
    1986          35 : }
    1987             : 
    1988             : struct lvs_esnap_hotplug_req {
    1989             :         struct spdk_lvol                        *lvol;
    1990             :         spdk_lvol_op_with_handle_complete       cb_fn;
    1991             :         void                                    *cb_arg;
    1992             : };
    1993             : 
    1994             : static void
    1995          25 : lvs_esnap_hotplug_done(void *cb_arg, int bserrno)
    1996             : {
    1997          25 :         struct lvs_esnap_hotplug_req *req = cb_arg;
    1998          25 :         struct spdk_lvol        *lvol = req->lvol;
    1999          25 :         struct spdk_lvol_store  *lvs = lvol->lvol_store;
    2000             : 
    2001          25 :         if (bserrno != 0) {
    2002           0 :                 SPDK_ERRLOG("lvol %s/%s: failed to hotplug blob_bdev due to error %d\n",
    2003             :                             lvs->name, lvol->name, bserrno);
    2004           0 :         }
    2005          25 :         req->cb_fn(req->cb_arg, lvol, bserrno);
    2006          25 :         free(req);
    2007          25 : }
    2008             : 
    2009             : static void
    2010          15 : lvs_esnap_degraded_hotplug(struct spdk_lvs_degraded_lvol_set *degraded_set,
    2011             :                            spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
    2012             : {
    2013          15 :         struct spdk_lvol_store  *lvs = degraded_set->lvol_store;
    2014             :         struct spdk_lvol        *lvol, *tmp, *last_missing;
    2015             :         struct spdk_bs_dev      *bs_dev;
    2016          15 :         const void              *esnap_id = degraded_set->esnap_id;
    2017          15 :         uint32_t                id_len = degraded_set->id_len;
    2018             :         struct lvs_esnap_hotplug_req *req;
    2019             :         int                     rc;
    2020             : 
    2021          15 :         assert(lvs->thread == spdk_get_thread());
    2022             : 
    2023             :         /*
    2024             :          * When lvs->esnap_bs_bdev_create() tries to load an external snapshot, it can encounter
    2025             :          * errors that lead it to calling spdk_lvs_esnap_missing_add(). This function needs to be
    2026             :          * sure that such modifications do not lead to degraded_set->lvols tailqs or references
    2027             :          * to memory that this function will free.
    2028             :          *
    2029             :          * While this function is running, no other thread can add items to degraded_set->lvols. If
    2030             :          * the list is mutated, it must have been done by this function or something in its call
    2031             :          * graph running on this thread.
    2032             :          */
    2033             : 
    2034             :         /* Remember the last lvol on the list. Iteration will stop once it has been processed. */
    2035          15 :         last_missing = TAILQ_LAST(&degraded_set->lvols, degraded_lvols);
    2036             : 
    2037          28 :         TAILQ_FOREACH_SAFE(lvol, &degraded_set->lvols, degraded_link, tmp) {
    2038          28 :                 req = calloc(1, sizeof(*req));
    2039          28 :                 if (req == NULL) {
    2040           0 :                         SPDK_ERRLOG("lvol %s: failed to create esnap bs_dev: out of memory\n",
    2041             :                                     lvol->unique_id);
    2042           0 :                         cb_fn(cb_arg, lvol, -ENOMEM);
    2043             :                         /* The next one likely won't succeed either, but keep going so that all the
    2044             :                          * failed hotplugs are logged.
    2045             :                          */
    2046           0 :                         goto next;
    2047             :                 }
    2048             : 
    2049             :                 /*
    2050             :                  * Remove the lvol from the tailq so that tailq corruption is avoided if
    2051             :                  * lvs->esnap_bs_dev_create() calls spdk_lvs_esnap_missing_add(lvol).
    2052             :                  */
    2053          28 :                 TAILQ_REMOVE(&degraded_set->lvols, lvol, degraded_link);
    2054          28 :                 lvol->degraded_set = NULL;
    2055             : 
    2056          28 :                 bs_dev = NULL;
    2057          28 :                 rc = lvs->esnap_bs_dev_create(lvs, lvol, lvol->blob, esnap_id, id_len, &bs_dev);
    2058          28 :                 if (rc != 0) {
    2059           3 :                         SPDK_ERRLOG("lvol %s: failed to create esnap bs_dev: error %d\n",
    2060             :                                     lvol->unique_id, rc);
    2061           3 :                         lvol->degraded_set = degraded_set;
    2062           3 :                         TAILQ_INSERT_TAIL(&degraded_set->lvols, lvol, degraded_link);
    2063           3 :                         cb_fn(cb_arg, lvol, rc);
    2064           3 :                         free(req);
    2065           3 :                         goto next;
    2066             :                 }
    2067             : 
    2068          25 :                 req->lvol = lvol;
    2069          25 :                 req->cb_fn = cb_fn;
    2070          25 :                 req->cb_arg = cb_arg;
    2071          25 :                 spdk_blob_set_esnap_bs_dev(lvol->blob, bs_dev, lvs_esnap_hotplug_done, req);
    2072             : 
    2073             : next:
    2074          28 :                 if (lvol == last_missing) {
    2075             :                         /*
    2076             :                          * Anything after last_missing was added due to some problem encountered
    2077             :                          * while trying to create the esnap bs_dev.
    2078             :                          */
    2079          15 :                         break;
    2080             :                 }
    2081          13 :         }
    2082             : 
    2083          15 :         if (TAILQ_EMPTY(&degraded_set->lvols)) {
    2084           6 :                 RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
    2085           6 :                 free((void *)degraded_set->esnap_id);
    2086           6 :                 free(degraded_set);
    2087           6 :         }
    2088          15 : }
    2089             : 
    2090             : /*
    2091             :  * Notify each lvstore created on this thread that is missing a bdev by the specified name or uuid
    2092             :  * that the bdev now exists.
    2093             :  */
    2094             : bool
    2095          15 : spdk_lvs_notify_hotplug(const void *esnap_id, uint32_t id_len,
    2096             :                         spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
    2097             : {
    2098             :         struct spdk_lvs_degraded_lvol_set *found;
    2099          15 :         struct spdk_lvs_degraded_lvol_set find = { 0 };
    2100             :         struct spdk_lvol_store  *lvs;
    2101          15 :         struct spdk_thread      *thread = spdk_get_thread();
    2102          15 :         bool                    ret = false;
    2103             : 
    2104          15 :         find.esnap_id = esnap_id;
    2105          15 :         find.id_len = id_len;
    2106             : 
    2107          15 :         pthread_mutex_lock(&g_lvol_stores_mutex);
    2108          30 :         TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
    2109          15 :                 if (thread != lvs->thread) {
    2110             :                         /*
    2111             :                          * It is expected that this is called from vbdev_lvol's examine_config()
    2112             :                          * callback. The lvstore was likely loaded do a creation happening as a
    2113             :                          * result of an RPC call or opening of an existing lvstore via
    2114             :                          * examine_disk() callback. RPC calls, examine_disk(), and examine_config()
    2115             :                          * should all be happening only on the app thread. The "wrong thread"
    2116             :                          * condition will only happen when an application is doing something weird.
    2117             :                          */
    2118           0 :                         SPDK_NOTICELOG("Discarded examine for lvstore %s: wrong thread\n",
    2119             :                                        lvs->name);
    2120           0 :                         continue;
    2121             :                 }
    2122             : 
    2123          15 :                 found = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
    2124          15 :                 if (found == NULL) {
    2125           0 :                         continue;
    2126             :                 }
    2127             : 
    2128          15 :                 ret = true;
    2129          15 :                 lvs_esnap_degraded_hotplug(found, cb_fn, cb_arg);
    2130          15 :         }
    2131          15 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
    2132             : 
    2133          15 :         return ret;
    2134             : }
    2135             : 
    2136             : int
    2137           4 : spdk_lvol_iter_immediate_clones(struct spdk_lvol *lvol, spdk_lvol_iter_cb cb_fn, void *cb_arg)
    2138             : {
    2139           4 :         struct spdk_lvol_store *lvs = lvol->lvol_store;
    2140           4 :         struct spdk_blob_store *bs = lvs->blobstore;
    2141             :         struct spdk_lvol *clone;
    2142             :         spdk_blob_id *ids;
    2143           4 :         size_t id_cnt = 0;
    2144             :         size_t i;
    2145             :         int rc;
    2146             : 
    2147           4 :         rc = spdk_blob_get_clones(bs, lvol->blob_id, NULL, &id_cnt);
    2148           4 :         if (rc != -ENOMEM) {
    2149             :                 /* -ENOMEM says id_cnt is valid, no other errors should be returned. */
    2150           1 :                 assert(rc == 0);
    2151           1 :                 return rc;
    2152             :         }
    2153             : 
    2154           3 :         ids = calloc(id_cnt, sizeof(*ids));
    2155           3 :         if (ids == NULL) {
    2156           0 :                 SPDK_ERRLOG("lvol %s: out of memory while iterating clones\n", lvol->unique_id);
    2157           0 :                 return -ENOMEM;
    2158             :         }
    2159             : 
    2160           3 :         rc = spdk_blob_get_clones(bs, lvol->blob_id, ids, &id_cnt);
    2161           3 :         if (rc != 0) {
    2162           0 :                 SPDK_ERRLOG("lvol %s: unable to get clone blob IDs: %d\n", lvol->unique_id, rc);
    2163           0 :                 free(ids);
    2164           0 :                 return rc;
    2165             :         }
    2166             : 
    2167           6 :         for (i = 0; i < id_cnt; i++) {
    2168           4 :                 clone = lvs_get_lvol_by_blob_id(lvs, ids[i]);
    2169           4 :                 if (clone == NULL) {
    2170           0 :                         SPDK_NOTICELOG("lvol %s: unable to find clone lvol with blob id 0x%"
    2171             :                                        PRIx64 "\n", lvol->unique_id, ids[i]);
    2172           0 :                         continue;
    2173             :                 }
    2174           4 :                 rc = cb_fn(cb_arg, clone);
    2175           4 :                 if (rc != 0) {
    2176           1 :                         SPDK_DEBUGLOG(lvol, "lvol %s: iteration stopped when lvol %s (blob 0x%"
    2177             :                                       PRIx64 ") returned %d\n", lvol->unique_id, clone->unique_id,
    2178             :                                       ids[i], rc);
    2179           1 :                         break;
    2180             :                 }
    2181           3 :         }
    2182             : 
    2183           3 :         free(ids);
    2184           3 :         return rc;
    2185           4 : }
    2186             : 
    2187             : struct spdk_lvol *
    2188           2 : spdk_lvol_get_by_uuid(const struct spdk_uuid *uuid)
    2189             : {
    2190             :         struct spdk_lvol_store *lvs;
    2191             :         struct spdk_lvol *lvol;
    2192             : 
    2193           2 :         pthread_mutex_lock(&g_lvol_stores_mutex);
    2194             : 
    2195           2 :         TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
    2196           2 :                 TAILQ_FOREACH(lvol, &lvs->lvols, link) {
    2197           2 :                         if (spdk_uuid_compare(uuid, &lvol->uuid) == 0) {
    2198           2 :                                 pthread_mutex_unlock(&g_lvol_stores_mutex);
    2199           2 :                                 return lvol;
    2200             :                         }
    2201           0 :                 }
    2202           0 :         }
    2203             : 
    2204           0 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
    2205           0 :         return NULL;
    2206           2 : }
    2207             : 
    2208             : struct spdk_lvol *
    2209          12 : spdk_lvol_get_by_names(const char *lvs_name, const char *lvol_name)
    2210             : {
    2211             :         struct spdk_lvol_store *lvs;
    2212             :         struct spdk_lvol *lvol;
    2213             : 
    2214          12 :         pthread_mutex_lock(&g_lvol_stores_mutex);
    2215             : 
    2216          17 :         TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
    2217          13 :                 if (strcmp(lvs_name, lvs->name) != 0) {
    2218           3 :                         continue;
    2219             :                 }
    2220          15 :                 TAILQ_FOREACH(lvol, &lvs->lvols, link) {
    2221          13 :                         if (strcmp(lvol_name, lvol->name) == 0) {
    2222           8 :                                 pthread_mutex_unlock(&g_lvol_stores_mutex);
    2223           8 :                                 return lvol;
    2224             :                         }
    2225           5 :                 }
    2226           2 :         }
    2227             : 
    2228           4 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
    2229           4 :         return NULL;
    2230          12 : }
    2231             : 
    2232             : bool
    2233           0 : spdk_lvol_is_degraded(const struct spdk_lvol *lvol)
    2234             : {
    2235           0 :         struct spdk_blob *blob = lvol->blob;
    2236             : 
    2237           0 :         if (blob == NULL) {
    2238           0 :                 return true;
    2239             :         }
    2240           0 :         return spdk_blob_is_degraded(blob);
    2241           0 : }
    2242             : 
    2243             : static void
    2244           1 : lvol_shallow_copy_cb(void *cb_arg, int lvolerrno)
    2245             : {
    2246           1 :         struct spdk_lvol_copy_req *req = cb_arg;
    2247           1 :         struct spdk_lvol *lvol = req->lvol;
    2248             : 
    2249           1 :         spdk_bs_free_io_channel(req->channel);
    2250             : 
    2251           1 :         if (lvolerrno < 0) {
    2252           0 :                 SPDK_ERRLOG("Could not make a shallow copy of lvol %s, error %d\n", lvol->unique_id, lvolerrno);
    2253           0 :         }
    2254             : 
    2255           1 :         req->cb_fn(req->cb_arg, lvolerrno);
    2256           1 :         free(req);
    2257           1 : }
    2258             : 
    2259             : int
    2260           3 : spdk_lvol_shallow_copy(struct spdk_lvol *lvol, struct spdk_bs_dev *ext_dev,
    2261             :                        spdk_blob_shallow_copy_status status_cb_fn, void *status_cb_arg,
    2262             :                        spdk_lvol_op_complete cb_fn, void *cb_arg)
    2263             : {
    2264             :         struct spdk_lvol_copy_req *req;
    2265             :         spdk_blob_id blob_id;
    2266             :         int rc;
    2267             : 
    2268           3 :         assert(cb_fn != NULL);
    2269             : 
    2270           3 :         if (lvol == NULL) {
    2271           1 :                 SPDK_ERRLOG("lvol must not be NULL\n");
    2272           1 :                 return -EINVAL;
    2273             :         }
    2274             : 
    2275           2 :         assert(lvol->lvol_store->thread == spdk_get_thread());
    2276             : 
    2277           2 :         if (ext_dev == NULL) {
    2278           1 :                 SPDK_ERRLOG("lvol %s shallow copy, ext_dev must not be NULL\n", lvol->unique_id);
    2279           1 :                 return -EINVAL;
    2280             :         }
    2281             : 
    2282           1 :         req = calloc(1, sizeof(*req));
    2283           1 :         if (!req) {
    2284           0 :                 SPDK_ERRLOG("lvol %s shallow copy, cannot alloc memory for lvol request\n", lvol->unique_id);
    2285           0 :                 return -ENOMEM;
    2286             :         }
    2287             : 
    2288           1 :         req->lvol = lvol;
    2289           1 :         req->cb_fn = cb_fn;
    2290           1 :         req->cb_arg = cb_arg;
    2291           1 :         req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    2292           1 :         if (req->channel == NULL) {
    2293           0 :                 SPDK_ERRLOG("lvol %s shallow copy, cannot alloc io channel for lvol request\n", lvol->unique_id);
    2294           0 :                 free(req);
    2295           0 :                 return -ENOMEM;
    2296             :         }
    2297             : 
    2298           1 :         blob_id = spdk_blob_get_id(lvol->blob);
    2299             : 
    2300           2 :         rc = spdk_bs_blob_shallow_copy(lvol->lvol_store->blobstore, req->channel, blob_id, ext_dev,
    2301           1 :                                        status_cb_fn, status_cb_arg, lvol_shallow_copy_cb, req);
    2302             : 
    2303           1 :         if (rc < 0) {
    2304           0 :                 SPDK_ERRLOG("Could not make a shallow copy of lvol %s\n", lvol->unique_id);
    2305           0 :                 spdk_bs_free_io_channel(req->channel);
    2306           0 :                 free(req);
    2307           0 :         }
    2308             : 
    2309           1 :         return rc;
    2310           3 : }
    2311             : 
    2312             : static void
    2313           1 : lvol_set_parent_cb(void *cb_arg, int lvolerrno)
    2314             : {
    2315           1 :         struct spdk_lvol_req *req = cb_arg;
    2316             : 
    2317           1 :         if (lvolerrno < 0) {
    2318           0 :                 SPDK_ERRLOG("could not set parent of lvol %s, error %d\n", req->lvol->name, lvolerrno);
    2319           0 :         }
    2320             : 
    2321           1 :         req->cb_fn(req->cb_arg, lvolerrno);
    2322           1 :         free(req);
    2323           1 : }
    2324             : 
    2325             : void
    2326           3 : spdk_lvol_set_parent(struct spdk_lvol *lvol, struct spdk_lvol *snapshot,
    2327             :                      spdk_lvol_op_complete cb_fn, void *cb_arg)
    2328             : {
    2329             :         struct spdk_lvol_req *req;
    2330             :         spdk_blob_id blob_id, snapshot_id;
    2331             : 
    2332           3 :         assert(cb_fn != NULL);
    2333             : 
    2334           3 :         if (lvol == NULL) {
    2335           1 :                 SPDK_ERRLOG("lvol must not be NULL\n");
    2336           1 :                 cb_fn(cb_arg, -EINVAL);
    2337           1 :                 return;
    2338             :         }
    2339             : 
    2340           2 :         if (snapshot == NULL) {
    2341           1 :                 SPDK_ERRLOG("snapshot must not be NULL\n");
    2342           1 :                 cb_fn(cb_arg, -EINVAL);
    2343           1 :                 return;
    2344             :         }
    2345             : 
    2346           1 :         req = calloc(1, sizeof(*req));
    2347           1 :         if (!req) {
    2348           0 :                 SPDK_ERRLOG("cannot alloc memory for lvol request pointer\n");
    2349           0 :                 cb_fn(cb_arg, -ENOMEM);
    2350           0 :                 return;
    2351             :         }
    2352             : 
    2353           1 :         req->lvol = lvol;
    2354           1 :         req->cb_fn = cb_fn;
    2355           1 :         req->cb_arg = cb_arg;
    2356             : 
    2357           1 :         blob_id = spdk_blob_get_id(lvol->blob);
    2358           1 :         snapshot_id = spdk_blob_get_id(snapshot->blob);
    2359             : 
    2360           2 :         spdk_bs_blob_set_parent(lvol->lvol_store->blobstore, blob_id, snapshot_id,
    2361           1 :                                 lvol_set_parent_cb, req);
    2362           3 : }
    2363             : 
    2364             : static void
    2365           1 : lvol_set_external_parent_cb(void *cb_arg, int lvolerrno)
    2366             : {
    2367           1 :         struct spdk_lvol_bs_dev_req *req = cb_arg;
    2368             : 
    2369           1 :         if (lvolerrno < 0) {
    2370           0 :                 SPDK_ERRLOG("could not set external parent of lvol %s, error %d\n", req->lvol->name, lvolerrno);
    2371           0 :                 req->bs_dev->destroy(req->bs_dev);
    2372           0 :         }
    2373             : 
    2374           1 :         req->cb_fn(req->cb_arg, lvolerrno);
    2375           1 :         free(req);
    2376           1 : }
    2377             : 
    2378             : void
    2379           4 : spdk_lvol_set_external_parent(struct spdk_lvol *lvol, const void *esnap_id, uint32_t esnap_id_len,
    2380             :                               spdk_lvol_op_complete cb_fn, void *cb_arg)
    2381             : {
    2382             :         struct spdk_lvol_bs_dev_req *req;
    2383             :         struct spdk_bs_dev *bs_dev;
    2384             :         spdk_blob_id blob_id;
    2385             :         int rc;
    2386             : 
    2387           4 :         assert(cb_fn != NULL);
    2388             : 
    2389           4 :         if (lvol == NULL) {
    2390           1 :                 SPDK_ERRLOG("lvol must not be NULL\n");
    2391           1 :                 cb_fn(cb_arg, -EINVAL);
    2392           1 :                 return;
    2393             :         }
    2394             : 
    2395           3 :         if (esnap_id == NULL) {
    2396           1 :                 SPDK_ERRLOG("snapshot must not be NULL\n");
    2397           1 :                 cb_fn(cb_arg, -EINVAL);
    2398           1 :                 return;
    2399             :         }
    2400             : 
    2401           2 :         if (esnap_id_len == sizeof(lvol->uuid_str) &&
    2402           2 :             memcmp(esnap_id, lvol->uuid_str, esnap_id_len) == 0) {
    2403           1 :                 SPDK_ERRLOG("lvol %s and esnap have the same UUID\n", lvol->name);
    2404           1 :                 cb_fn(cb_arg, -EINVAL);
    2405           1 :                 return;
    2406             :         }
    2407             : 
    2408           1 :         rc = lvs_esnap_bs_dev_create(lvol->lvol_store, lvol, lvol->blob, esnap_id, esnap_id_len, &bs_dev);
    2409           1 :         if (rc < 0) {
    2410           0 :                 cb_fn(cb_arg, rc);
    2411           0 :                 return;
    2412             :         }
    2413             : 
    2414           1 :         req = calloc(1, sizeof(*req));
    2415           1 :         if (!req) {
    2416           0 :                 SPDK_ERRLOG("cannot alloc memory for lvol request pointer\n");
    2417           0 :                 cb_fn(cb_arg, -ENOMEM);
    2418           0 :                 return;
    2419             :         }
    2420             : 
    2421           1 :         req->lvol = lvol;
    2422           1 :         req->bs_dev = bs_dev;
    2423           1 :         req->cb_fn = cb_fn;
    2424           1 :         req->cb_arg = cb_arg;
    2425             : 
    2426           1 :         blob_id = spdk_blob_get_id(lvol->blob);
    2427             : 
    2428           2 :         spdk_bs_blob_set_external_parent(lvol->lvol_store->blobstore, blob_id, bs_dev, esnap_id,
    2429           1 :                                          esnap_id_len, lvol_set_external_parent_cb, req);
    2430           4 : }

Generated by: LCOV version 1.15