LCOV - code coverage report
Current view: top level - lib/lvol - lvol.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 1028 1310 78.5 %
Date: 2024-11-05 10:06:02 Functions: 86 97 88.7 %

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

Generated by: LCOV version 1.15