LCOV - code coverage report
Current view: top level - lib/lvol - lvol.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 1096 1396 78.5 %
Date: 2024-12-04 08:00:14 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;
     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 :         if (strnlen(lvs_opts.name, SPDK_LVS_NAME_MAX) == SPDK_LVS_NAME_MAX) {
     722           1 :                 SPDK_ERRLOG("Name has no null terminator.\n");
     723           1 :                 lvs_free(lvs);
     724           1 :                 return -EINVAL;
     725             :         }
     726             : 
     727          51 :         if (strnlen(lvs_opts.name, SPDK_LVS_NAME_MAX) == 0) {
     728           1 :                 SPDK_ERRLOG("No name specified.\n");
     729           1 :                 lvs_free(lvs);
     730           1 :                 return -EINVAL;
     731             :         }
     732             : 
     733          50 :         spdk_uuid_generate(&lvs->uuid);
     734          50 :         snprintf(lvs->name, sizeof(lvs->name), "%s", lvs_opts.name);
     735             : 
     736          50 :         rc = add_lvs_to_list(lvs);
     737          50 :         if (rc) {
     738           1 :                 SPDK_ERRLOG("lvolstore with name %s already exists\n", lvs->name);
     739           1 :                 lvs_free(lvs);
     740           1 :                 return -EEXIST;
     741             :         }
     742             : 
     743          49 :         lvs_req = calloc(1, sizeof(*lvs_req));
     744          49 :         if (!lvs_req) {
     745           0 :                 lvs_free(lvs);
     746           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
     747           0 :                 return -ENOMEM;
     748             :         }
     749             : 
     750          49 :         assert(cb_fn != NULL);
     751          49 :         lvs_req->cb_fn = cb_fn;
     752          49 :         lvs_req->cb_arg = cb_arg;
     753          49 :         lvs_req->lvol_store = lvs;
     754          49 :         lvs->bs_dev = bs_dev;
     755             : 
     756          49 :         SPDK_INFOLOG(lvol, "Initializing lvol store\n");
     757          49 :         spdk_bs_init(bs_dev, &opts, lvs_init_cb, lvs_req);
     758             : 
     759          49 :         return 0;
     760          53 : }
     761             : 
     762             : static void
     763           2 : lvs_rename_cb(void *cb_arg, int lvolerrno)
     764             : {
     765           2 :         struct spdk_lvs_req *req = cb_arg;
     766             : 
     767           2 :         if (lvolerrno != 0) {
     768           1 :                 req->lvserrno = lvolerrno;
     769           1 :         }
     770           2 :         if (req->lvserrno != 0) {
     771           1 :                 SPDK_ERRLOG("Lvol store rename operation failed\n");
     772             :                 /* Lvs renaming failed, so we should 'clear' new_name.
     773             :                  * Otherwise it could cause a failure on the next attempt to change the name to 'new_name'  */
     774           2 :                 snprintf(req->lvol_store->new_name,
     775             :                          sizeof(req->lvol_store->new_name),
     776           1 :                          "%s", req->lvol_store->name);
     777           1 :         } else {
     778             :                 /* Update lvs name with new_name */
     779           2 :                 snprintf(req->lvol_store->name,
     780             :                          sizeof(req->lvol_store->name),
     781           1 :                          "%s", req->lvol_store->new_name);
     782             :         }
     783             : 
     784           2 :         req->cb_fn(req->cb_arg, req->lvserrno);
     785           2 :         free(req);
     786           2 : }
     787             : 
     788             : static void
     789           1 : lvs_rename_sync_cb(void *cb_arg, int lvolerrno)
     790             : {
     791           1 :         struct spdk_lvs_req *req = cb_arg;
     792           1 :         struct spdk_blob *blob = req->lvol_store->super_blob;
     793             : 
     794           1 :         if (lvolerrno < 0) {
     795           0 :                 req->lvserrno = lvolerrno;
     796           0 :         }
     797             : 
     798           1 :         spdk_blob_close(blob, lvs_rename_cb, req);
     799           1 : }
     800             : 
     801             : static void
     802           2 : lvs_rename_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     803             : {
     804           2 :         struct spdk_lvs_req *req = cb_arg;
     805             :         int rc;
     806             : 
     807           2 :         if (lvolerrno < 0) {
     808           1 :                 lvs_rename_cb(cb_arg, lvolerrno);
     809           1 :                 return;
     810             :         }
     811             : 
     812           2 :         rc = spdk_blob_set_xattr(blob, "name", req->lvol_store->new_name,
     813           1 :                                  strlen(req->lvol_store->new_name) + 1);
     814           1 :         if (rc < 0) {
     815           0 :                 req->lvserrno = rc;
     816           0 :                 lvs_rename_sync_cb(req, rc);
     817           0 :                 return;
     818             :         }
     819             : 
     820           1 :         req->lvol_store->super_blob = blob;
     821             : 
     822           1 :         spdk_blob_sync_md(blob, lvs_rename_sync_cb, req);
     823           2 : }
     824             : 
     825             : void
     826           5 : spdk_lvs_rename(struct spdk_lvol_store *lvs, const char *new_name,
     827             :                 spdk_lvs_op_complete cb_fn, void *cb_arg)
     828             : {
     829             :         struct spdk_lvs_req *req;
     830             :         struct spdk_lvol_store *tmp;
     831             : 
     832             :         /* Check if new name is current lvs name.
     833             :          * If so, return success immediately */
     834           5 :         if (strncmp(lvs->name, new_name, SPDK_LVS_NAME_MAX) == 0) {
     835           1 :                 cb_fn(cb_arg, 0);
     836           1 :                 return;
     837             :         }
     838             : 
     839             :         /* Check if new or new_name is already used in other lvs */
     840           4 :         pthread_mutex_lock(&g_lvol_stores_mutex);
     841           9 :         TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
     842           7 :                 if (!strncmp(new_name, tmp->name, SPDK_LVS_NAME_MAX) ||
     843           6 :                     !strncmp(new_name, tmp->new_name, SPDK_LVS_NAME_MAX)) {
     844           2 :                         pthread_mutex_unlock(&g_lvol_stores_mutex);
     845           2 :                         cb_fn(cb_arg, -EEXIST);
     846           2 :                         return;
     847             :                 }
     848           5 :         }
     849           2 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
     850             : 
     851           2 :         req = calloc(1, sizeof(*req));
     852           2 :         if (!req) {
     853           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
     854           0 :                 cb_fn(cb_arg, -ENOMEM);
     855           0 :                 return;
     856             :         }
     857           2 :         snprintf(lvs->new_name, sizeof(lvs->new_name), "%s", new_name);
     858           2 :         req->lvol_store = lvs;
     859           2 :         req->cb_fn = cb_fn;
     860           2 :         req->cb_arg = cb_arg;
     861             : 
     862           2 :         spdk_bs_open_blob(lvs->blobstore, lvs->super_blob_id, lvs_rename_open_cb, req);
     863           5 : }
     864             : 
     865             : static void
     866          27 : _lvs_unload_cb(void *cb_arg, int lvserrno)
     867             : {
     868          27 :         struct spdk_lvs_req *lvs_req = cb_arg;
     869             : 
     870          27 :         SPDK_INFOLOG(lvol, "Lvol store unloaded\n");
     871          27 :         assert(lvs_req->cb_fn != NULL);
     872          27 :         lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
     873          27 :         free(lvs_req);
     874          27 : }
     875             : 
     876             : int
     877          29 : spdk_lvs_unload(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn,
     878             :                 void *cb_arg)
     879             : {
     880             :         struct spdk_lvs_req *lvs_req;
     881             :         struct spdk_lvol *lvol, *tmp;
     882             : 
     883          29 :         if (lvs == NULL) {
     884           1 :                 SPDK_ERRLOG("Lvol store is NULL\n");
     885           1 :                 return -ENODEV;
     886             :         }
     887             : 
     888          52 :         TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
     889          25 :                 if (lvol->action_in_progress == true) {
     890           0 :                         SPDK_ERRLOG("Cannot unload lvol store - operations on lvols pending\n");
     891           0 :                         cb_fn(cb_arg, -EBUSY);
     892           0 :                         return -EBUSY;
     893          25 :                 } else if (lvol->ref_count != 0) {
     894           1 :                         SPDK_ERRLOG("Lvols still open on lvol store\n");
     895           1 :                         cb_fn(cb_arg, -EBUSY);
     896           1 :                         return -EBUSY;
     897             :                 }
     898          24 :         }
     899             : 
     900          51 :         TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
     901          24 :                 spdk_lvs_esnap_missing_remove(lvol);
     902          24 :                 TAILQ_REMOVE(&lvs->lvols, lvol, link);
     903          24 :                 lvol_free(lvol);
     904          24 :         }
     905             : 
     906          27 :         lvs_req = calloc(1, sizeof(*lvs_req));
     907          27 :         if (!lvs_req) {
     908           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
     909           0 :                 return -ENOMEM;
     910             :         }
     911             : 
     912          27 :         lvs_req->cb_fn = cb_fn;
     913          27 :         lvs_req->cb_arg = cb_arg;
     914             : 
     915          27 :         SPDK_INFOLOG(lvol, "Unloading lvol store\n");
     916          27 :         spdk_bs_unload(lvs->blobstore, _lvs_unload_cb, lvs_req);
     917          27 :         lvs_free(lvs);
     918             : 
     919          27 :         return 0;
     920          29 : }
     921             : 
     922             : static void
     923          28 : _lvs_destroy_cb(void *cb_arg, int lvserrno)
     924             : {
     925          28 :         struct spdk_lvs_destroy_req *lvs_req = cb_arg;
     926             : 
     927          28 :         SPDK_INFOLOG(lvol, "Lvol store destroyed\n");
     928          28 :         assert(lvs_req->cb_fn != NULL);
     929          28 :         lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
     930          28 :         free(lvs_req);
     931          28 : }
     932             : 
     933             : static void
     934          28 : _lvs_destroy_super_cb(void *cb_arg, int bserrno)
     935             : {
     936          28 :         struct spdk_lvs_destroy_req *lvs_req = cb_arg;
     937          28 :         struct spdk_lvol_store *lvs = lvs_req->lvs;
     938             : 
     939          28 :         assert(lvs != NULL);
     940             : 
     941          28 :         SPDK_INFOLOG(lvol, "Destroying lvol store\n");
     942          28 :         spdk_bs_destroy(lvs->blobstore, _lvs_destroy_cb, lvs_req);
     943          28 :         lvs_free(lvs);
     944          28 : }
     945             : 
     946             : int
     947          29 : spdk_lvs_destroy(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn,
     948             :                  void *cb_arg)
     949             : {
     950             :         struct spdk_lvs_destroy_req *lvs_req;
     951             :         struct spdk_lvol *iter_lvol, *tmp;
     952             : 
     953          29 :         if (lvs == NULL) {
     954           0 :                 SPDK_ERRLOG("Lvol store is NULL\n");
     955           0 :                 return -ENODEV;
     956             :         }
     957             : 
     958          32 :         TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
     959           4 :                 if (iter_lvol->action_in_progress == true) {
     960           0 :                         SPDK_ERRLOG("Cannot destroy lvol store - operations on lvols pending\n");
     961           0 :                         cb_fn(cb_arg, -EBUSY);
     962           0 :                         return -EBUSY;
     963           4 :                 } else if (iter_lvol->ref_count != 0) {
     964           1 :                         SPDK_ERRLOG("Lvols still open on lvol store\n");
     965           1 :                         cb_fn(cb_arg, -EBUSY);
     966           1 :                         return -EBUSY;
     967             :                 }
     968           3 :         }
     969             : 
     970          31 :         TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
     971           3 :                 free(iter_lvol);
     972           3 :         }
     973             : 
     974          28 :         lvs_req = calloc(1, sizeof(*lvs_req));
     975          28 :         if (!lvs_req) {
     976           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
     977           0 :                 return -ENOMEM;
     978             :         }
     979             : 
     980          28 :         lvs_req->cb_fn = cb_fn;
     981          28 :         lvs_req->cb_arg = cb_arg;
     982          28 :         lvs_req->lvs = lvs;
     983             : 
     984          28 :         SPDK_INFOLOG(lvol, "Deleting super blob\n");
     985          28 :         spdk_bs_delete_blob(lvs->blobstore, lvs->super_blob_id, _lvs_destroy_super_cb, lvs_req);
     986             : 
     987          28 :         return 0;
     988          29 : }
     989             : 
     990             : static void
     991          80 : lvol_close_blob_cb(void *cb_arg, int lvolerrno)
     992             : {
     993          80 :         struct spdk_lvol_req *req = cb_arg;
     994          80 :         struct spdk_lvol *lvol = req->lvol;
     995             : 
     996          80 :         if (lvolerrno < 0) {
     997           1 :                 SPDK_ERRLOG("Could not close blob on lvol\n");
     998           1 :                 goto end;
     999             :         }
    1000             : 
    1001          79 :         lvol->ref_count--;
    1002          79 :         lvol->blob = NULL;
    1003          79 :         SPDK_INFOLOG(lvol, "Lvol %s closed\n", lvol->unique_id);
    1004             : 
    1005             : end:
    1006          80 :         lvol->action_in_progress = false;
    1007          80 :         req->cb_fn(req->cb_arg, lvolerrno);
    1008          80 :         free(req);
    1009          80 : }
    1010             : 
    1011             : bool
    1012           0 : spdk_lvol_deletable(struct spdk_lvol *lvol)
    1013             : {
    1014           0 :         size_t count = 0;
    1015             : 
    1016           0 :         spdk_blob_get_clones(lvol->lvol_store->blobstore, lvol->blob_id, NULL, &count);
    1017           0 :         return (count == 0);
    1018             : }
    1019             : 
    1020             : static void
    1021          56 : lvol_delete_blob_cb(void *cb_arg, int lvolerrno)
    1022             : {
    1023          56 :         struct spdk_lvol_req *req = cb_arg;
    1024          56 :         struct spdk_lvol *lvol = req->lvol;
    1025          56 :         struct spdk_lvol *clone_lvol = req->clone_lvol;
    1026             : 
    1027          56 :         if (lvolerrno < 0) {
    1028           1 :                 SPDK_ERRLOG("Could not remove blob on lvol gracefully - forced removal\n");
    1029           1 :         } else {
    1030          55 :                 SPDK_INFOLOG(lvol, "Lvol %s deleted\n", lvol->unique_id);
    1031             :         }
    1032             : 
    1033          56 :         if (lvol->degraded_set != NULL) {
    1034          12 :                 if (clone_lvol != NULL) {
    1035             :                         /*
    1036             :                          * A degraded esnap clone that has a blob clone has been deleted. clone_lvol
    1037             :                          * becomes an esnap clone and needs to be associated with the
    1038             :                          * spdk_lvs_degraded_lvol_set.
    1039             :                          */
    1040           1 :                         struct spdk_lvs_degraded_lvol_set *degraded_set = lvol->degraded_set;
    1041             : 
    1042           1 :                         lvs_degraded_lvol_set_remove(degraded_set, lvol);
    1043           1 :                         lvs_degraded_lvol_set_add(degraded_set, clone_lvol);
    1044           1 :                 } else {
    1045          11 :                         spdk_lvs_esnap_missing_remove(lvol);
    1046             :                 }
    1047          12 :         }
    1048             : 
    1049          56 :         TAILQ_REMOVE(&lvol->lvol_store->lvols, lvol, link);
    1050          56 :         lvol_free(lvol);
    1051          56 :         req->cb_fn(req->cb_arg, lvolerrno);
    1052          56 :         free(req);
    1053          56 : }
    1054             : 
    1055             : static void
    1056          75 : lvol_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
    1057             : {
    1058          75 :         struct spdk_lvol_with_handle_req *req = cb_arg;
    1059          75 :         struct spdk_lvol *lvol = req->lvol;
    1060             : 
    1061          75 :         TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
    1062             : 
    1063          75 :         if (lvolerrno < 0) {
    1064           0 :                 lvol_free(lvol);
    1065           0 :                 req->cb_fn(req->cb_arg, NULL, lvolerrno);
    1066           0 :                 free(req);
    1067           0 :                 return;
    1068             :         }
    1069             : 
    1070          75 :         lvol->blob = blob;
    1071          75 :         lvol->blob_id = spdk_blob_get_id(blob);
    1072             : 
    1073          75 :         TAILQ_INSERT_TAIL(&lvol->lvol_store->lvols, lvol, link);
    1074             : 
    1075          75 :         lvol->ref_count++;
    1076             : 
    1077          75 :         assert(req->cb_fn != NULL);
    1078          75 :         req->cb_fn(req->cb_arg, req->lvol, lvolerrno);
    1079          75 :         free(req);
    1080          75 : }
    1081             : 
    1082             : static void
    1083          76 : lvol_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
    1084             : {
    1085          76 :         struct spdk_lvol_with_handle_req *req = cb_arg;
    1086             :         struct spdk_blob_store *bs;
    1087             :         struct spdk_blob_open_opts opts;
    1088             : 
    1089          76 :         if (lvolerrno < 0) {
    1090           1 :                 TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
    1091           1 :                 lvol_free(req->lvol);
    1092           1 :                 assert(req->cb_fn != NULL);
    1093           1 :                 req->cb_fn(req->cb_arg, NULL, lvolerrno);
    1094           1 :                 free(req);
    1095           1 :                 return;
    1096             :         }
    1097             : 
    1098          75 :         spdk_blob_open_opts_init(&opts, sizeof(opts));
    1099          75 :         opts.clear_method = req->lvol->clear_method;
    1100             :         /*
    1101             :          * If the lvol that is being created is an esnap clone, the blobstore needs to be able to
    1102             :          * pass the lvol to the esnap_bs_dev_create callback. In order for that to happen, we need
    1103             :          * to pass it here.
    1104             :          *
    1105             :          * This does set ensap_ctx in cases where it's not needed, but we don't know that it's not
    1106             :          * needed until after the blob is open. When the blob is not an esnap clone, a reference to
    1107             :          * the value stored in opts.esnap_ctx is not retained by the blobstore.
    1108             :          */
    1109          75 :         opts.esnap_ctx = req->lvol;
    1110          75 :         bs = req->lvol->lvol_store->blobstore;
    1111             : 
    1112          75 :         if (req->origlvol != NULL && req->origlvol->degraded_set != NULL) {
    1113             :                 /*
    1114             :                  * A snapshot was created from a degraded esnap clone. The new snapshot is now a
    1115             :                  * degraded esnap clone. The previous clone is now a regular clone of a blob. Update
    1116             :                  * the set of directly-related clones to the missing external snapshot.
    1117             :                  */
    1118           1 :                 struct spdk_lvs_degraded_lvol_set *degraded_set = req->origlvol->degraded_set;
    1119             : 
    1120           1 :                 lvs_degraded_lvol_set_remove(degraded_set, req->origlvol);
    1121           1 :                 lvs_degraded_lvol_set_add(degraded_set, req->lvol);
    1122           1 :         }
    1123             : 
    1124          75 :         spdk_bs_open_blob_ext(bs, blobid, &opts, lvol_create_open_cb, req);
    1125          76 : }
    1126             : 
    1127             : static void
    1128           2 : lvol_get_xattr_value(void *xattr_ctx, const char *name,
    1129             :                      const void **value, size_t *value_len)
    1130             : {
    1131           2 :         struct spdk_lvol *lvol = xattr_ctx;
    1132             : 
    1133           2 :         if (!strcmp(LVOL_NAME, name)) {
    1134           1 :                 *value = lvol->name;
    1135           1 :                 *value_len = SPDK_LVOL_NAME_MAX;
    1136           1 :                 return;
    1137             :         }
    1138           1 :         if (!strcmp("uuid", name)) {
    1139           0 :                 *value = lvol->uuid_str;
    1140           0 :                 *value_len = sizeof(lvol->uuid_str);
    1141           0 :                 return;
    1142             :         }
    1143           1 :         *value = NULL;
    1144           1 :         *value_len = 0;
    1145           2 : }
    1146             : 
    1147             : static int
    1148          95 : lvs_verify_lvol_name(struct spdk_lvol_store *lvs, const char *name)
    1149             : {
    1150             :         struct spdk_lvol *tmp;
    1151             : 
    1152          95 :         if (name == NULL || strnlen(name, SPDK_LVOL_NAME_MAX) == 0) {
    1153           7 :                 SPDK_INFOLOG(lvol, "lvol name not provided.\n");
    1154           7 :                 return -EINVAL;
    1155             :         }
    1156             : 
    1157          88 :         if (strnlen(name, SPDK_LVOL_NAME_MAX) == SPDK_LVOL_NAME_MAX) {
    1158           2 :                 SPDK_ERRLOG("Name has no null terminator.\n");
    1159           2 :                 return -EINVAL;
    1160             :         }
    1161             : 
    1162         130 :         TAILQ_FOREACH(tmp, &lvs->lvols, link) {
    1163          52 :                 if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
    1164           8 :                         SPDK_ERRLOG("lvol with name %s already exists\n", name);
    1165           8 :                         return -EEXIST;
    1166             :                 }
    1167          44 :         }
    1168             : 
    1169          78 :         TAILQ_FOREACH(tmp, &lvs->pending_lvols, link) {
    1170           1 :                 if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
    1171           1 :                         SPDK_ERRLOG("lvol with name %s is being already created\n", name);
    1172           1 :                         return -EEXIST;
    1173             :                 }
    1174           0 :         }
    1175             : 
    1176          77 :         return 0;
    1177          95 : }
    1178             : 
    1179             : int
    1180          42 : spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
    1181             :                  bool thin_provision, enum lvol_clear_method clear_method, spdk_lvol_op_with_handle_complete cb_fn,
    1182             :                  void *cb_arg)
    1183             : {
    1184             :         struct spdk_lvol_with_handle_req *req;
    1185             :         struct spdk_blob_store *bs;
    1186             :         struct spdk_lvol *lvol;
    1187             :         struct spdk_blob_opts opts;
    1188          42 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1189             :         int rc;
    1190             : 
    1191          42 :         if (lvs == NULL) {
    1192           1 :                 SPDK_ERRLOG("lvol store does not exist\n");
    1193           1 :                 return -EINVAL;
    1194             :         }
    1195             : 
    1196          41 :         rc = lvs_verify_lvol_name(lvs, name);
    1197          41 :         if (rc < 0) {
    1198           7 :                 return rc;
    1199             :         }
    1200             : 
    1201          34 :         bs = lvs->blobstore;
    1202             : 
    1203          34 :         req = calloc(1, sizeof(*req));
    1204          34 :         if (!req) {
    1205           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1206           0 :                 return -ENOMEM;
    1207             :         }
    1208          34 :         req->cb_fn = cb_fn;
    1209          34 :         req->cb_arg = cb_arg;
    1210             : 
    1211          34 :         lvol = lvol_alloc(lvs, name, thin_provision, clear_method);
    1212          34 :         if (!lvol) {
    1213           0 :                 free(req);
    1214           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
    1215           0 :                 return -ENOMEM;
    1216             :         }
    1217             : 
    1218          34 :         req->lvol = lvol;
    1219          34 :         spdk_blob_opts_init(&opts, sizeof(opts));
    1220          34 :         opts.thin_provision = thin_provision;
    1221          34 :         opts.num_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(bs));
    1222          34 :         opts.clear_method = lvol->clear_method;
    1223          34 :         opts.xattrs.count = SPDK_COUNTOF(xattr_names);
    1224          34 :         opts.xattrs.names = xattr_names;
    1225          34 :         opts.xattrs.ctx = lvol;
    1226          34 :         opts.xattrs.get_value = lvol_get_xattr_value;
    1227             : 
    1228          34 :         spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
    1229             : 
    1230          34 :         return 0;
    1231          42 : }
    1232             : 
    1233             : int
    1234          38 : spdk_lvol_create_esnap_clone(const void *esnap_id, uint32_t id_len, uint64_t size_bytes,
    1235             :                              struct spdk_lvol_store *lvs, const char *clone_name,
    1236             :                              spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
    1237             : {
    1238             :         struct spdk_lvol_with_handle_req *req;
    1239             :         struct spdk_blob_store *bs;
    1240             :         struct spdk_lvol *lvol;
    1241             :         struct spdk_blob_opts opts;
    1242             :         uint64_t cluster_sz;
    1243          38 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1244             :         int rc;
    1245             : 
    1246          38 :         if (lvs == NULL) {
    1247           1 :                 SPDK_ERRLOG("lvol store does not exist\n");
    1248           1 :                 return -EINVAL;
    1249             :         }
    1250             : 
    1251          37 :         rc = lvs_verify_lvol_name(lvs, clone_name);
    1252          37 :         if (rc < 0) {
    1253           5 :                 return rc;
    1254             :         }
    1255             : 
    1256          32 :         bs = lvs->blobstore;
    1257             : 
    1258          32 :         cluster_sz = spdk_bs_get_cluster_size(bs);
    1259          32 :         if ((size_bytes % cluster_sz) != 0) {
    1260           1 :                 SPDK_ERRLOG("Cannot create '%s/%s': size %" PRIu64 " is not an integer multiple of "
    1261             :                             "cluster size %" PRIu64 "\n", lvs->name, clone_name, size_bytes,
    1262             :                             cluster_sz);
    1263           1 :                 return -EINVAL;
    1264             :         }
    1265             : 
    1266          31 :         req = calloc(1, sizeof(*req));
    1267          31 :         if (!req) {
    1268           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1269           0 :                 return -ENOMEM;
    1270             :         }
    1271          31 :         req->cb_fn = cb_fn;
    1272          31 :         req->cb_arg = cb_arg;
    1273             : 
    1274          31 :         lvol = lvol_alloc(lvs, clone_name, true, LVOL_CLEAR_WITH_DEFAULT);
    1275          31 :         if (!lvol) {
    1276           0 :                 free(req);
    1277           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
    1278           0 :                 return -ENOMEM;
    1279             :         }
    1280          31 :         req->lvol = lvol;
    1281             : 
    1282          31 :         spdk_blob_opts_init(&opts, sizeof(opts));
    1283          31 :         opts.esnap_id = esnap_id;
    1284          31 :         opts.esnap_id_len = id_len;
    1285          31 :         opts.thin_provision = true;
    1286          31 :         opts.num_clusters = spdk_divide_round_up(size_bytes, cluster_sz);
    1287          31 :         opts.clear_method = lvol->clear_method;
    1288          31 :         opts.xattrs.count = SPDK_COUNTOF(xattr_names);
    1289          31 :         opts.xattrs.names = xattr_names;
    1290          31 :         opts.xattrs.ctx = lvol;
    1291          31 :         opts.xattrs.get_value = lvol_get_xattr_value;
    1292             : 
    1293          31 :         spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
    1294             : 
    1295          31 :         return 0;
    1296          38 : }
    1297             : 
    1298             : void
    1299          11 : spdk_lvol_create_snapshot(struct spdk_lvol *origlvol, const char *snapshot_name,
    1300             :                           spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
    1301             : {
    1302             :         struct spdk_lvol_store *lvs;
    1303             :         struct spdk_lvol *newlvol;
    1304             :         struct spdk_blob *origblob;
    1305             :         struct spdk_lvol_with_handle_req *req;
    1306             :         struct spdk_blob_xattr_opts snapshot_xattrs;
    1307          11 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1308             :         int rc;
    1309             : 
    1310          11 :         if (origlvol == NULL) {
    1311           1 :                 SPDK_INFOLOG(lvol, "Lvol not provided.\n");
    1312           1 :                 cb_fn(cb_arg, NULL, -EINVAL);
    1313           1 :                 return;
    1314             :         }
    1315             : 
    1316          10 :         origblob = origlvol->blob;
    1317          10 :         lvs = origlvol->lvol_store;
    1318          10 :         if (lvs == NULL) {
    1319           0 :                 SPDK_ERRLOG("lvol store does not exist\n");
    1320           0 :                 cb_fn(cb_arg, NULL, -EINVAL);
    1321           0 :                 return;
    1322             :         }
    1323             : 
    1324          10 :         rc = lvs_verify_lvol_name(lvs, snapshot_name);
    1325          10 :         if (rc < 0) {
    1326           3 :                 cb_fn(cb_arg, NULL, rc);
    1327           3 :                 return;
    1328             :         }
    1329             : 
    1330           7 :         req = calloc(1, sizeof(*req));
    1331           7 :         if (!req) {
    1332           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1333           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1334           0 :                 return;
    1335             :         }
    1336             : 
    1337          14 :         newlvol = lvol_alloc(origlvol->lvol_store, snapshot_name, true,
    1338           7 :                              (enum lvol_clear_method)origlvol->clear_method);
    1339           7 :         if (!newlvol) {
    1340           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
    1341           0 :                 free(req);
    1342           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1343           0 :                 return;
    1344             :         }
    1345             : 
    1346           7 :         snapshot_xattrs.count = SPDK_COUNTOF(xattr_names);
    1347           7 :         snapshot_xattrs.ctx = newlvol;
    1348           7 :         snapshot_xattrs.names = xattr_names;
    1349           7 :         snapshot_xattrs.get_value = lvol_get_xattr_value;
    1350           7 :         req->lvol = newlvol;
    1351           7 :         req->origlvol = origlvol;
    1352           7 :         req->cb_fn = cb_fn;
    1353           7 :         req->cb_arg = cb_arg;
    1354             : 
    1355          14 :         spdk_bs_create_snapshot(lvs->blobstore, spdk_blob_get_id(origblob), &snapshot_xattrs,
    1356           7 :                                 lvol_create_cb, req);
    1357          11 : }
    1358             : 
    1359             : void
    1360           8 : spdk_lvol_create_clone(struct spdk_lvol *origlvol, const char *clone_name,
    1361             :                        spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
    1362             : {
    1363             :         struct spdk_lvol *newlvol;
    1364             :         struct spdk_lvol_with_handle_req *req;
    1365             :         struct spdk_lvol_store *lvs;
    1366             :         struct spdk_blob *origblob;
    1367             :         struct spdk_blob_xattr_opts clone_xattrs;
    1368           8 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1369             :         int rc;
    1370             : 
    1371           8 :         if (origlvol == NULL) {
    1372           1 :                 SPDK_INFOLOG(lvol, "Lvol not provided.\n");
    1373           1 :                 cb_fn(cb_arg, NULL, -EINVAL);
    1374           1 :                 return;
    1375             :         }
    1376             : 
    1377           7 :         origblob = origlvol->blob;
    1378           7 :         lvs = origlvol->lvol_store;
    1379           7 :         if (lvs == NULL) {
    1380           0 :                 SPDK_ERRLOG("lvol store does not exist\n");
    1381           0 :                 cb_fn(cb_arg, NULL, -EINVAL);
    1382           0 :                 return;
    1383             :         }
    1384             : 
    1385           7 :         rc = lvs_verify_lvol_name(lvs, clone_name);
    1386           7 :         if (rc < 0) {
    1387           3 :                 cb_fn(cb_arg, NULL, rc);
    1388           3 :                 return;
    1389             :         }
    1390             : 
    1391           4 :         req = calloc(1, sizeof(*req));
    1392           4 :         if (!req) {
    1393           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1394           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1395           0 :                 return;
    1396             :         }
    1397             : 
    1398           4 :         newlvol = lvol_alloc(lvs, clone_name, true, (enum lvol_clear_method)origlvol->clear_method);
    1399           4 :         if (!newlvol) {
    1400           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
    1401           0 :                 free(req);
    1402           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1403           0 :                 return;
    1404             :         }
    1405             : 
    1406           4 :         clone_xattrs.count = SPDK_COUNTOF(xattr_names);
    1407           4 :         clone_xattrs.ctx = newlvol;
    1408           4 :         clone_xattrs.names = xattr_names;
    1409           4 :         clone_xattrs.get_value = lvol_get_xattr_value;
    1410           4 :         req->lvol = newlvol;
    1411           4 :         req->cb_fn = cb_fn;
    1412           4 :         req->cb_arg = cb_arg;
    1413             : 
    1414           8 :         spdk_bs_create_clone(lvs->blobstore, spdk_blob_get_id(origblob), &clone_xattrs,
    1415             :                              lvol_create_cb,
    1416           4 :                              req);
    1417           8 : }
    1418             : 
    1419             : static void
    1420           4 : lvol_resize_done(void *cb_arg, int lvolerrno)
    1421             : {
    1422           4 :         struct spdk_lvol_req *req = cb_arg;
    1423             : 
    1424           4 :         req->cb_fn(req->cb_arg,  lvolerrno);
    1425           4 :         free(req);
    1426           4 : }
    1427             : 
    1428             : static void
    1429           6 : lvol_blob_resize_cb(void *cb_arg, int bserrno)
    1430             : {
    1431           6 :         struct spdk_lvol_req *req = cb_arg;
    1432           6 :         struct spdk_lvol *lvol = req->lvol;
    1433             : 
    1434           6 :         if (bserrno != 0) {
    1435           2 :                 req->cb_fn(req->cb_arg, bserrno);
    1436           2 :                 free(req);
    1437           2 :                 return;
    1438             :         }
    1439             : 
    1440           4 :         spdk_blob_sync_md(lvol->blob, lvol_resize_done, req);
    1441           6 : }
    1442             : 
    1443             : void
    1444           6 : spdk_lvol_resize(struct spdk_lvol *lvol, uint64_t sz,
    1445             :                  spdk_lvol_op_complete cb_fn, void *cb_arg)
    1446             : {
    1447           6 :         struct spdk_blob *blob = lvol->blob;
    1448           6 :         struct spdk_lvol_store *lvs = lvol->lvol_store;
    1449             :         struct spdk_lvol_req *req;
    1450           6 :         uint64_t new_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(lvs->blobstore));
    1451             : 
    1452           6 :         req = calloc(1, sizeof(*req));
    1453           6 :         if (!req) {
    1454           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1455           0 :                 cb_fn(cb_arg, -ENOMEM);
    1456           0 :                 return;
    1457             :         }
    1458           6 :         req->cb_fn = cb_fn;
    1459           6 :         req->cb_arg = cb_arg;
    1460           6 :         req->lvol = lvol;
    1461             : 
    1462           6 :         spdk_blob_resize(blob, new_clusters, lvol_blob_resize_cb, req);
    1463           6 : }
    1464             : 
    1465             : static void
    1466           1 : lvol_set_read_only_cb(void *cb_arg, int lvolerrno)
    1467             : {
    1468           1 :         struct spdk_lvol_req *req = cb_arg;
    1469             : 
    1470           1 :         req->cb_fn(req->cb_arg, lvolerrno);
    1471           1 :         free(req);
    1472           1 : }
    1473             : 
    1474             : void
    1475           1 : spdk_lvol_set_read_only(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
    1476             : {
    1477             :         struct spdk_lvol_req *req;
    1478             : 
    1479           1 :         req = calloc(1, sizeof(*req));
    1480           1 :         if (!req) {
    1481           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1482           0 :                 cb_fn(cb_arg, -ENOMEM);
    1483           0 :                 return;
    1484             :         }
    1485           1 :         req->cb_fn = cb_fn;
    1486           1 :         req->cb_arg = cb_arg;
    1487             : 
    1488           1 :         spdk_blob_set_read_only(lvol->blob);
    1489           1 :         spdk_blob_sync_md(lvol->blob, lvol_set_read_only_cb, req);
    1490           1 : }
    1491             : 
    1492             : static void
    1493           1 : lvol_rename_cb(void *cb_arg, int lvolerrno)
    1494             : {
    1495           1 :         struct spdk_lvol_req *req = cb_arg;
    1496             : 
    1497           1 :         if (lvolerrno != 0) {
    1498           0 :                 SPDK_ERRLOG("Lvol rename operation failed\n");
    1499           0 :         } else {
    1500           1 :                 snprintf(req->lvol->name, sizeof(req->lvol->name), "%s", req->name);
    1501             :         }
    1502             : 
    1503           1 :         req->cb_fn(req->cb_arg, lvolerrno);
    1504           1 :         free(req);
    1505           1 : }
    1506             : 
    1507             : void
    1508           2 : spdk_lvol_rename(struct spdk_lvol *lvol, const char *new_name,
    1509             :                  spdk_lvol_op_complete cb_fn, void *cb_arg)
    1510             : {
    1511             :         struct spdk_lvol *tmp;
    1512           2 :         struct spdk_blob *blob = lvol->blob;
    1513             :         struct spdk_lvol_req *req;
    1514             :         int rc;
    1515             : 
    1516             :         /* Check if new name is current lvol name.
    1517             :          * If so, return success immediately */
    1518           2 :         if (strncmp(lvol->name, new_name, SPDK_LVOL_NAME_MAX) == 0) {
    1519           0 :                 cb_fn(cb_arg, 0);
    1520           0 :                 return;
    1521             :         }
    1522             : 
    1523             :         /* Check if lvol with 'new_name' already exists in lvolstore */
    1524           4 :         TAILQ_FOREACH(tmp, &lvol->lvol_store->lvols, link) {
    1525           3 :                 if (strncmp(tmp->name, new_name, SPDK_LVOL_NAME_MAX) == 0) {
    1526           1 :                         SPDK_ERRLOG("Lvol %s already exists in lvol store %s\n", new_name, lvol->lvol_store->name);
    1527           1 :                         cb_fn(cb_arg, -EEXIST);
    1528           1 :                         return;
    1529             :                 }
    1530           2 :         }
    1531             : 
    1532           1 :         req = calloc(1, sizeof(*req));
    1533           1 :         if (!req) {
    1534           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1535           0 :                 cb_fn(cb_arg, -ENOMEM);
    1536           0 :                 return;
    1537             :         }
    1538           1 :         req->cb_fn = cb_fn;
    1539           1 :         req->cb_arg = cb_arg;
    1540           1 :         req->lvol = lvol;
    1541           1 :         snprintf(req->name, sizeof(req->name), "%s", new_name);
    1542             : 
    1543           1 :         rc = spdk_blob_set_xattr(blob, "name", new_name, strlen(new_name) + 1);
    1544           1 :         if (rc < 0) {
    1545           0 :                 free(req);
    1546           0 :                 cb_fn(cb_arg, rc);
    1547           0 :                 return;
    1548             :         }
    1549             : 
    1550           1 :         spdk_blob_sync_md(blob, lvol_rename_cb, req);
    1551           2 : }
    1552             : 
    1553             : void
    1554          57 : spdk_lvol_destroy(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
    1555             : {
    1556             :         struct spdk_lvol_req *req;
    1557             :         struct spdk_blob_store *bs;
    1558             :         struct spdk_lvol_store  *lvs;
    1559             :         spdk_blob_id    clone_id;
    1560          57 :         size_t          count = 1;
    1561             :         int             rc;
    1562             : 
    1563          57 :         assert(cb_fn != NULL);
    1564             : 
    1565          57 :         if (lvol == NULL) {
    1566           0 :                 SPDK_ERRLOG("lvol does not exist\n");
    1567           0 :                 cb_fn(cb_arg, -ENODEV);
    1568           0 :                 return;
    1569             :         }
    1570             : 
    1571          57 :         lvs = lvol->lvol_store;
    1572             : 
    1573          57 :         if (lvol->ref_count != 0) {
    1574           1 :                 SPDK_ERRLOG("Cannot destroy lvol %s because it is still open\n", lvol->unique_id);
    1575           1 :                 cb_fn(cb_arg, -EBUSY);
    1576           1 :                 return;
    1577             :         }
    1578             : 
    1579          56 :         req = calloc(1, sizeof(*req));
    1580          56 :         if (!req) {
    1581           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1582           0 :                 cb_fn(cb_arg, -ENOMEM);
    1583           0 :                 return;
    1584             :         }
    1585             : 
    1586          56 :         req->cb_fn = cb_fn;
    1587          56 :         req->cb_arg = cb_arg;
    1588          56 :         req->lvol = lvol;
    1589          56 :         bs = lvol->lvol_store->blobstore;
    1590             : 
    1591          56 :         rc = spdk_blob_get_clones(lvs->blobstore, lvol->blob_id, &clone_id, &count);
    1592          56 :         if (rc == 0 && count == 1) {
    1593           1 :                 req->clone_lvol = lvs_get_lvol_by_blob_id(lvs, clone_id);
    1594          56 :         } else if (rc == -ENOMEM) {
    1595           0 :                 SPDK_INFOLOG(lvol, "lvol %s: cannot destroy: has %" PRIu64 " clones\n",
    1596             :                              lvol->unique_id, count);
    1597           0 :                 free(req);
    1598           0 :                 assert(count > 1);
    1599           0 :                 cb_fn(cb_arg, -EBUSY);
    1600           0 :                 return;
    1601             :         }
    1602             : 
    1603          56 :         lvol->action_in_progress = true;
    1604             : 
    1605          56 :         spdk_bs_delete_blob(bs, lvol->blob_id, lvol_delete_blob_cb, req);
    1606          57 : }
    1607             : 
    1608             : void
    1609          84 : spdk_lvol_close(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
    1610             : {
    1611             :         struct spdk_lvol_req *req;
    1612             : 
    1613          84 :         assert(cb_fn != NULL);
    1614             : 
    1615          84 :         if (lvol == NULL) {
    1616           1 :                 SPDK_ERRLOG("lvol does not exist\n");
    1617           1 :                 cb_fn(cb_arg, -ENODEV);
    1618           1 :                 return;
    1619             :         }
    1620             : 
    1621          83 :         if (lvol->ref_count > 1) {
    1622           1 :                 lvol->ref_count--;
    1623           1 :                 cb_fn(cb_arg, 0);
    1624           1 :                 return;
    1625          82 :         } else if (lvol->ref_count == 0) {
    1626           2 :                 cb_fn(cb_arg, -EINVAL);
    1627           2 :                 return;
    1628             :         }
    1629             : 
    1630          80 :         req = calloc(1, sizeof(*req));
    1631          80 :         if (!req) {
    1632           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1633           0 :                 cb_fn(cb_arg, -ENOMEM);
    1634           0 :                 return;
    1635             :         }
    1636             : 
    1637          80 :         req->cb_fn = cb_fn;
    1638          80 :         req->cb_arg = cb_arg;
    1639          80 :         req->lvol = lvol;
    1640             : 
    1641          80 :         lvol->action_in_progress = true;
    1642             : 
    1643          80 :         spdk_blob_close(lvol->blob, lvol_close_blob_cb, req);
    1644          84 : }
    1645             : 
    1646             : struct spdk_io_channel *
    1647           0 : spdk_lvol_get_io_channel(struct spdk_lvol *lvol)
    1648             : {
    1649           0 :         return spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    1650             : }
    1651             : 
    1652             : static void
    1653           4 : lvol_inflate_cb(void *cb_arg, int lvolerrno)
    1654             : {
    1655           4 :         struct spdk_lvol_req *req = cb_arg;
    1656             : 
    1657           4 :         spdk_bs_free_io_channel(req->channel);
    1658             : 
    1659           4 :         if (lvolerrno < 0) {
    1660           2 :                 SPDK_ERRLOG("Could not inflate lvol\n");
    1661           2 :         }
    1662             : 
    1663           4 :         req->cb_fn(req->cb_arg, lvolerrno);
    1664           4 :         free(req);
    1665           4 : }
    1666             : 
    1667             : void
    1668           2 : spdk_lvol_inflate(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
    1669             : {
    1670             :         struct spdk_lvol_req *req;
    1671             :         spdk_blob_id blob_id;
    1672             : 
    1673           2 :         assert(cb_fn != NULL);
    1674             : 
    1675           2 :         if (lvol == NULL) {
    1676           0 :                 SPDK_ERRLOG("Lvol does not exist\n");
    1677           0 :                 cb_fn(cb_arg, -ENODEV);
    1678           0 :                 return;
    1679             :         }
    1680             : 
    1681           2 :         req = calloc(1, sizeof(*req));
    1682           2 :         if (!req) {
    1683           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1684           0 :                 cb_fn(cb_arg, -ENOMEM);
    1685           0 :                 return;
    1686             :         }
    1687             : 
    1688           2 :         req->cb_fn = cb_fn;
    1689           2 :         req->cb_arg = cb_arg;
    1690           2 :         req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    1691           2 :         if (req->channel == NULL) {
    1692           0 :                 SPDK_ERRLOG("Cannot alloc io channel for lvol inflate request\n");
    1693           0 :                 free(req);
    1694           0 :                 cb_fn(cb_arg, -ENOMEM);
    1695           0 :                 return;
    1696             :         }
    1697             : 
    1698           2 :         blob_id = spdk_blob_get_id(lvol->blob);
    1699           4 :         spdk_bs_inflate_blob(lvol->lvol_store->blobstore, req->channel, blob_id, lvol_inflate_cb,
    1700           2 :                              req);
    1701           2 : }
    1702             : 
    1703             : void
    1704           2 : spdk_lvol_decouple_parent(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg)
    1705             : {
    1706             :         struct spdk_lvol_req *req;
    1707             :         spdk_blob_id blob_id;
    1708             : 
    1709           2 :         assert(cb_fn != NULL);
    1710             : 
    1711           2 :         if (lvol == NULL) {
    1712           0 :                 SPDK_ERRLOG("Lvol does not exist\n");
    1713           0 :                 cb_fn(cb_arg, -ENODEV);
    1714           0 :                 return;
    1715             :         }
    1716             : 
    1717           2 :         req = calloc(1, sizeof(*req));
    1718           2 :         if (!req) {
    1719           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1720           0 :                 cb_fn(cb_arg, -ENOMEM);
    1721           0 :                 return;
    1722             :         }
    1723             : 
    1724           2 :         req->cb_fn = cb_fn;
    1725           2 :         req->cb_arg = cb_arg;
    1726           2 :         req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    1727           2 :         if (req->channel == NULL) {
    1728           0 :                 SPDK_ERRLOG("Cannot alloc io channel for lvol inflate request\n");
    1729           0 :                 free(req);
    1730           0 :                 cb_fn(cb_arg, -ENOMEM);
    1731           0 :                 return;
    1732             :         }
    1733             : 
    1734           2 :         blob_id = spdk_blob_get_id(lvol->blob);
    1735           4 :         spdk_bs_blob_decouple_parent(lvol->lvol_store->blobstore, req->channel, blob_id,
    1736           2 :                                      lvol_inflate_cb, req);
    1737           2 : }
    1738             : 
    1739             : static void
    1740           0 : lvs_grow_live_cb(void *cb_arg, int lvolerrno)
    1741             : {
    1742           0 :         struct spdk_lvs_req *req = (struct spdk_lvs_req *)cb_arg;
    1743             : 
    1744           0 :         if (req->cb_fn) {
    1745           0 :                 req->cb_fn(req->cb_arg, lvolerrno);
    1746           0 :         }
    1747           0 :         free(req);
    1748           0 :         return;
    1749             : }
    1750             : 
    1751             : void
    1752           0 : spdk_lvs_grow_live(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, void *cb_arg)
    1753             : {
    1754             :         struct spdk_lvs_req *req;
    1755             : 
    1756           0 :         req = calloc(1, sizeof(*req));
    1757           0 :         if (req == NULL) {
    1758           0 :                 SPDK_ERRLOG("Cannot alloc memory for request structure\n");
    1759           0 :                 if (cb_fn) {
    1760           0 :                         cb_fn(cb_arg, -ENOMEM);
    1761           0 :                 }
    1762           0 :                 return;
    1763             :         }
    1764             : 
    1765           0 :         req->cb_fn = cb_fn;
    1766           0 :         req->cb_arg = cb_arg;
    1767           0 :         req->lvol_store = lvs;
    1768             : 
    1769           0 :         spdk_bs_grow_live(lvs->blobstore, lvs_grow_live_cb, req);
    1770           0 : }
    1771             : 
    1772             : void
    1773           0 : spdk_lvs_grow(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
    1774             : {
    1775             :         struct spdk_lvs_with_handle_req *req;
    1776           0 :         struct spdk_bs_opts opts = {};
    1777             : 
    1778           0 :         assert(cb_fn != NULL);
    1779             : 
    1780           0 :         if (bs_dev == NULL) {
    1781           0 :                 SPDK_ERRLOG("Blobstore device does not exist\n");
    1782           0 :                 cb_fn(cb_arg, NULL, -ENODEV);
    1783           0 :                 return;
    1784             :         }
    1785             : 
    1786           0 :         req = calloc(1, sizeof(*req));
    1787           0 :         if (req == NULL) {
    1788           0 :                 SPDK_ERRLOG("Cannot alloc memory for request structure\n");
    1789           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1790           0 :                 return;
    1791             :         }
    1792             : 
    1793           0 :         req->lvol_store = lvs_alloc();
    1794           0 :         if (req->lvol_store == NULL) {
    1795           0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store\n");
    1796           0 :                 free(req);
    1797           0 :                 cb_fn(cb_arg, NULL, -ENOMEM);
    1798           0 :                 return;
    1799             :         }
    1800           0 :         req->cb_fn = cb_fn;
    1801           0 :         req->cb_arg = cb_arg;
    1802           0 :         req->bs_dev = bs_dev;
    1803             : 
    1804           0 :         lvs_bs_opts_init(&opts);
    1805           0 :         snprintf(opts.bstype.bstype, sizeof(opts.bstype.bstype), "LVOLSTORE");
    1806             : 
    1807           0 :         spdk_bs_grow(bs_dev, &opts, lvs_load_cb, req);
    1808           0 : }
    1809             : 
    1810             : static struct spdk_lvol *
    1811           5 : lvs_get_lvol_by_blob_id(struct spdk_lvol_store *lvs, spdk_blob_id blob_id)
    1812             : {
    1813             :         struct spdk_lvol *lvol;
    1814             : 
    1815           7 :         TAILQ_FOREACH(lvol, &lvs->lvols, link) {
    1816           7 :                 if (lvol->blob_id == blob_id) {
    1817           5 :                         return lvol;
    1818             :                 }
    1819           2 :         }
    1820           0 :         return NULL;
    1821           5 : }
    1822             : 
    1823             : static int
    1824           6 : lvs_esnap_bs_dev_create(void *bs_ctx, void *blob_ctx, struct spdk_blob *blob,
    1825             :                         const void *esnap_id, uint32_t id_len,
    1826             :                         struct spdk_bs_dev **bs_dev)
    1827             : {
    1828           6 :         struct spdk_lvol_store  *lvs = bs_ctx;
    1829           6 :         struct spdk_lvol        *lvol = blob_ctx;
    1830           6 :         spdk_blob_id            blob_id = spdk_blob_get_id(blob);
    1831             : 
    1832           6 :         if (lvs == NULL) {
    1833           2 :                 if (lvol == NULL || lvol->lvol_store == NULL) {
    1834           1 :                         SPDK_ERRLOG("Blob 0x%" PRIx64 ": no lvs context nor lvol context\n",
    1835             :                                     blob_id);
    1836           1 :                         return -EINVAL;
    1837             :                 }
    1838           1 :                 lvs = lvol->lvol_store;
    1839           1 :         }
    1840             : 
    1841             :         /*
    1842             :          * When spdk_lvs_load() is called, it iterates through all blobs in its blobstore building
    1843             :          * up a list of lvols (lvs->lvols). During this initial iteration, each blob is opened,
    1844             :          * passed to load_next_lvol(), then closed. There is no need to open the external snapshot
    1845             :          * during this phase. Once the blobstore is loaded, lvs->load_esnaps is set to true so that
    1846             :          * future lvol opens cause the external snapshot to be loaded.
    1847             :          */
    1848           5 :         if (!lvs->load_esnaps) {
    1849           4 :                 *bs_dev = NULL;
    1850           4 :                 return 0;
    1851             :         }
    1852             : 
    1853           1 :         if (lvol == NULL) {
    1854           0 :                 spdk_blob_id blob_id = spdk_blob_get_id(blob);
    1855             : 
    1856             :                 /*
    1857             :                  * If spdk_bs_blob_open() is used instead of spdk_bs_blob_open_ext() the lvol will
    1858             :                  * not have been passed in. The same is true if the open happens spontaneously due
    1859             :                  * to blobstore activity.
    1860             :                  */
    1861           0 :                 lvol = lvs_get_lvol_by_blob_id(lvs, blob_id);
    1862           0 :                 if (lvol == NULL) {
    1863           0 :                         SPDK_ERRLOG("lvstore %s: no lvol for blob 0x%" PRIx64 "\n",
    1864             :                                     lvs->name, blob_id);
    1865           0 :                         return -ENODEV;
    1866             :                 }
    1867           0 :         }
    1868             : 
    1869           1 :         return lvs->esnap_bs_dev_create(lvs, lvol, blob, esnap_id, id_len, bs_dev);
    1870           6 : }
    1871             : 
    1872             : /*
    1873             :  * The theory of missing external snapshots
    1874             :  *
    1875             :  * The lvs->esnap_bs_dev_create() callback may be unable to create an external snapshot bs_dev when
    1876             :  * it is called. This can happen, for instance, as when the device containing the lvolstore is
    1877             :  * examined prior to spdk_bdev_register() being called on a bdev that acts as an external snapshot.
    1878             :  * In such a case, the esnap_bs_dev_create() callback will call spdk_lvs_esnap_missing_add().
    1879             :  *
    1880             :  * Missing external snapshots are tracked in a per-lvolstore tree, lvs->degraded_lvol_sets_tree.
    1881             :  * Each tree node (struct spdk_lvs_degraded_lvol_set) contains a tailq of lvols that are missing
    1882             :  * that particular external snapshot.
    1883             :  *
    1884             :  * When a potential missing snapshot becomes available, spdk_lvs_notify_hotplug() may be called to
    1885             :  * notify this library that it is available. It will then iterate through the active lvolstores and
    1886             :  * search each lvs->degraded_lvol_sets_tree for a set of degraded lvols that are missing an external
    1887             :  * snapshot matching the id passed in the notification. The lvols in the tailq on each matching tree
    1888             :  * node are then asked to create an external snapshot bs_dev using the esnap_bs_dev_create()
    1889             :  * callback that the consumer registered with the lvolstore. If lvs->esnap_bs_dev_create() returns
    1890             :  * 0, the lvol is removed from the spdk_lvs_degraded_lvol_set's lvol tailq. When this tailq becomes
    1891             :  * empty, the degraded lvol set node for this missing external snapshot is removed.
    1892             :  */
    1893             : static int
    1894          93 : lvs_esnap_name_cmp(struct spdk_lvs_degraded_lvol_set *m1, struct spdk_lvs_degraded_lvol_set *m2)
    1895             : {
    1896          93 :         if (m1->id_len == m2->id_len) {
    1897          93 :                 return memcmp(m1->esnap_id, m2->esnap_id, m1->id_len);
    1898             :         }
    1899           0 :         return (m1->id_len > m2->id_len) ? 1 : -1;
    1900          93 : }
    1901             : 
    1902         265 : RB_GENERATE_STATIC(degraded_lvol_sets_tree, spdk_lvs_degraded_lvol_set, node, lvs_esnap_name_cmp)
    1903             : 
    1904             : static void
    1905          38 : lvs_degraded_lvol_set_add(struct spdk_lvs_degraded_lvol_set *degraded_set, struct spdk_lvol *lvol)
    1906             : {
    1907          38 :         assert(lvol->lvol_store->thread == spdk_get_thread());
    1908             : 
    1909          38 :         lvol->degraded_set = degraded_set;
    1910          38 :         TAILQ_INSERT_TAIL(&degraded_set->lvols, lvol, degraded_link);
    1911          38 : }
    1912             : 
    1913             : static void
    1914          13 : lvs_degraded_lvol_set_remove(struct spdk_lvs_degraded_lvol_set *degraded_set,
    1915             :                              struct spdk_lvol *lvol)
    1916             : {
    1917          13 :         assert(lvol->lvol_store->thread == spdk_get_thread());
    1918             : 
    1919          13 :         lvol->degraded_set = NULL;
    1920          13 :         TAILQ_REMOVE(&degraded_set->lvols, lvol, degraded_link);
    1921             :         /* degraded_set->lvols may be empty. Caller should check if not immediately adding a new
    1922             :          * lvol. */
    1923          13 : }
    1924             : 
    1925             : /*
    1926             :  * Record in lvs->degraded_lvol_sets_tree that a bdev of the specified name is needed by the
    1927             :  * specified lvol.
    1928             :  */
    1929             : int
    1930          36 : spdk_lvs_esnap_missing_add(struct spdk_lvol_store *lvs, struct spdk_lvol *lvol,
    1931             :                            const void *esnap_id, uint32_t id_len)
    1932             : {
    1933             :         struct spdk_lvs_degraded_lvol_set find, *degraded_set;
    1934             : 
    1935          36 :         assert(lvs->thread == spdk_get_thread());
    1936             : 
    1937          36 :         find.esnap_id = esnap_id;
    1938          36 :         find.id_len = id_len;
    1939          36 :         degraded_set = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
    1940          36 :         if (degraded_set == NULL) {
    1941          16 :                 degraded_set = calloc(1, sizeof(*degraded_set));
    1942          16 :                 if (degraded_set == NULL) {
    1943           0 :                         SPDK_ERRLOG("lvol %s: cannot create degraded_set node: out of memory\n",
    1944             :                                     lvol->unique_id);
    1945           0 :                         return -ENOMEM;
    1946             :                 }
    1947          16 :                 degraded_set->esnap_id = calloc(1, id_len);
    1948          16 :                 if (degraded_set->esnap_id == NULL) {
    1949           0 :                         free(degraded_set);
    1950           0 :                         SPDK_ERRLOG("lvol %s: cannot create degraded_set node: out of memory\n",
    1951             :                                     lvol->unique_id);
    1952           0 :                         return -ENOMEM;
    1953             :                 }
    1954          16 :                 memcpy((void *)degraded_set->esnap_id, esnap_id, id_len);
    1955          16 :                 degraded_set->id_len = id_len;
    1956          16 :                 degraded_set->lvol_store = lvs;
    1957          16 :                 TAILQ_INIT(&degraded_set->lvols);
    1958          16 :                 RB_INSERT(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
    1959          16 :         }
    1960             : 
    1961          36 :         lvs_degraded_lvol_set_add(degraded_set, lvol);
    1962             : 
    1963          36 :         return 0;
    1964          36 : }
    1965             : 
    1966             : /*
    1967             :  * Remove the record of the specified lvol needing a degraded_set bdev.
    1968             :  */
    1969             : void
    1970          35 : spdk_lvs_esnap_missing_remove(struct spdk_lvol *lvol)
    1971             : {
    1972          35 :         struct spdk_lvol_store          *lvs = lvol->lvol_store;
    1973          35 :         struct spdk_lvs_degraded_lvol_set       *degraded_set = lvol->degraded_set;
    1974             : 
    1975          35 :         assert(lvs->thread == spdk_get_thread());
    1976             : 
    1977          35 :         if (degraded_set == NULL) {
    1978          24 :                 return;
    1979             :         }
    1980             : 
    1981          11 :         lvs_degraded_lvol_set_remove(degraded_set, lvol);
    1982             : 
    1983          11 :         if (!TAILQ_EMPTY(&degraded_set->lvols)) {
    1984           1 :                 return;
    1985             :         }
    1986             : 
    1987          10 :         RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
    1988             : 
    1989          10 :         free((char *)degraded_set->esnap_id);
    1990          10 :         free(degraded_set);
    1991          35 : }
    1992             : 
    1993             : struct lvs_esnap_hotplug_req {
    1994             :         struct spdk_lvol                        *lvol;
    1995             :         spdk_lvol_op_with_handle_complete       cb_fn;
    1996             :         void                                    *cb_arg;
    1997             : };
    1998             : 
    1999             : static void
    2000          25 : lvs_esnap_hotplug_done(void *cb_arg, int bserrno)
    2001             : {
    2002          25 :         struct lvs_esnap_hotplug_req *req = cb_arg;
    2003          25 :         struct spdk_lvol        *lvol = req->lvol;
    2004          25 :         struct spdk_lvol_store  *lvs = lvol->lvol_store;
    2005             : 
    2006          25 :         if (bserrno != 0) {
    2007           0 :                 SPDK_ERRLOG("lvol %s/%s: failed to hotplug blob_bdev due to error %d\n",
    2008             :                             lvs->name, lvol->name, bserrno);
    2009           0 :         }
    2010          25 :         req->cb_fn(req->cb_arg, lvol, bserrno);
    2011          25 :         free(req);
    2012          25 : }
    2013             : 
    2014             : static void
    2015          15 : lvs_esnap_degraded_hotplug(struct spdk_lvs_degraded_lvol_set *degraded_set,
    2016             :                            spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
    2017             : {
    2018          15 :         struct spdk_lvol_store  *lvs = degraded_set->lvol_store;
    2019             :         struct spdk_lvol        *lvol, *tmp, *last_missing;
    2020             :         struct spdk_bs_dev      *bs_dev;
    2021          15 :         const void              *esnap_id = degraded_set->esnap_id;
    2022          15 :         uint32_t                id_len = degraded_set->id_len;
    2023             :         struct lvs_esnap_hotplug_req *req;
    2024             :         int                     rc;
    2025             : 
    2026          15 :         assert(lvs->thread == spdk_get_thread());
    2027             : 
    2028             :         /*
    2029             :          * When lvs->esnap_bs_bdev_create() tries to load an external snapshot, it can encounter
    2030             :          * errors that lead it to calling spdk_lvs_esnap_missing_add(). This function needs to be
    2031             :          * sure that such modifications do not lead to degraded_set->lvols tailqs or references
    2032             :          * to memory that this function will free.
    2033             :          *
    2034             :          * While this function is running, no other thread can add items to degraded_set->lvols. If
    2035             :          * the list is mutated, it must have been done by this function or something in its call
    2036             :          * graph running on this thread.
    2037             :          */
    2038             : 
    2039             :         /* Remember the last lvol on the list. Iteration will stop once it has been processed. */
    2040          15 :         last_missing = TAILQ_LAST(&degraded_set->lvols, degraded_lvols);
    2041             : 
    2042          28 :         TAILQ_FOREACH_SAFE(lvol, &degraded_set->lvols, degraded_link, tmp) {
    2043          28 :                 req = calloc(1, sizeof(*req));
    2044          28 :                 if (req == NULL) {
    2045           0 :                         SPDK_ERRLOG("lvol %s: failed to create esnap bs_dev: out of memory\n",
    2046             :                                     lvol->unique_id);
    2047           0 :                         cb_fn(cb_arg, lvol, -ENOMEM);
    2048             :                         /* The next one likely won't succeed either, but keep going so that all the
    2049             :                          * failed hotplugs are logged.
    2050             :                          */
    2051           0 :                         goto next;
    2052             :                 }
    2053             : 
    2054             :                 /*
    2055             :                  * Remove the lvol from the tailq so that tailq corruption is avoided if
    2056             :                  * lvs->esnap_bs_dev_create() calls spdk_lvs_esnap_missing_add(lvol).
    2057             :                  */
    2058          28 :                 TAILQ_REMOVE(&degraded_set->lvols, lvol, degraded_link);
    2059          28 :                 lvol->degraded_set = NULL;
    2060             : 
    2061          28 :                 bs_dev = NULL;
    2062          28 :                 rc = lvs->esnap_bs_dev_create(lvs, lvol, lvol->blob, esnap_id, id_len, &bs_dev);
    2063          28 :                 if (rc != 0) {
    2064           3 :                         SPDK_ERRLOG("lvol %s: failed to create esnap bs_dev: error %d\n",
    2065             :                                     lvol->unique_id, rc);
    2066           3 :                         lvol->degraded_set = degraded_set;
    2067           3 :                         TAILQ_INSERT_TAIL(&degraded_set->lvols, lvol, degraded_link);
    2068           3 :                         cb_fn(cb_arg, lvol, rc);
    2069           3 :                         free(req);
    2070           3 :                         goto next;
    2071             :                 }
    2072             : 
    2073          25 :                 req->lvol = lvol;
    2074          25 :                 req->cb_fn = cb_fn;
    2075          25 :                 req->cb_arg = cb_arg;
    2076          25 :                 spdk_blob_set_esnap_bs_dev(lvol->blob, bs_dev, lvs_esnap_hotplug_done, req);
    2077             : 
    2078             : next:
    2079          28 :                 if (lvol == last_missing) {
    2080             :                         /*
    2081             :                          * Anything after last_missing was added due to some problem encountered
    2082             :                          * while trying to create the esnap bs_dev.
    2083             :                          */
    2084          15 :                         break;
    2085             :                 }
    2086          13 :         }
    2087             : 
    2088          15 :         if (TAILQ_EMPTY(&degraded_set->lvols)) {
    2089           6 :                 RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
    2090           6 :                 free((void *)degraded_set->esnap_id);
    2091           6 :                 free(degraded_set);
    2092           6 :         }
    2093          15 : }
    2094             : 
    2095             : /*
    2096             :  * Notify each lvstore created on this thread that is missing a bdev by the specified name or uuid
    2097             :  * that the bdev now exists.
    2098             :  */
    2099             : bool
    2100          15 : spdk_lvs_notify_hotplug(const void *esnap_id, uint32_t id_len,
    2101             :                         spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
    2102             : {
    2103             :         struct spdk_lvs_degraded_lvol_set *found;
    2104          15 :         struct spdk_lvs_degraded_lvol_set find = { 0 };
    2105             :         struct spdk_lvol_store  *lvs;
    2106          15 :         struct spdk_thread      *thread = spdk_get_thread();
    2107          15 :         bool                    ret = false;
    2108             : 
    2109          15 :         find.esnap_id = esnap_id;
    2110          15 :         find.id_len = id_len;
    2111             : 
    2112          15 :         pthread_mutex_lock(&g_lvol_stores_mutex);
    2113          30 :         TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
    2114          15 :                 if (thread != lvs->thread) {
    2115             :                         /*
    2116             :                          * It is expected that this is called from vbdev_lvol's examine_config()
    2117             :                          * callback. The lvstore was likely loaded do a creation happening as a
    2118             :                          * result of an RPC call or opening of an existing lvstore via
    2119             :                          * examine_disk() callback. RPC calls, examine_disk(), and examine_config()
    2120             :                          * should all be happening only on the app thread. The "wrong thread"
    2121             :                          * condition will only happen when an application is doing something weird.
    2122             :                          */
    2123           0 :                         SPDK_NOTICELOG("Discarded examine for lvstore %s: wrong thread\n",
    2124             :                                        lvs->name);
    2125           0 :                         continue;
    2126             :                 }
    2127             : 
    2128          15 :                 found = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
    2129          15 :                 if (found == NULL) {
    2130           0 :                         continue;
    2131             :                 }
    2132             : 
    2133          15 :                 ret = true;
    2134          15 :                 lvs_esnap_degraded_hotplug(found, cb_fn, cb_arg);
    2135          15 :         }
    2136          15 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
    2137             : 
    2138          15 :         return ret;
    2139             : }
    2140             : 
    2141             : int
    2142           4 : spdk_lvol_iter_immediate_clones(struct spdk_lvol *lvol, spdk_lvol_iter_cb cb_fn, void *cb_arg)
    2143             : {
    2144           4 :         struct spdk_lvol_store *lvs = lvol->lvol_store;
    2145           4 :         struct spdk_blob_store *bs = lvs->blobstore;
    2146             :         struct spdk_lvol *clone;
    2147             :         spdk_blob_id *ids;
    2148           4 :         size_t id_cnt = 0;
    2149             :         size_t i;
    2150             :         int rc;
    2151             : 
    2152           4 :         rc = spdk_blob_get_clones(bs, lvol->blob_id, NULL, &id_cnt);
    2153           4 :         if (rc != -ENOMEM) {
    2154             :                 /* -ENOMEM says id_cnt is valid, no other errors should be returned. */
    2155           1 :                 assert(rc == 0);
    2156           1 :                 return rc;
    2157             :         }
    2158             : 
    2159           3 :         ids = calloc(id_cnt, sizeof(*ids));
    2160           3 :         if (ids == NULL) {
    2161           0 :                 SPDK_ERRLOG("lvol %s: out of memory while iterating clones\n", lvol->unique_id);
    2162           0 :                 return -ENOMEM;
    2163             :         }
    2164             : 
    2165           3 :         rc = spdk_blob_get_clones(bs, lvol->blob_id, ids, &id_cnt);
    2166           3 :         if (rc != 0) {
    2167           0 :                 SPDK_ERRLOG("lvol %s: unable to get clone blob IDs: %d\n", lvol->unique_id, rc);
    2168           0 :                 free(ids);
    2169           0 :                 return rc;
    2170             :         }
    2171             : 
    2172           6 :         for (i = 0; i < id_cnt; i++) {
    2173           4 :                 clone = lvs_get_lvol_by_blob_id(lvs, ids[i]);
    2174           4 :                 if (clone == NULL) {
    2175           0 :                         SPDK_NOTICELOG("lvol %s: unable to find clone lvol with blob id 0x%"
    2176             :                                        PRIx64 "\n", lvol->unique_id, ids[i]);
    2177           0 :                         continue;
    2178             :                 }
    2179           4 :                 rc = cb_fn(cb_arg, clone);
    2180           4 :                 if (rc != 0) {
    2181           1 :                         SPDK_DEBUGLOG(lvol, "lvol %s: iteration stopped when lvol %s (blob 0x%"
    2182             :                                       PRIx64 ") returned %d\n", lvol->unique_id, clone->unique_id,
    2183             :                                       ids[i], rc);
    2184           1 :                         break;
    2185             :                 }
    2186           3 :         }
    2187             : 
    2188           3 :         free(ids);
    2189           3 :         return rc;
    2190           4 : }
    2191             : 
    2192             : struct spdk_lvol *
    2193           2 : spdk_lvol_get_by_uuid(const struct spdk_uuid *uuid)
    2194             : {
    2195             :         struct spdk_lvol_store *lvs;
    2196             :         struct spdk_lvol *lvol;
    2197             : 
    2198           2 :         pthread_mutex_lock(&g_lvol_stores_mutex);
    2199             : 
    2200           2 :         TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
    2201           2 :                 TAILQ_FOREACH(lvol, &lvs->lvols, link) {
    2202           2 :                         if (spdk_uuid_compare(uuid, &lvol->uuid) == 0) {
    2203           2 :                                 pthread_mutex_unlock(&g_lvol_stores_mutex);
    2204           2 :                                 return lvol;
    2205             :                         }
    2206           0 :                 }
    2207           0 :         }
    2208             : 
    2209           0 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
    2210           0 :         return NULL;
    2211           2 : }
    2212             : 
    2213             : struct spdk_lvol *
    2214          12 : spdk_lvol_get_by_names(const char *lvs_name, const char *lvol_name)
    2215             : {
    2216             :         struct spdk_lvol_store *lvs;
    2217             :         struct spdk_lvol *lvol;
    2218             : 
    2219          12 :         pthread_mutex_lock(&g_lvol_stores_mutex);
    2220             : 
    2221          17 :         TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
    2222          13 :                 if (strcmp(lvs_name, lvs->name) != 0) {
    2223           3 :                         continue;
    2224             :                 }
    2225          15 :                 TAILQ_FOREACH(lvol, &lvs->lvols, link) {
    2226          13 :                         if (strcmp(lvol_name, lvol->name) == 0) {
    2227           8 :                                 pthread_mutex_unlock(&g_lvol_stores_mutex);
    2228           8 :                                 return lvol;
    2229             :                         }
    2230           5 :                 }
    2231           2 :         }
    2232             : 
    2233           4 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
    2234           4 :         return NULL;
    2235          12 : }
    2236             : 
    2237             : bool
    2238           0 : spdk_lvol_is_degraded(const struct spdk_lvol *lvol)
    2239             : {
    2240           0 :         struct spdk_blob *blob = lvol->blob;
    2241             : 
    2242           0 :         if (blob == NULL) {
    2243           0 :                 return true;
    2244             :         }
    2245           0 :         return spdk_blob_is_degraded(blob);
    2246           0 : }
    2247             : 
    2248             : static void
    2249           1 : lvol_shallow_copy_cb(void *cb_arg, int lvolerrno)
    2250             : {
    2251           1 :         struct spdk_lvol_copy_req *req = cb_arg;
    2252           1 :         struct spdk_lvol *lvol = req->lvol;
    2253             : 
    2254           1 :         spdk_bs_free_io_channel(req->channel);
    2255             : 
    2256           1 :         if (lvolerrno < 0) {
    2257           0 :                 SPDK_ERRLOG("Could not make a shallow copy of lvol %s, error %d\n", lvol->unique_id, lvolerrno);
    2258           0 :         }
    2259             : 
    2260           1 :         req->cb_fn(req->cb_arg, lvolerrno);
    2261           1 :         free(req);
    2262           1 : }
    2263             : 
    2264             : int
    2265           3 : spdk_lvol_shallow_copy(struct spdk_lvol *lvol, struct spdk_bs_dev *ext_dev,
    2266             :                        spdk_blob_shallow_copy_status status_cb_fn, void *status_cb_arg,
    2267             :                        spdk_lvol_op_complete cb_fn, void *cb_arg)
    2268             : {
    2269             :         struct spdk_lvol_copy_req *req;
    2270             :         spdk_blob_id blob_id;
    2271             :         int rc;
    2272             : 
    2273           3 :         assert(cb_fn != NULL);
    2274             : 
    2275           3 :         if (lvol == NULL) {
    2276           1 :                 SPDK_ERRLOG("lvol must not be NULL\n");
    2277           1 :                 return -EINVAL;
    2278             :         }
    2279             : 
    2280           2 :         assert(lvol->lvol_store->thread == spdk_get_thread());
    2281             : 
    2282           2 :         if (ext_dev == NULL) {
    2283           1 :                 SPDK_ERRLOG("lvol %s shallow copy, ext_dev must not be NULL\n", lvol->unique_id);
    2284           1 :                 return -EINVAL;
    2285             :         }
    2286             : 
    2287           1 :         req = calloc(1, sizeof(*req));
    2288           1 :         if (!req) {
    2289           0 :                 SPDK_ERRLOG("lvol %s shallow copy, cannot alloc memory for lvol request\n", lvol->unique_id);
    2290           0 :                 return -ENOMEM;
    2291             :         }
    2292             : 
    2293           1 :         req->lvol = lvol;
    2294           1 :         req->cb_fn = cb_fn;
    2295           1 :         req->cb_arg = cb_arg;
    2296           1 :         req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    2297           1 :         if (req->channel == NULL) {
    2298           0 :                 SPDK_ERRLOG("lvol %s shallow copy, cannot alloc io channel for lvol request\n", lvol->unique_id);
    2299           0 :                 free(req);
    2300           0 :                 return -ENOMEM;
    2301             :         }
    2302             : 
    2303           1 :         blob_id = spdk_blob_get_id(lvol->blob);
    2304             : 
    2305           2 :         rc = spdk_bs_blob_shallow_copy(lvol->lvol_store->blobstore, req->channel, blob_id, ext_dev,
    2306           1 :                                        status_cb_fn, status_cb_arg, lvol_shallow_copy_cb, req);
    2307             : 
    2308           1 :         if (rc < 0) {
    2309           0 :                 SPDK_ERRLOG("Could not make a shallow copy of lvol %s\n", lvol->unique_id);
    2310           0 :                 spdk_bs_free_io_channel(req->channel);
    2311           0 :                 free(req);
    2312           0 :         }
    2313             : 
    2314           1 :         return rc;
    2315           3 : }
    2316             : 
    2317             : static void
    2318           1 : lvol_set_parent_cb(void *cb_arg, int lvolerrno)
    2319             : {
    2320           1 :         struct spdk_lvol_req *req = cb_arg;
    2321             : 
    2322           1 :         if (lvolerrno < 0) {
    2323           0 :                 SPDK_ERRLOG("could not set parent of lvol %s, error %d\n", req->lvol->name, lvolerrno);
    2324           0 :         }
    2325             : 
    2326           1 :         req->cb_fn(req->cb_arg, lvolerrno);
    2327           1 :         free(req);
    2328           1 : }
    2329             : 
    2330             : void
    2331           3 : spdk_lvol_set_parent(struct spdk_lvol *lvol, struct spdk_lvol *snapshot,
    2332             :                      spdk_lvol_op_complete cb_fn, void *cb_arg)
    2333             : {
    2334             :         struct spdk_lvol_req *req;
    2335             :         spdk_blob_id blob_id, snapshot_id;
    2336             : 
    2337           3 :         assert(cb_fn != NULL);
    2338             : 
    2339           3 :         if (lvol == NULL) {
    2340           1 :                 SPDK_ERRLOG("lvol must not be NULL\n");
    2341           1 :                 cb_fn(cb_arg, -EINVAL);
    2342           1 :                 return;
    2343             :         }
    2344             : 
    2345           2 :         if (snapshot == NULL) {
    2346           1 :                 SPDK_ERRLOG("snapshot must not be NULL\n");
    2347           1 :                 cb_fn(cb_arg, -EINVAL);
    2348           1 :                 return;
    2349             :         }
    2350             : 
    2351           1 :         req = calloc(1, sizeof(*req));
    2352           1 :         if (!req) {
    2353           0 :                 SPDK_ERRLOG("cannot alloc memory for lvol request pointer\n");
    2354           0 :                 cb_fn(cb_arg, -ENOMEM);
    2355           0 :                 return;
    2356             :         }
    2357             : 
    2358           1 :         req->lvol = lvol;
    2359           1 :         req->cb_fn = cb_fn;
    2360           1 :         req->cb_arg = cb_arg;
    2361             : 
    2362           1 :         blob_id = spdk_blob_get_id(lvol->blob);
    2363           1 :         snapshot_id = spdk_blob_get_id(snapshot->blob);
    2364             : 
    2365           2 :         spdk_bs_blob_set_parent(lvol->lvol_store->blobstore, blob_id, snapshot_id,
    2366           1 :                                 lvol_set_parent_cb, req);
    2367           3 : }
    2368             : 
    2369             : static void
    2370           1 : lvol_set_external_parent_cb(void *cb_arg, int lvolerrno)
    2371             : {
    2372           1 :         struct spdk_lvol_bs_dev_req *req = cb_arg;
    2373             : 
    2374           1 :         if (lvolerrno < 0) {
    2375           0 :                 SPDK_ERRLOG("could not set external parent of lvol %s, error %d\n", req->lvol->name, lvolerrno);
    2376           0 :                 req->bs_dev->destroy(req->bs_dev);
    2377           0 :         }
    2378             : 
    2379           1 :         req->cb_fn(req->cb_arg, lvolerrno);
    2380           1 :         free(req);
    2381           1 : }
    2382             : 
    2383             : void
    2384           4 : spdk_lvol_set_external_parent(struct spdk_lvol *lvol, const void *esnap_id, uint32_t esnap_id_len,
    2385             :                               spdk_lvol_op_complete cb_fn, void *cb_arg)
    2386             : {
    2387             :         struct spdk_lvol_bs_dev_req *req;
    2388             :         struct spdk_bs_dev *bs_dev;
    2389             :         spdk_blob_id blob_id;
    2390             :         int rc;
    2391             : 
    2392           4 :         assert(cb_fn != NULL);
    2393             : 
    2394           4 :         if (lvol == NULL) {
    2395           1 :                 SPDK_ERRLOG("lvol must not be NULL\n");
    2396           1 :                 cb_fn(cb_arg, -EINVAL);
    2397           1 :                 return;
    2398             :         }
    2399             : 
    2400           3 :         if (esnap_id == NULL) {
    2401           1 :                 SPDK_ERRLOG("snapshot must not be NULL\n");
    2402           1 :                 cb_fn(cb_arg, -EINVAL);
    2403           1 :                 return;
    2404             :         }
    2405             : 
    2406           2 :         if (esnap_id_len == sizeof(lvol->uuid_str) &&
    2407           2 :             memcmp(esnap_id, lvol->uuid_str, esnap_id_len) == 0) {
    2408           1 :                 SPDK_ERRLOG("lvol %s and esnap have the same UUID\n", lvol->name);
    2409           1 :                 cb_fn(cb_arg, -EINVAL);
    2410           1 :                 return;
    2411             :         }
    2412             : 
    2413           1 :         rc = lvs_esnap_bs_dev_create(lvol->lvol_store, lvol, lvol->blob, esnap_id, esnap_id_len, &bs_dev);
    2414           1 :         if (rc < 0) {
    2415           0 :                 cb_fn(cb_arg, rc);
    2416           0 :                 return;
    2417             :         }
    2418             : 
    2419           1 :         req = calloc(1, sizeof(*req));
    2420           1 :         if (!req) {
    2421           0 :                 SPDK_ERRLOG("cannot alloc memory for lvol request pointer\n");
    2422           0 :                 cb_fn(cb_arg, -ENOMEM);
    2423           0 :                 return;
    2424             :         }
    2425             : 
    2426           1 :         req->lvol = lvol;
    2427           1 :         req->bs_dev = bs_dev;
    2428           1 :         req->cb_fn = cb_fn;
    2429           1 :         req->cb_arg = cb_arg;
    2430             : 
    2431           1 :         blob_id = spdk_blob_get_id(lvol->blob);
    2432             : 
    2433           2 :         spdk_bs_blob_set_external_parent(lvol->lvol_store->blobstore, blob_id, bs_dev, esnap_id,
    2434           1 :                                          esnap_id_len, lvol_set_external_parent_cb, req);
    2435           4 : }

Generated by: LCOV version 1.15