LCOV - code coverage report
Current view: top level - spdk/lib/lvol - lvol.c (source / functions) Hit Total Coverage
Test: Combined Lines: 985 1206 81.7 %
Date: 2024-07-12 17:08:57 Functions: 85 91 93.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 458 724 63.3 %

           Branch data     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                 :       2066 : 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                 :        589 : add_lvs_to_list(struct spdk_lvol_store *lvs)
      45                 :            : {
      46                 :            :         struct spdk_lvol_store *tmp;
      47                 :        589 :         bool name_conflict = false;
      48                 :            : 
      49                 :        589 :         pthread_mutex_lock(&g_lvol_stores_mutex);
      50         [ +  + ]:        740 :         TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
      51   [ +  +  -  +  :        164 :                 if (!strncmp(lvs->name, tmp->name, SPDK_LVS_NAME_MAX)) {
                   +  + ]
      52                 :         13 :                         name_conflict = true;
      53                 :         13 :                         break;
      54                 :            :                 }
      55                 :            :         }
      56         [ +  + ]:        589 :         if (!name_conflict) {
      57                 :        576 :                 lvs->on_list = true;
      58                 :        576 :                 TAILQ_INSERT_TAIL(&g_lvol_stores, lvs, link);
      59                 :            :         }
      60                 :        589 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
      61                 :            : 
      62         [ +  + ]:        589 :         return name_conflict ? -1 : 0;
      63                 :            : }
      64                 :            : 
      65                 :            : static struct spdk_lvol_store *
      66                 :       6406 : lvs_alloc(void)
      67                 :            : {
      68                 :            :         struct spdk_lvol_store *lvs;
      69                 :            : 
      70                 :       6406 :         lvs = calloc(1, sizeof(*lvs));
      71         [ -  + ]:       6406 :         if (lvs == NULL) {
      72                 :          0 :                 return NULL;
      73                 :            :         }
      74                 :            : 
      75                 :       6406 :         TAILQ_INIT(&lvs->lvols);
      76                 :       6406 :         TAILQ_INIT(&lvs->pending_lvols);
      77                 :       6406 :         TAILQ_INIT(&lvs->retry_open_lvols);
      78                 :            : 
      79                 :       6406 :         lvs->load_esnaps = false;
      80                 :       6406 :         RB_INIT(&lvs->degraded_lvol_sets_tree);
      81                 :       6406 :         lvs->thread = spdk_get_thread();
      82                 :            : 
      83                 :       6406 :         return lvs;
      84                 :            : }
      85                 :            : 
      86                 :            : static void
      87                 :       6406 : lvs_free(struct spdk_lvol_store *lvs)
      88                 :            : {
      89         [ -  + ]:       6406 :         pthread_mutex_lock(&g_lvol_stores_mutex);
      90   [ +  +  +  + ]:       6406 :         if (lvs->on_list) {
      91         [ +  + ]:        576 :                 TAILQ_REMOVE(&g_lvol_stores, lvs, link);
      92                 :            :         }
      93         [ -  + ]:       6406 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
      94                 :            : 
      95         [ -  + ]:       6406 :         assert(RB_EMPTY(&lvs->degraded_lvol_sets_tree));
      96                 :            : 
      97                 :       6406 :         free(lvs);
      98                 :       6406 : }
      99                 :            : 
     100                 :            : static struct spdk_lvol *
     101                 :        959 : 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                 :        959 :         lvol = calloc(1, sizeof(*lvol));
     107         [ -  + ]:        959 :         if (lvol == NULL) {
     108                 :          0 :                 return NULL;
     109                 :            :         }
     110                 :            : 
     111                 :        959 :         lvol->lvol_store = lvs;
     112                 :        959 :         lvol->clear_method = (enum blob_clear_method)clear_method;
     113         [ -  + ]:        959 :         snprintf(lvol->name, sizeof(lvol->name), "%s", name);
     114                 :        959 :         spdk_uuid_generate(&lvol->uuid);
     115                 :        959 :         spdk_uuid_fmt_lower(lvol->uuid_str, sizeof(lvol->uuid_str), &lvol->uuid);
     116                 :        959 :         spdk_uuid_fmt_lower(lvol->unique_id, sizeof(lvol->uuid_str), &lvol->uuid);
     117                 :            : 
     118                 :        959 :         TAILQ_INSERT_TAIL(&lvs->pending_lvols, lvol, link);
     119                 :            : 
     120                 :        959 :         return lvol;
     121                 :            : }
     122                 :            : 
     123                 :            : static void
     124                 :       1093 : lvol_free(struct spdk_lvol *lvol)
     125                 :            : {
     126                 :       1093 :         free(lvol);
     127                 :       1093 : }
     128                 :            : 
     129                 :            : static void
     130                 :        128 : lvol_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     131                 :            : {
     132                 :        128 :         struct spdk_lvol_with_handle_req *req = cb_arg;
     133                 :        128 :         struct spdk_lvol *lvol = req->lvol;
     134                 :            : 
     135         [ +  + ]:        128 :         if (lvolerrno != 0) {
     136   [ -  +  -  + ]:         18 :                 SPDK_INFOLOG(lvol, "Failed to open lvol %s\n", lvol->unique_id);
     137                 :         18 :                 goto end;
     138                 :            :         }
     139                 :            : 
     140                 :        110 :         lvol->ref_count++;
     141                 :        110 :         lvol->blob = blob;
     142                 :        128 : end:
     143                 :        128 :         req->cb_fn(req->cb_arg, lvol, lvolerrno);
     144                 :        128 :         free(req);
     145                 :        128 : }
     146                 :            : 
     147                 :            : void
     148                 :        134 : 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                 :        113 :         struct spdk_blob_open_opts opts;
     152                 :            : 
     153         [ -  + ]:        134 :         assert(cb_fn != NULL);
     154                 :            : 
     155         [ -  + ]:        134 :         if (lvol == NULL) {
     156                 :          0 :                 SPDK_ERRLOG("lvol does not exist\n");
     157                 :          0 :                 cb_fn(cb_arg, NULL, -ENODEV);
     158                 :          1 :                 return;
     159                 :            :         }
     160                 :            : 
     161   [ -  +  -  + ]:        134 :         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         [ +  + ]:        134 :         if (lvol->ref_count > 0) {
     168                 :          6 :                 lvol->ref_count++;
     169                 :          6 :                 cb_fn(cb_arg, lvol, 0);
     170                 :          6 :                 return;
     171                 :            :         }
     172                 :            : 
     173                 :        128 :         req = calloc(1, sizeof(*req));
     174         [ -  + ]:        128 :         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                 :        128 :         req->cb_fn = cb_fn;
     181                 :        128 :         req->cb_arg = cb_arg;
     182                 :        128 :         req->lvol = lvol;
     183                 :            : 
     184                 :        128 :         spdk_blob_open_opts_init(&opts, sizeof(opts));
     185                 :        128 :         opts.clear_method = lvol->clear_method;
     186                 :            : 
     187                 :        128 :         spdk_bs_open_blob_ext(lvol->lvol_store->blobstore, lvol->blob_id, &opts, lvol_open_cb, req);
     188                 :            : }
     189                 :            : 
     190                 :            : static void
     191                 :         48 : bs_unload_with_error_cb(void *cb_arg, int lvolerrno)
     192                 :            : {
     193                 :         48 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     194                 :            : 
     195                 :         48 :         req->cb_fn(req->cb_arg, NULL, req->lvserrno);
     196                 :         48 :         free(req);
     197                 :         48 : }
     198                 :            : 
     199                 :            : static void
     200                 :        392 : load_next_lvol(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     201                 :            : {
     202                 :        392 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     203                 :        392 :         struct spdk_lvol_store *lvs = req->lvol_store;
     204                 :        392 :         struct spdk_blob_store *bs = lvs->blobstore;
     205                 :            :         struct spdk_lvol *lvol, *tmp;
     206                 :            :         spdk_blob_id blob_id;
     207                 :        324 :         const char *attr;
     208                 :        324 :         size_t value_len;
     209                 :            :         int rc;
     210                 :            : 
     211         [ +  + ]:        392 :         if (lvolerrno == -ENOENT) {
     212                 :            :                 /* Finished iterating */
     213         [ +  + ]:        114 :                 if (req->lvserrno == 0) {
     214                 :        102 :                         lvs->load_esnaps = true;
     215                 :        102 :                         req->cb_fn(req->cb_arg, lvs, req->lvserrno);
     216                 :        102 :                         free(req);
     217                 :            :                 } else {
     218         [ +  + ]:         36 :                         TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
     219         [ +  + ]:         24 :                                 TAILQ_REMOVE(&lvs->lvols, lvol, link);
     220                 :         24 :                                 lvol_free(lvol);
     221                 :            :                         }
     222                 :         12 :                         lvs_free(lvs);
     223                 :         12 :                         spdk_bs_unload(bs, bs_unload_with_error_cb, req);
     224                 :            :                 }
     225                 :        135 :                 return;
     226         [ +  + ]:        278 :         } else if (lvolerrno < 0) {
     227                 :         12 :                 SPDK_ERRLOG("Failed to fetch blobs list\n");
     228                 :         12 :                 req->lvserrno = lvolerrno;
     229                 :         12 :                 goto invalid;
     230                 :            :         }
     231                 :            : 
     232                 :        266 :         blob_id = spdk_blob_get_id(blob);
     233                 :            : 
     234         [ +  + ]:        266 :         if (blob_id == lvs->super_blob_id) {
     235   [ -  +  -  + ]:        114 :                 SPDK_INFOLOG(lvol, "found superblob %"PRIu64"\n", (uint64_t)blob_id);
     236                 :        114 :                 spdk_bs_iter_next(bs, blob, load_next_lvol, req);
     237                 :        114 :                 return;
     238                 :            :         }
     239                 :            : 
     240                 :        152 :         lvol = calloc(1, sizeof(*lvol));
     241         [ -  + ]:        152 :         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                 :        152 :         lvol->blob_id = blob_id;
     252                 :        152 :         lvol->lvol_store = lvs;
     253                 :            : 
     254                 :        152 :         rc = spdk_blob_get_xattr_value(blob, "uuid", (const void **)&attr, &value_len);
     255   [ +  -  +  -  :        304 :         if (rc != 0 || value_len != SPDK_UUID_STRING_LEN || attr[SPDK_UUID_STRING_LEN - 1] != '\0' ||
             +  -  -  + ]
     256                 :        152 :             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                 :        152 :         spdk_uuid_fmt_lower(lvol->uuid_str, sizeof(lvol->uuid_str), &lvol->uuid);
     261                 :            : 
     262         [ +  - ]:        152 :         if (!spdk_uuid_is_null(&lvol->uuid)) {
     263                 :        152 :                 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                 :        152 :         rc = spdk_blob_get_xattr_value(blob, "name", (const void **)&attr, &value_len);
     272   [ +  -  -  + ]:        152 :         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                 :        152 :         snprintf(lvol->name, sizeof(lvol->name), "%s", attr);
     280                 :            : 
     281                 :        152 :         TAILQ_INSERT_TAIL(&lvs->lvols, lvol, link);
     282                 :            : 
     283                 :        152 :         lvs->lvol_count++;
     284                 :            : 
     285   [ +  +  +  - ]:        152 :         SPDK_INFOLOG(lvol, "added lvol %s (%s)\n", lvol->unique_id, lvol->uuid_str);
     286                 :            : 
     287                 :        162 : invalid:
     288                 :        164 :         spdk_bs_iter_next(bs, blob, load_next_lvol, req);
     289                 :            : }
     290                 :            : 
     291                 :            : static void
     292                 :        120 : close_super_cb(void *cb_arg, int lvolerrno)
     293                 :            : {
     294                 :        120 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     295                 :        120 :         struct spdk_lvol_store *lvs = req->lvol_store;
     296                 :        120 :         struct spdk_blob_store *bs = lvs->blobstore;
     297                 :            : 
     298         [ +  + ]:        120 :         if (lvolerrno != 0) {
     299   [ -  +  -  + ]:          6 :                 SPDK_INFOLOG(lvol, "Could not close super blob\n");
     300                 :          6 :                 lvs_free(lvs);
     301                 :          6 :                 req->lvserrno = -ENODEV;
     302                 :          6 :                 spdk_bs_unload(bs, bs_unload_with_error_cb, req);
     303                 :          6 :                 return;
     304                 :            :         }
     305                 :            : 
     306                 :            :         /* Start loading lvols */
     307                 :        114 :         spdk_bs_iter_first(lvs->blobstore, load_next_lvol, req);
     308                 :            : }
     309                 :            : 
     310                 :            : static void
     311                 :         18 : close_super_blob_with_error_cb(void *cb_arg, int lvolerrno)
     312                 :            : {
     313                 :         18 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     314                 :         18 :         struct spdk_lvol_store *lvs = req->lvol_store;
     315                 :         18 :         struct spdk_blob_store *bs = lvs->blobstore;
     316                 :            : 
     317                 :         18 :         lvs_free(lvs);
     318                 :            : 
     319                 :         18 :         spdk_bs_unload(bs, bs_unload_with_error_cb, req);
     320                 :         18 : }
     321                 :            : 
     322                 :            : static void
     323                 :        144 : lvs_read_uuid(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     324                 :            : {
     325                 :        144 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     326                 :        144 :         struct spdk_lvol_store *lvs = req->lvol_store;
     327                 :        144 :         struct spdk_blob_store *bs = lvs->blobstore;
     328                 :        118 :         const char *attr;
     329                 :        118 :         size_t value_len;
     330                 :            :         int rc;
     331                 :            : 
     332         [ +  + ]:        144 :         if (lvolerrno != 0) {
     333   [ -  +  -  + ]:          6 :                 SPDK_INFOLOG(lvol, "Could not open super blob\n");
     334                 :          6 :                 lvs_free(lvs);
     335                 :          6 :                 req->lvserrno = -ENODEV;
     336                 :          6 :                 spdk_bs_unload(bs, bs_unload_with_error_cb, req);
     337                 :          9 :                 return;
     338                 :            :         }
     339                 :            : 
     340                 :        138 :         rc = spdk_blob_get_xattr_value(blob, "uuid", (const void **)&attr, &value_len);
     341   [ +  +  +  -  :        138 :         if (rc != 0 || value_len != SPDK_UUID_STRING_LEN || attr[SPDK_UUID_STRING_LEN - 1] != '\0') {
                   -  + ]
     342   [ -  +  -  + ]:          6 :                 SPDK_INFOLOG(lvol, "degraded_set or incorrect UUID\n");
     343                 :          6 :                 req->lvserrno = -EINVAL;
     344                 :          6 :                 spdk_blob_close(blob, close_super_blob_with_error_cb, req);
     345                 :          6 :                 return;
     346                 :            :         }
     347                 :            : 
     348         [ -  + ]:        132 :         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                 :        132 :         rc = spdk_blob_get_xattr_value(blob, "name", (const void **)&attr, &value_len);
     356   [ +  +  -  + ]:        132 :         if (rc != 0 || value_len > SPDK_LVS_NAME_MAX) {
     357   [ -  +  -  + ]:          6 :                 SPDK_INFOLOG(lvol, "degraded_set or invalid name\n");
     358                 :          6 :                 req->lvserrno = -EINVAL;
     359                 :          6 :                 spdk_blob_close(blob, close_super_blob_with_error_cb, req);
     360                 :          6 :                 return;
     361                 :            :         }
     362                 :            : 
     363         [ -  + ]:        126 :         snprintf(lvs->name, sizeof(lvs->name), "%s", attr);
     364                 :            : 
     365                 :        126 :         rc = add_lvs_to_list(lvs);
     366         [ +  + ]:        126 :         if (rc) {
     367   [ -  +  -  + ]:          6 :                 SPDK_INFOLOG(lvol, "lvolstore with name %s already exists\n", lvs->name);
     368                 :          6 :                 req->lvserrno = -EEXIST;
     369                 :          6 :                 spdk_blob_close(blob, close_super_blob_with_error_cb, req);
     370                 :          6 :                 return;
     371                 :            :         }
     372                 :            : 
     373                 :        120 :         lvs->super_blob_id = spdk_blob_get_id(blob);
     374                 :            : 
     375                 :        120 :         spdk_blob_close(blob, close_super_cb, req);
     376                 :            : }
     377                 :            : 
     378                 :            : static void
     379                 :        150 : lvs_open_super(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
     380                 :            : {
     381                 :        150 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     382                 :        150 :         struct spdk_lvol_store *lvs = req->lvol_store;
     383                 :        150 :         struct spdk_blob_store *bs = lvs->blobstore;
     384                 :            : 
     385         [ +  + ]:        150 :         if (lvolerrno != 0) {
     386   [ -  +  -  + ]:          6 :                 SPDK_INFOLOG(lvol, "Super blob not found\n");
     387                 :          6 :                 lvs_free(lvs);
     388                 :          6 :                 req->lvserrno = -ENODEV;
     389                 :          6 :                 spdk_bs_unload(bs, bs_unload_with_error_cb, req);
     390                 :          6 :                 return;
     391                 :            :         }
     392                 :            : 
     393                 :        144 :         spdk_bs_open_blob(bs, blobid, lvs_read_uuid, req);
     394                 :            : }
     395                 :            : 
     396                 :            : static void
     397                 :       5925 : lvs_load_cb(void *cb_arg, struct spdk_blob_store *bs, int lvolerrno)
     398                 :            : {
     399                 :       5925 :         struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg;
     400                 :       5925 :         struct spdk_lvol_store *lvs = req->lvol_store;
     401                 :            : 
     402         [ +  + ]:       5925 :         if (lvolerrno != 0) {
     403                 :       5775 :                 req->cb_fn(req->cb_arg, NULL, lvolerrno);
     404                 :       5775 :                 lvs_free(lvs);
     405                 :       5775 :                 free(req);
     406                 :       5775 :                 return;
     407                 :            :         }
     408                 :            : 
     409                 :        150 :         lvs->blobstore = bs;
     410                 :        150 :         lvs->bs_dev = req->bs_dev;
     411                 :            : 
     412                 :        150 :         spdk_bs_get_super(bs, lvs_open_super, req);
     413                 :            : }
     414                 :            : 
     415                 :            : static void
     416                 :       6400 : lvs_bs_opts_init(struct spdk_bs_opts *opts)
     417                 :            : {
     418                 :       6400 :         spdk_bs_opts_init(opts, sizeof(*opts));
     419                 :       6400 :         opts->max_channel_ops = SPDK_LVOL_BLOB_OPTS_CHANNEL_OPS;
     420                 :       6400 : }
     421                 :            : 
     422                 :            : static void
     423                 :       5931 : 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                 :       5931 :         struct spdk_bs_opts bs_opts = {};
     428                 :       3509 :         struct spdk_lvs_opts lvs_opts;
     429                 :            : 
     430         [ -  + ]:       5931 :         assert(cb_fn != NULL);
     431                 :            : 
     432         [ -  + ]:       5931 :         if (bs_dev == NULL) {
     433                 :          0 :                 SPDK_ERRLOG("Blobstore device does not exist\n");
     434                 :          0 :                 cb_fn(cb_arg, NULL, -ENODEV);
     435                 :          1 :                 return;
     436                 :            :         }
     437                 :            : 
     438                 :       5931 :         spdk_lvs_opts_init(&lvs_opts);
     439         [ +  + ]:       5931 :         if (_lvs_opts != NULL) {
     440         [ +  + ]:       5847 :                 if (lvs_opts_copy(_lvs_opts, &lvs_opts) != 0) {
     441                 :          6 :                         SPDK_ERRLOG("Invalid options\n");
     442                 :          6 :                         cb_fn(cb_arg, NULL, -EINVAL);
     443                 :          6 :                         return;
     444                 :            :                 }
     445                 :            :         }
     446                 :            : 
     447                 :       5925 :         req = calloc(1, sizeof(*req));
     448         [ -  + ]:       5925 :         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                 :       5925 :         req->lvol_store = lvs_alloc();
     455         [ -  + ]:       5925 :         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                 :       5925 :         req->cb_fn = cb_fn;
     462                 :       5925 :         req->cb_arg = cb_arg;
     463                 :       5925 :         req->bs_dev = bs_dev;
     464                 :            : 
     465                 :       5925 :         lvs_bs_opts_init(&bs_opts);
     466         [ -  + ]:       5925 :         snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "LVOLSTORE");
     467                 :            : 
     468         [ +  + ]:       5925 :         if (lvs_opts.esnap_bs_dev_create != NULL) {
     469                 :       5841 :                 req->lvol_store->esnap_bs_dev_create = lvs_opts.esnap_bs_dev_create;
     470                 :       5841 :                 bs_opts.esnap_bs_dev_create = lvs_esnap_bs_dev_create;
     471                 :       5841 :                 bs_opts.esnap_ctx = req->lvol_store;
     472                 :            :         }
     473                 :            : 
     474                 :       5925 :         spdk_bs_load(bs_dev, &bs_opts, lvs_load_cb, req);
     475                 :            : }
     476                 :            : 
     477                 :            : void
     478                 :         84 : spdk_lvs_load(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg)
     479                 :            : {
     480                 :         84 :         lvs_load(bs_dev, NULL, cb_fn, cb_arg);
     481                 :         84 : }
     482                 :            : 
     483                 :            : void
     484                 :       5847 : 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                 :       5847 :         lvs_load(bs_dev, opts, cb_fn, cb_arg);
     488                 :       5847 : }
     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                 :        455 : super_create_close_cb(void *cb_arg, int lvolerrno)
     506                 :            : {
     507                 :        455 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     508                 :        455 :         struct spdk_lvol_store *lvs = req->lvol_store;
     509                 :            : 
     510         [ -  + ]:        455 :         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                 :        455 :         req->cb_fn(req->cb_arg, lvs, lvolerrno);
     517                 :        455 :         free(req);
     518                 :            : }
     519                 :            : 
     520                 :            : static void
     521                 :        455 : super_blob_set_cb(void *cb_arg, int lvolerrno)
     522                 :            : {
     523                 :        455 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     524                 :        455 :         struct spdk_lvol_store *lvs = req->lvol_store;
     525                 :        455 :         struct spdk_blob *blob = lvs->super_blob;
     526                 :            : 
     527         [ -  + ]:        455 :         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                 :        455 :         spdk_blob_close(blob, super_create_close_cb, req);
     534                 :            : }
     535                 :            : 
     536                 :            : static void
     537                 :        455 : super_blob_init_cb(void *cb_arg, int lvolerrno)
     538                 :            : {
     539                 :        455 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     540                 :        455 :         struct spdk_lvol_store *lvs = req->lvol_store;
     541                 :        455 :         struct spdk_blob *blob = lvs->super_blob;
     542                 :        337 :         char uuid[SPDK_UUID_STRING_LEN];
     543                 :            : 
     544         [ -  + ]:        455 :         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                 :        455 :         spdk_uuid_fmt_lower(uuid, sizeof(uuid), &lvs->uuid);
     551                 :            : 
     552                 :        455 :         spdk_blob_set_xattr(blob, "uuid", uuid, sizeof(uuid));
     553         [ -  + ]:        455 :         spdk_blob_set_xattr(blob, "name", lvs->name, strnlen(lvs->name, SPDK_LVS_NAME_MAX) + 1);
     554                 :        455 :         spdk_blob_sync_md(blob, super_blob_set_cb, req);
     555                 :            : }
     556                 :            : 
     557                 :            : static void
     558                 :        455 : super_blob_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     559                 :            : {
     560                 :        455 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     561                 :        455 :         struct spdk_lvol_store *lvs = req->lvol_store;
     562                 :            : 
     563         [ -  + ]:        455 :         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                 :        455 :         lvs->super_blob = blob;
     570                 :        455 :         lvs->super_blob_id = spdk_blob_get_id(blob);
     571                 :            : 
     572                 :        455 :         spdk_bs_set_super(lvs->blobstore, lvs->super_blob_id, super_blob_init_cb, req);
     573                 :            : }
     574                 :            : 
     575                 :            : static void
     576                 :        455 : super_blob_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
     577                 :            : {
     578                 :        455 :         struct spdk_lvs_with_handle_req *req = cb_arg;
     579                 :        455 :         struct spdk_lvol_store *lvs = req->lvol_store;
     580                 :            :         struct spdk_blob_store *bs;
     581                 :            : 
     582         [ -  + ]:        455 :         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                 :        455 :         bs = req->lvol_store->blobstore;
     589                 :            : 
     590                 :        455 :         spdk_bs_open_blob(bs, blobid, super_blob_create_open_cb, req);
     591                 :            : }
     592                 :            : 
     593                 :            : static void
     594                 :        456 : lvs_init_cb(void *cb_arg, struct spdk_blob_store *bs, int lvserrno)
     595                 :            : {
     596                 :        456 :         struct spdk_lvs_with_handle_req *lvs_req = cb_arg;
     597                 :        456 :         struct spdk_lvol_store *lvs = lvs_req->lvol_store;
     598                 :            : 
     599         [ +  + ]:        456 :         if (lvserrno != 0) {
     600         [ -  + ]:          1 :                 assert(bs == NULL);
     601                 :          1 :                 lvs_req->cb_fn(lvs_req->cb_arg, NULL, lvserrno);
     602                 :          1 :                 SPDK_ERRLOG("Lvol store init failed: could not initialize blobstore\n");
     603                 :          1 :                 lvs_free(lvs);
     604                 :          1 :                 free(lvs_req);
     605                 :          1 :                 return;
     606                 :            :         }
     607                 :            : 
     608         [ -  + ]:        455 :         assert(bs != NULL);
     609                 :        455 :         lvs->blobstore = bs;
     610                 :            : 
     611   [ -  +  -  + ]:        455 :         SPDK_INFOLOG(lvol, "Lvol store initialized\n");
     612                 :            : 
     613                 :            :         /* create super blob */
     614                 :        455 :         spdk_bs_create_blob(lvs->blobstore, super_blob_create_cb, lvs_req);
     615                 :            : }
     616                 :            : 
     617                 :            : void
     618                 :      12708 : spdk_lvs_opts_init(struct spdk_lvs_opts *o)
     619                 :            : {
     620         [ -  + ]:      12708 :         memset(o, 0, sizeof(*o));
     621                 :      12708 :         o->cluster_sz = SPDK_LVS_OPTS_CLUSTER_SZ;
     622                 :      12708 :         o->clear_method = LVS_CLEAR_WITH_UNMAP;
     623                 :      12708 :         o->num_md_pages_per_cluster_ratio = 100;
     624                 :      12708 :         o->opts_size = sizeof(*o);
     625                 :      12708 : }
     626                 :            : 
     627                 :            : static inline int
     628                 :       6323 : lvs_opts_copy(const struct spdk_lvs_opts *src, struct spdk_lvs_opts *dst)
     629                 :            : {
     630         [ +  + ]:       6323 :         if (src->opts_size == 0) {
     631                 :          6 :                 SPDK_ERRLOG("opts_size should not be zero value\n");
     632                 :          6 :                 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         [ +  - ]:       6317 :         SET_FIELD(cluster_sz);
     643         [ +  - ]:       6317 :         SET_FIELD(clear_method);
     644         [ +  - ]:       6317 :         if (FIELD_OK(name)) {
     645   [ -  +  -  + ]:       6317 :                 memcpy(&dst->name, &src->name, sizeof(dst->name));
     646                 :            :         }
     647         [ +  - ]:       6317 :         SET_FIELD(num_md_pages_per_cluster_ratio);
     648         [ +  - ]:       6317 :         SET_FIELD(opts_size);
     649         [ +  - ]:       6317 :         SET_FIELD(esnap_bs_dev_create);
     650                 :            : 
     651                 :       6317 :         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                 :       6317 :         return 0;
     661                 :            : }
     662                 :            : 
     663                 :            : static void
     664                 :        475 : setup_lvs_opts(struct spdk_bs_opts *bs_opts, struct spdk_lvs_opts *o, uint32_t total_clusters,
     665                 :            :                void *esnap_ctx)
     666                 :            : {
     667         [ -  + ]:        475 :         assert(o != NULL);
     668                 :        475 :         lvs_bs_opts_init(bs_opts);
     669                 :        475 :         bs_opts->cluster_sz = o->cluster_sz;
     670                 :        475 :         bs_opts->clear_method = (enum bs_clear_method)o->clear_method;
     671                 :        475 :         bs_opts->num_md_pages = (o->num_md_pages_per_cluster_ratio * total_clusters) / 100;
     672                 :        475 :         bs_opts->esnap_bs_dev_create = o->esnap_bs_dev_create;
     673                 :        475 :         bs_opts->esnap_ctx = esnap_ctx;
     674         [ -  + ]:        475 :         snprintf(bs_opts->bstype.bstype, sizeof(bs_opts->bstype.bstype), "LVOLSTORE");
     675                 :        475 : }
     676                 :            : 
     677                 :            : int
     678                 :        482 : 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                 :        482 :         struct spdk_bs_opts opts = {};
     684                 :        360 :         struct spdk_lvs_opts lvs_opts;
     685                 :            :         uint32_t total_clusters;
     686                 :            :         int rc;
     687                 :            : 
     688         [ +  + ]:        482 :         if (bs_dev == NULL) {
     689                 :          6 :                 SPDK_ERRLOG("Blobstore device does not exist\n");
     690                 :          6 :                 return -ENODEV;
     691                 :            :         }
     692                 :            : 
     693         [ -  + ]:        476 :         if (o == NULL) {
     694                 :          0 :                 SPDK_ERRLOG("spdk_lvs_opts not specified\n");
     695                 :          0 :                 return -EINVAL;
     696                 :            :         }
     697                 :            : 
     698                 :        476 :         spdk_lvs_opts_init(&lvs_opts);
     699         [ -  + ]:        476 :         if (lvs_opts_copy(o, &lvs_opts) != 0) {
     700                 :          0 :                 SPDK_ERRLOG("spdk_lvs_opts invalid\n");
     701                 :          0 :                 return -EINVAL;
     702                 :            :         }
     703                 :            : 
     704         [ +  + ]:        476 :         if (lvs_opts.cluster_sz < bs_dev->blocklen) {
     705                 :          1 :                 SPDK_ERRLOG("Cluster size %" PRIu32 " is smaller than blocklen %" PRIu32 "\n",
     706                 :            :                             lvs_opts.cluster_sz, bs_dev->blocklen);
     707                 :          1 :                 return -EINVAL;
     708                 :            :         }
     709   [ -  +  -  + ]:        475 :         total_clusters = bs_dev->blockcnt / (lvs_opts.cluster_sz / bs_dev->blocklen);
     710                 :            : 
     711                 :        475 :         lvs = lvs_alloc();
     712         [ -  + ]:        475 :         if (!lvs) {
     713                 :          0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store base pointer\n");
     714                 :          0 :                 return -ENOMEM;
     715                 :            :         }
     716                 :            : 
     717                 :        475 :         setup_lvs_opts(&opts, o, total_clusters, lvs);
     718                 :            : 
     719         [ +  + ]:        475 :         if (strnlen(lvs_opts.name, SPDK_LVS_NAME_MAX) == SPDK_LVS_NAME_MAX) {
     720                 :          6 :                 SPDK_ERRLOG("Name has no null terminator.\n");
     721                 :          6 :                 lvs_free(lvs);
     722                 :          6 :                 return -EINVAL;
     723                 :            :         }
     724                 :            : 
     725         [ +  + ]:        469 :         if (strnlen(lvs_opts.name, SPDK_LVS_NAME_MAX) == 0) {
     726                 :          6 :                 SPDK_ERRLOG("No name specified.\n");
     727                 :          6 :                 lvs_free(lvs);
     728                 :          6 :                 return -EINVAL;
     729                 :            :         }
     730                 :            : 
     731                 :        463 :         spdk_uuid_generate(&lvs->uuid);
     732                 :        463 :         snprintf(lvs->name, sizeof(lvs->name), "%s", lvs_opts.name);
     733                 :            : 
     734                 :        463 :         rc = add_lvs_to_list(lvs);
     735         [ +  + ]:        463 :         if (rc) {
     736                 :          7 :                 SPDK_ERRLOG("lvolstore with name %s already exists\n", lvs->name);
     737                 :          7 :                 lvs_free(lvs);
     738                 :          7 :                 return -EEXIST;
     739                 :            :         }
     740                 :            : 
     741                 :        456 :         lvs_req = calloc(1, sizeof(*lvs_req));
     742         [ -  + ]:        456 :         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         [ -  + ]:        456 :         assert(cb_fn != NULL);
     749                 :        456 :         lvs_req->cb_fn = cb_fn;
     750                 :        456 :         lvs_req->cb_arg = cb_arg;
     751                 :        456 :         lvs_req->lvol_store = lvs;
     752                 :        456 :         lvs->bs_dev = bs_dev;
     753                 :            : 
     754   [ -  +  -  + ]:        456 :         SPDK_INFOLOG(lvol, "Initializing lvol store\n");
     755                 :        456 :         spdk_bs_init(bs_dev, &opts, lvs_init_cb, lvs_req);
     756                 :            : 
     757                 :        456 :         return 0;
     758                 :            : }
     759                 :            : 
     760                 :            : static void
     761                 :         13 : lvs_rename_cb(void *cb_arg, int lvolerrno)
     762                 :            : {
     763                 :         13 :         struct spdk_lvs_req *req = cb_arg;
     764                 :            : 
     765         [ +  + ]:         13 :         if (lvolerrno != 0) {
     766                 :          6 :                 req->lvserrno = lvolerrno;
     767                 :            :         }
     768         [ +  + ]:         13 :         if (req->lvserrno != 0) {
     769                 :          6 :                 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         [ -  + ]:          6 :                 snprintf(req->lvol_store->new_name,
     773                 :            :                          sizeof(req->lvol_store->new_name),
     774                 :          6 :                          "%s", req->lvol_store->name);
     775                 :            :         } else {
     776                 :            :                 /* Update lvs name with new_name */
     777         [ -  + ]:          7 :                 snprintf(req->lvol_store->name,
     778                 :            :                          sizeof(req->lvol_store->name),
     779                 :          7 :                          "%s", req->lvol_store->new_name);
     780                 :            :         }
     781                 :            : 
     782                 :         13 :         req->cb_fn(req->cb_arg, req->lvserrno);
     783                 :         13 :         free(req);
     784                 :         13 : }
     785                 :            : 
     786                 :            : static void
     787                 :          7 : lvs_rename_sync_cb(void *cb_arg, int lvolerrno)
     788                 :            : {
     789                 :          7 :         struct spdk_lvs_req *req = cb_arg;
     790                 :          7 :         struct spdk_blob *blob = req->lvol_store->super_blob;
     791                 :            : 
     792         [ -  + ]:          7 :         if (lvolerrno < 0) {
     793                 :          0 :                 req->lvserrno = lvolerrno;
     794                 :            :         }
     795                 :            : 
     796                 :          7 :         spdk_blob_close(blob, lvs_rename_cb, req);
     797                 :          7 : }
     798                 :            : 
     799                 :            : static void
     800                 :         13 : lvs_rename_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
     801                 :            : {
     802                 :         13 :         struct spdk_lvs_req *req = cb_arg;
     803                 :            :         int rc;
     804                 :            : 
     805         [ +  + ]:         13 :         if (lvolerrno < 0) {
     806                 :          6 :                 lvs_rename_cb(cb_arg, lvolerrno);
     807                 :          6 :                 return;
     808                 :            :         }
     809                 :            : 
     810                 :          7 :         rc = spdk_blob_set_xattr(blob, "name", req->lvol_store->new_name,
     811         [ -  + ]:          7 :                                  strlen(req->lvol_store->new_name) + 1);
     812         [ -  + ]:          7 :         if (rc < 0) {
     813                 :          0 :                 req->lvserrno = rc;
     814                 :          0 :                 lvs_rename_sync_cb(req, rc);
     815                 :          0 :                 return;
     816                 :            :         }
     817                 :            : 
     818                 :          7 :         req->lvol_store->super_blob = blob;
     819                 :            : 
     820                 :          7 :         spdk_blob_sync_md(blob, lvs_rename_sync_cb, req);
     821                 :            : }
     822                 :            : 
     823                 :            : void
     824                 :         32 : 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   [ +  +  -  +  :         32 :         if (strncmp(lvs->name, new_name, SPDK_LVS_NAME_MAX) == 0) {
                   +  + ]
     833                 :          6 :                 cb_fn(cb_arg, 0);
     834                 :          6 :                 return;
     835                 :            :         }
     836                 :            : 
     837                 :            :         /* Check if new or new_name is already used in other lvs */
     838                 :         26 :         pthread_mutex_lock(&g_lvol_stores_mutex);
     839         [ +  + ]:         58 :         TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
     840   [ +  +  -  +  :         45 :                 if (!strncmp(new_name, tmp->name, SPDK_LVS_NAME_MAX) ||
                   +  + ]
     841   [ +  +  -  +  :         38 :                     !strncmp(new_name, tmp->new_name, SPDK_LVS_NAME_MAX)) {
                   +  + ]
     842                 :         13 :                         pthread_mutex_unlock(&g_lvol_stores_mutex);
     843                 :         13 :                         cb_fn(cb_arg, -EEXIST);
     844                 :         13 :                         return;
     845                 :            :                 }
     846                 :            :         }
     847                 :         13 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
     848                 :            : 
     849                 :         13 :         req = calloc(1, sizeof(*req));
     850         [ -  + ]:         13 :         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                 :         13 :         snprintf(lvs->new_name, sizeof(lvs->new_name), "%s", new_name);
     856                 :         13 :         req->lvol_store = lvs;
     857                 :         13 :         req->cb_fn = cb_fn;
     858                 :         13 :         req->cb_arg = cb_arg;
     859                 :            : 
     860                 :         13 :         spdk_bs_open_blob(lvs->blobstore, lvs->super_blob_id, lvs_rename_open_cb, req);
     861                 :            : }
     862                 :            : 
     863                 :            : static void
     864                 :        287 : _lvs_unload_cb(void *cb_arg, int lvserrno)
     865                 :            : {
     866                 :        287 :         struct spdk_lvs_req *lvs_req = cb_arg;
     867                 :            : 
     868   [ -  +  -  + ]:        287 :         SPDK_INFOLOG(lvol, "Lvol store unloaded\n");
     869         [ -  + ]:        287 :         assert(lvs_req->cb_fn != NULL);
     870                 :        287 :         lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
     871                 :        287 :         free(lvs_req);
     872                 :        287 : }
     873                 :            : 
     874                 :            : int
     875                 :        299 : 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         [ +  + ]:        299 :         if (lvs == NULL) {
     882                 :          6 :                 SPDK_ERRLOG("Lvol store is NULL\n");
     883                 :          6 :                 return -ENODEV;
     884                 :            :         }
     885                 :            : 
     886         [ +  + ]:        773 :         TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
     887   [ -  +  -  + ]:        486 :                 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         [ +  + ]:        486 :                 } else if (lvol->ref_count != 0) {
     892                 :          6 :                         SPDK_ERRLOG("Lvols still open on lvol store\n");
     893                 :          6 :                         cb_fn(cb_arg, -EBUSY);
     894                 :          6 :                         return -EBUSY;
     895                 :            :                 }
     896                 :            :         }
     897                 :            : 
     898         [ +  + ]:        767 :         TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) {
     899                 :        480 :                 spdk_lvs_esnap_missing_remove(lvol);
     900         [ +  + ]:        480 :                 TAILQ_REMOVE(&lvs->lvols, lvol, link);
     901                 :        480 :                 lvol_free(lvol);
     902                 :            :         }
     903                 :            : 
     904                 :        287 :         lvs_req = calloc(1, sizeof(*lvs_req));
     905         [ -  + ]:        287 :         if (!lvs_req) {
     906                 :          0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
     907                 :          0 :                 return -ENOMEM;
     908                 :            :         }
     909                 :            : 
     910                 :        287 :         lvs_req->cb_fn = cb_fn;
     911                 :        287 :         lvs_req->cb_arg = cb_arg;
     912                 :            : 
     913   [ -  +  -  + ]:        287 :         SPDK_INFOLOG(lvol, "Unloading lvol store\n");
     914                 :        287 :         spdk_bs_unload(lvs->blobstore, _lvs_unload_cb, lvs_req);
     915                 :        287 :         lvs_free(lvs);
     916                 :            : 
     917                 :        287 :         return 0;
     918                 :            : }
     919                 :            : 
     920                 :            : static void
     921                 :        270 : _lvs_destroy_cb(void *cb_arg, int lvserrno)
     922                 :            : {
     923                 :        270 :         struct spdk_lvs_destroy_req *lvs_req = cb_arg;
     924                 :            : 
     925   [ -  +  -  + ]:        270 :         SPDK_INFOLOG(lvol, "Lvol store destroyed\n");
     926         [ -  + ]:        270 :         assert(lvs_req->cb_fn != NULL);
     927                 :        270 :         lvs_req->cb_fn(lvs_req->cb_arg, lvserrno);
     928                 :        270 :         free(lvs_req);
     929                 :        270 : }
     930                 :            : 
     931                 :            : static void
     932                 :        270 : _lvs_destroy_super_cb(void *cb_arg, int bserrno)
     933                 :            : {
     934                 :        270 :         struct spdk_lvs_destroy_req *lvs_req = cb_arg;
     935                 :        270 :         struct spdk_lvol_store *lvs = lvs_req->lvs;
     936                 :            : 
     937         [ -  + ]:        270 :         assert(lvs != NULL);
     938                 :            : 
     939   [ -  +  -  + ]:        270 :         SPDK_INFOLOG(lvol, "Destroying lvol store\n");
     940                 :        270 :         spdk_bs_destroy(lvs->blobstore, _lvs_destroy_cb, lvs_req);
     941                 :        270 :         lvs_free(lvs);
     942                 :        270 : }
     943                 :            : 
     944                 :            : int
     945                 :        276 : 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         [ -  + ]:        276 :         if (lvs == NULL) {
     952                 :          0 :                 SPDK_ERRLOG("Lvol store is NULL\n");
     953                 :          0 :                 return -ENODEV;
     954                 :            :         }
     955                 :            : 
     956         [ +  + ]:        294 :         TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
     957   [ -  +  -  + ]:         24 :                 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         [ +  + ]:         24 :                 } else if (iter_lvol->ref_count != 0) {
     962                 :          6 :                         SPDK_ERRLOG("Lvols still open on lvol store\n");
     963                 :          6 :                         cb_fn(cb_arg, -EBUSY);
     964                 :          6 :                         return -EBUSY;
     965                 :            :                 }
     966                 :            :         }
     967                 :            : 
     968         [ +  + ]:        288 :         TAILQ_FOREACH_SAFE(iter_lvol, &lvs->lvols, link, tmp) {
     969                 :         18 :                 free(iter_lvol);
     970                 :            :         }
     971                 :            : 
     972                 :        270 :         lvs_req = calloc(1, sizeof(*lvs_req));
     973         [ -  + ]:        270 :         if (!lvs_req) {
     974                 :          0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol store request pointer\n");
     975                 :          0 :                 return -ENOMEM;
     976                 :            :         }
     977                 :            : 
     978                 :        270 :         lvs_req->cb_fn = cb_fn;
     979                 :        270 :         lvs_req->cb_arg = cb_arg;
     980                 :        270 :         lvs_req->lvs = lvs;
     981                 :            : 
     982   [ -  +  -  + ]:        270 :         SPDK_INFOLOG(lvol, "Deleting super blob\n");
     983                 :        270 :         spdk_bs_delete_blob(lvs->blobstore, lvs->super_blob_id, _lvs_destroy_super_cb, lvs_req);
     984                 :            : 
     985                 :        270 :         return 0;
     986                 :            : }
     987                 :            : 
     988                 :            : static void
     989                 :       1052 : lvol_close_blob_cb(void *cb_arg, int lvolerrno)
     990                 :            : {
     991                 :       1052 :         struct spdk_lvol_req *req = cb_arg;
     992                 :       1052 :         struct spdk_lvol *lvol = req->lvol;
     993                 :            : 
     994         [ +  + ]:       1052 :         if (lvolerrno < 0) {
     995                 :          6 :                 SPDK_ERRLOG("Could not close blob on lvol\n");
     996                 :          6 :                 goto end;
     997                 :            :         }
     998                 :            : 
     999                 :       1046 :         lvol->ref_count--;
    1000                 :       1046 :         lvol->blob = NULL;
    1001   [ +  +  +  - ]:       1046 :         SPDK_INFOLOG(lvol, "Lvol %s closed\n", lvol->unique_id);
    1002                 :            : 
    1003                 :       1046 : end:
    1004                 :       1052 :         lvol->action_in_progress = false;
    1005                 :       1052 :         req->cb_fn(req->cb_arg, lvolerrno);
    1006                 :       1052 :         free(req);
    1007                 :       1052 : }
    1008                 :            : 
    1009                 :            : bool
    1010                 :         62 : spdk_lvol_deletable(struct spdk_lvol *lvol)
    1011                 :            : {
    1012                 :         62 :         size_t count = 0;
    1013                 :            : 
    1014                 :         62 :         spdk_blob_get_clones(lvol->lvol_store->blobstore, lvol->blob_id, NULL, &count);
    1015                 :         62 :         return (count == 0);
    1016                 :            : }
    1017                 :            : 
    1018                 :            : static void
    1019                 :        572 : lvol_delete_blob_cb(void *cb_arg, int lvolerrno)
    1020                 :            : {
    1021                 :        572 :         struct spdk_lvol_req *req = cb_arg;
    1022                 :        572 :         struct spdk_lvol *lvol = req->lvol;
    1023                 :        572 :         struct spdk_lvol *clone_lvol = req->clone_lvol;
    1024                 :            : 
    1025         [ +  + ]:        572 :         if (lvolerrno < 0) {
    1026                 :          6 :                 SPDK_ERRLOG("Could not remove blob on lvol gracefully - forced removal\n");
    1027                 :            :         } else {
    1028   [ -  +  -  + ]:        566 :                 SPDK_INFOLOG(lvol, "Lvol %s deleted\n", lvol->unique_id);
    1029                 :            :         }
    1030                 :            : 
    1031         [ +  + ]:        572 :         if (lvol->degraded_set != NULL) {
    1032         [ +  + ]:         75 :                 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                 :          7 :                         struct spdk_lvs_degraded_lvol_set *degraded_set = lvol->degraded_set;
    1039                 :            : 
    1040                 :          7 :                         lvs_degraded_lvol_set_remove(degraded_set, lvol);
    1041                 :          7 :                         lvs_degraded_lvol_set_add(degraded_set, clone_lvol);
    1042                 :            :                 } else {
    1043                 :         68 :                         spdk_lvs_esnap_missing_remove(lvol);
    1044                 :            :                 }
    1045                 :            :         }
    1046                 :            : 
    1047         [ +  + ]:        572 :         TAILQ_REMOVE(&lvol->lvol_store->lvols, lvol, link);
    1048                 :        572 :         lvol_free(lvol);
    1049                 :        572 :         req->cb_fn(req->cb_arg, lvolerrno);
    1050                 :        572 :         free(req);
    1051                 :        572 : }
    1052                 :            : 
    1053                 :            : static void
    1054                 :        930 : lvol_create_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
    1055                 :            : {
    1056                 :        930 :         struct spdk_lvol_with_handle_req *req = cb_arg;
    1057                 :        930 :         struct spdk_lvol *lvol = req->lvol;
    1058                 :            : 
    1059         [ -  + ]:        930 :         TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
    1060                 :            : 
    1061         [ -  + ]:        930 :         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                 :        930 :         lvol->blob = blob;
    1069                 :        930 :         lvol->blob_id = spdk_blob_get_id(blob);
    1070                 :            : 
    1071                 :        930 :         TAILQ_INSERT_TAIL(&lvol->lvol_store->lvols, lvol, link);
    1072                 :            : 
    1073                 :        930 :         lvol->ref_count++;
    1074                 :            : 
    1075         [ -  + ]:        930 :         assert(req->cb_fn != NULL);
    1076                 :        930 :         req->cb_fn(req->cb_arg, req->lvol, lvolerrno);
    1077                 :        930 :         free(req);
    1078                 :            : }
    1079                 :            : 
    1080                 :            : static void
    1081                 :        941 : lvol_create_cb(void *cb_arg, spdk_blob_id blobid, int lvolerrno)
    1082                 :            : {
    1083                 :        941 :         struct spdk_lvol_with_handle_req *req = cb_arg;
    1084                 :            :         struct spdk_blob_store *bs;
    1085                 :        549 :         struct spdk_blob_open_opts opts;
    1086                 :            : 
    1087         [ +  + ]:        941 :         if (lvolerrno < 0) {
    1088         [ -  + ]:         11 :                 TAILQ_REMOVE(&req->lvol->lvol_store->pending_lvols, req->lvol, link);
    1089                 :         11 :                 lvol_free(req->lvol);
    1090         [ -  + ]:         11 :                 assert(req->cb_fn != NULL);
    1091                 :         11 :                 req->cb_fn(req->cb_arg, NULL, lvolerrno);
    1092                 :         11 :                 free(req);
    1093                 :         11 :                 return;
    1094                 :            :         }
    1095                 :            : 
    1096                 :        930 :         spdk_blob_open_opts_init(&opts, sizeof(opts));
    1097                 :        930 :         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                 :        930 :         opts.esnap_ctx = req->lvol;
    1108                 :        930 :         bs = req->lvol->lvol_store->blobstore;
    1109                 :            : 
    1110   [ +  +  +  + ]:        930 :         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                 :          6 :                 struct spdk_lvs_degraded_lvol_set *degraded_set = req->origlvol->degraded_set;
    1117                 :            : 
    1118                 :          6 :                 lvs_degraded_lvol_set_remove(degraded_set, req->origlvol);
    1119                 :          6 :                 lvs_degraded_lvol_set_add(degraded_set, req->lvol);
    1120                 :            :         }
    1121                 :            : 
    1122                 :        930 :         spdk_bs_open_blob_ext(bs, blobid, &opts, lvol_create_open_cb, req);
    1123                 :            : }
    1124                 :            : 
    1125                 :            : static void
    1126                 :       1036 : lvol_get_xattr_value(void *xattr_ctx, const char *name,
    1127                 :            :                      const void **value, size_t *value_len)
    1128                 :            : {
    1129                 :       1036 :         struct spdk_lvol *lvol = xattr_ctx;
    1130                 :            : 
    1131   [ +  +  +  + ]:       1036 :         if (!strcmp(LVOL_NAME, name)) {
    1132                 :        518 :                 *value = lvol->name;
    1133                 :        518 :                 *value_len = SPDK_LVOL_NAME_MAX;
    1134                 :        518 :                 return;
    1135                 :            :         }
    1136   [ +  +  +  + ]:        518 :         if (!strcmp("uuid", name)) {
    1137                 :        512 :                 *value = lvol->uuid_str;
    1138                 :        512 :                 *value_len = sizeof(lvol->uuid_str);
    1139                 :        512 :                 return;
    1140                 :            :         }
    1141                 :          6 :         *value = NULL;
    1142                 :          6 :         *value_len = 0;
    1143                 :            : }
    1144                 :            : 
    1145                 :            : static int
    1146                 :       1056 : lvs_verify_lvol_name(struct spdk_lvol_store *lvs, const char *name)
    1147                 :            : {
    1148                 :            :         struct spdk_lvol *tmp;
    1149                 :            : 
    1150   [ +  +  +  +  :       1056 :         if (name == NULL || strnlen(name, SPDK_LVOL_NAME_MAX) == 0) {
                   +  + ]
    1151   [ -  +  -  + ]:         42 :                 SPDK_INFOLOG(lvol, "lvol name not provided.\n");
    1152                 :         42 :                 return -EINVAL;
    1153                 :            :         }
    1154                 :            : 
    1155   [ +  +  +  + ]:       1014 :         if (strnlen(name, SPDK_LVOL_NAME_MAX) == SPDK_LVOL_NAME_MAX) {
    1156                 :         12 :                 SPDK_ERRLOG("Name has no null terminator.\n");
    1157                 :         12 :                 return -EINVAL;
    1158                 :            :         }
    1159                 :            : 
    1160         [ +  + ]:       3264 :         TAILQ_FOREACH(tmp, &lvs->lvols, link) {
    1161   [ +  +  -  +  :       2311 :                 if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
                   +  + ]
    1162                 :         49 :                         SPDK_ERRLOG("lvol with name %s already exists\n", name);
    1163                 :         49 :                         return -EEXIST;
    1164                 :            :                 }
    1165                 :            :         }
    1166                 :            : 
    1167         [ +  + ]:        953 :         TAILQ_FOREACH(tmp, &lvs->pending_lvols, link) {
    1168   [ +  +  -  +  :          6 :                 if (!strncmp(name, tmp->name, SPDK_LVOL_NAME_MAX)) {
                   +  - ]
    1169                 :          6 :                         SPDK_ERRLOG("lvol with name %s is being already created\n", name);
    1170                 :          6 :                         return -EEXIST;
    1171                 :            :                 }
    1172                 :            :         }
    1173                 :            : 
    1174                 :        947 :         return 0;
    1175                 :            : }
    1176                 :            : 
    1177                 :            : int
    1178                 :        682 : 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                 :        333 :         struct spdk_blob_opts opts;
    1186                 :        682 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1187                 :            :         int rc;
    1188                 :            : 
    1189         [ +  + ]:        682 :         if (lvs == NULL) {
    1190                 :          6 :                 SPDK_ERRLOG("lvol store does not exist\n");
    1191                 :          6 :                 return -EINVAL;
    1192                 :            :         }
    1193                 :            : 
    1194                 :        676 :         rc = lvs_verify_lvol_name(lvs, name);
    1195         [ +  + ]:        676 :         if (rc < 0) {
    1196                 :         43 :                 return rc;
    1197                 :            :         }
    1198                 :            : 
    1199                 :        633 :         bs = lvs->blobstore;
    1200                 :            : 
    1201                 :        633 :         req = calloc(1, sizeof(*req));
    1202         [ -  + ]:        633 :         if (!req) {
    1203                 :          0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1204                 :          0 :                 return -ENOMEM;
    1205                 :            :         }
    1206                 :        633 :         req->cb_fn = cb_fn;
    1207                 :        633 :         req->cb_arg = cb_arg;
    1208                 :            : 
    1209                 :        633 :         lvol = lvol_alloc(lvs, name, thin_provision, clear_method);
    1210         [ -  + ]:        633 :         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                 :        633 :         req->lvol = lvol;
    1217                 :        633 :         spdk_blob_opts_init(&opts, sizeof(opts));
    1218                 :        633 :         opts.thin_provision = thin_provision;
    1219                 :        633 :         opts.num_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(bs));
    1220                 :        633 :         opts.clear_method = lvol->clear_method;
    1221                 :        633 :         opts.xattrs.count = SPDK_COUNTOF(xattr_names);
    1222                 :        633 :         opts.xattrs.names = xattr_names;
    1223                 :        633 :         opts.xattrs.ctx = lvol;
    1224                 :        633 :         opts.xattrs.get_value = lvol_get_xattr_value;
    1225                 :            : 
    1226                 :        633 :         spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
    1227                 :            : 
    1228                 :        633 :         return 0;
    1229                 :            : }
    1230                 :            : 
    1231                 :            : int
    1232                 :        236 : 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                 :        198 :         struct spdk_blob_opts opts;
    1240                 :            :         uint64_t cluster_sz;
    1241                 :        236 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1242                 :            :         int rc;
    1243                 :            : 
    1244         [ +  + ]:        236 :         if (lvs == NULL) {
    1245                 :          6 :                 SPDK_ERRLOG("lvol store does not exist\n");
    1246                 :          6 :                 return -EINVAL;
    1247                 :            :         }
    1248                 :            : 
    1249                 :        230 :         rc = lvs_verify_lvol_name(lvs, clone_name);
    1250         [ +  + ]:        230 :         if (rc < 0) {
    1251                 :         30 :                 return rc;
    1252                 :            :         }
    1253                 :            : 
    1254                 :        200 :         bs = lvs->blobstore;
    1255                 :            : 
    1256                 :        200 :         cluster_sz = spdk_bs_get_cluster_size(bs);
    1257   [ +  +  +  + ]:        200 :         if ((size_bytes % cluster_sz) != 0) {
    1258                 :          6 :                 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                 :          6 :                 return -EINVAL;
    1262                 :            :         }
    1263                 :            : 
    1264                 :        194 :         req = calloc(1, sizeof(*req));
    1265         [ -  + ]:        194 :         if (!req) {
    1266                 :          0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
    1267                 :          0 :                 return -ENOMEM;
    1268                 :            :         }
    1269                 :        194 :         req->cb_fn = cb_fn;
    1270                 :        194 :         req->cb_arg = cb_arg;
    1271                 :            : 
    1272                 :        194 :         lvol = lvol_alloc(lvs, clone_name, true, LVOL_CLEAR_WITH_DEFAULT);
    1273         [ -  + ]:        194 :         if (!lvol) {
    1274                 :          0 :                 free(req);
    1275                 :          0 :                 SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
    1276                 :          0 :                 return -ENOMEM;
    1277                 :            :         }
    1278                 :        194 :         req->lvol = lvol;
    1279                 :            : 
    1280                 :        194 :         spdk_blob_opts_init(&opts, sizeof(opts));
    1281                 :        194 :         opts.esnap_id = esnap_id;
    1282                 :        194 :         opts.esnap_id_len = id_len;
    1283                 :        194 :         opts.thin_provision = true;
    1284                 :        194 :         opts.num_clusters = spdk_divide_round_up(size_bytes, cluster_sz);
    1285                 :        194 :         opts.clear_method = lvol->clear_method;
    1286                 :        194 :         opts.xattrs.count = SPDK_COUNTOF(xattr_names);
    1287                 :        194 :         opts.xattrs.names = xattr_names;
    1288                 :        194 :         opts.xattrs.ctx = lvol;
    1289                 :        194 :         opts.xattrs.get_value = lvol_get_xattr_value;
    1290                 :            : 
    1291                 :        194 :         spdk_bs_create_blob_ext(lvs->blobstore, &opts, lvol_create_cb, req);
    1292                 :            : 
    1293                 :        194 :         return 0;
    1294                 :            : }
    1295                 :            : 
    1296                 :            : void
    1297                 :         91 : 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                 :         76 :         struct spdk_blob_xattr_opts snapshot_xattrs;
    1305                 :         91 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1306                 :            :         int rc;
    1307                 :            : 
    1308         [ +  + ]:         91 :         if (origlvol == NULL) {
    1309   [ -  +  -  + ]:          6 :                 SPDK_INFOLOG(lvol, "Lvol not provided.\n");
    1310                 :          6 :                 cb_fn(cb_arg, NULL, -EINVAL);
    1311                 :          9 :                 return;
    1312                 :            :         }
    1313                 :            : 
    1314                 :         85 :         origblob = origlvol->blob;
    1315                 :         85 :         lvs = origlvol->lvol_store;
    1316         [ -  + ]:         85 :         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                 :         85 :         rc = lvs_verify_lvol_name(lvs, snapshot_name);
    1323         [ +  + ]:         85 :         if (rc < 0) {
    1324                 :         18 :                 cb_fn(cb_arg, NULL, rc);
    1325                 :         18 :                 return;
    1326                 :            :         }
    1327                 :            : 
    1328                 :         67 :         req = calloc(1, sizeof(*req));
    1329         [ -  + ]:         67 :         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                 :         67 :         newlvol = lvol_alloc(origlvol->lvol_store, snapshot_name, true,
    1336                 :         67 :                              (enum lvol_clear_method)origlvol->clear_method);
    1337         [ -  + ]:         67 :         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                 :         67 :         snapshot_xattrs.count = SPDK_COUNTOF(xattr_names);
    1345                 :         67 :         snapshot_xattrs.ctx = newlvol;
    1346                 :         67 :         snapshot_xattrs.names = xattr_names;
    1347                 :         67 :         snapshot_xattrs.get_value = lvol_get_xattr_value;
    1348                 :         67 :         req->lvol = newlvol;
    1349                 :         67 :         req->origlvol = origlvol;
    1350                 :         67 :         req->cb_fn = cb_fn;
    1351                 :         67 :         req->cb_arg = cb_arg;
    1352                 :            : 
    1353                 :         67 :         spdk_bs_create_snapshot(lvs->blobstore, spdk_blob_get_id(origblob), &snapshot_xattrs,
    1354                 :            :                                 lvol_create_cb, req);
    1355                 :            : }
    1356                 :            : 
    1357                 :            : void
    1358                 :         71 : 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                 :         58 :         struct spdk_blob_xattr_opts clone_xattrs;
    1366                 :         71 :         char *xattr_names[] = {LVOL_NAME, "uuid"};
    1367                 :            :         int rc;
    1368                 :            : 
    1369         [ +  + ]:         71 :         if (origlvol == NULL) {
    1370   [ -  +  -  + ]:          6 :                 SPDK_INFOLOG(lvol, "Lvol not provided.\n");
    1371                 :          6 :                 cb_fn(cb_arg, NULL, -EINVAL);
    1372                 :          9 :                 return;
    1373                 :            :         }
    1374                 :            : 
    1375                 :         65 :         origblob = origlvol->blob;
    1376                 :         65 :         lvs = origlvol->lvol_store;
    1377         [ -  + ]:         65 :         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                 :         65 :         rc = lvs_verify_lvol_name(lvs, clone_name);
    1384         [ +  + ]:         65 :         if (rc < 0) {
    1385                 :         18 :                 cb_fn(cb_arg, NULL, rc);
    1386                 :         18 :                 return;
    1387                 :            :         }
    1388                 :            : 
    1389                 :         47 :         req = calloc(1, sizeof(*req));
    1390         [ -  + ]:         47 :         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                 :         47 :         newlvol = lvol_alloc(lvs, clone_name, true, (enum lvol_clear_method)origlvol->clear_method);
    1397         [ -  + ]:         47 :         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                 :         47 :         clone_xattrs.count = SPDK_COUNTOF(xattr_names);
    1405                 :         47 :         clone_xattrs.ctx = newlvol;
    1406                 :         47 :         clone_xattrs.names = xattr_names;
    1407                 :         47 :         clone_xattrs.get_value = lvol_get_xattr_value;
    1408                 :         47 :         req->lvol = newlvol;
    1409                 :         47 :         req->cb_fn = cb_fn;
    1410                 :         47 :         req->cb_arg = cb_arg;
    1411                 :            : 
    1412                 :         47 :         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                 :         41 : lvol_resize_done(void *cb_arg, int lvolerrno)
    1419                 :            : {
    1420                 :         41 :         struct spdk_lvol_req *req = cb_arg;
    1421                 :            : 
    1422                 :         41 :         req->cb_fn(req->cb_arg,  lvolerrno);
    1423                 :         41 :         free(req);
    1424                 :         41 : }
    1425                 :            : 
    1426                 :            : static void
    1427                 :         54 : lvol_blob_resize_cb(void *cb_arg, int bserrno)
    1428                 :            : {
    1429                 :         54 :         struct spdk_lvol_req *req = cb_arg;
    1430                 :         54 :         struct spdk_lvol *lvol = req->lvol;
    1431                 :            : 
    1432         [ +  + ]:         54 :         if (bserrno != 0) {
    1433                 :         13 :                 req->cb_fn(req->cb_arg, bserrno);
    1434                 :         13 :                 free(req);
    1435                 :         13 :                 return;
    1436                 :            :         }
    1437                 :            : 
    1438                 :         41 :         spdk_blob_sync_md(lvol->blob, lvol_resize_done, req);
    1439                 :            : }
    1440                 :            : 
    1441                 :            : void
    1442                 :         54 : spdk_lvol_resize(struct spdk_lvol *lvol, uint64_t sz,
    1443                 :            :                  spdk_lvol_op_complete cb_fn, void *cb_arg)
    1444                 :            : {
    1445                 :         54 :         struct spdk_blob *blob = lvol->blob;
    1446                 :         54 :         struct spdk_lvol_store *lvs = lvol->lvol_store;
    1447                 :            :         struct spdk_lvol_req *req;
    1448                 :         54 :         uint64_t new_clusters = spdk_divide_round_up(sz, spdk_bs_get_cluster_size(lvs->blobstore));
    1449                 :            : 
    1450                 :         54 :         req = calloc(1, sizeof(*req));
    1451         [ -  + ]:         54 :         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                 :         54 :         req->cb_fn = cb_fn;
    1457                 :         54 :         req->cb_arg = cb_arg;
    1458                 :         54 :         req->lvol = lvol;
    1459                 :            : 
    1460                 :         54 :         spdk_blob_resize(blob, new_clusters, lvol_blob_resize_cb, req);
    1461                 :            : }
    1462                 :            : 
    1463                 :            : static void
    1464                 :          9 : lvol_set_read_only_cb(void *cb_arg, int lvolerrno)
    1465                 :            : {
    1466                 :          9 :         struct spdk_lvol_req *req = cb_arg;
    1467                 :            : 
    1468                 :          9 :         req->cb_fn(req->cb_arg, lvolerrno);
    1469                 :          9 :         free(req);
    1470                 :          9 : }
    1471                 :            : 
    1472                 :            : void
    1473                 :          9 : 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                 :          9 :         req = calloc(1, sizeof(*req));
    1478         [ -  + ]:          9 :         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                 :          9 :         req->cb_fn = cb_fn;
    1484                 :          9 :         req->cb_arg = cb_arg;
    1485                 :            : 
    1486                 :          9 :         spdk_blob_set_read_only(lvol->blob);
    1487                 :          9 :         spdk_blob_sync_md(lvol->blob, lvol_set_read_only_cb, req);
    1488                 :            : }
    1489                 :            : 
    1490                 :            : static void
    1491                 :         10 : lvol_rename_cb(void *cb_arg, int lvolerrno)
    1492                 :            : {
    1493                 :         10 :         struct spdk_lvol_req *req = cb_arg;
    1494                 :            : 
    1495         [ -  + ]:         10 :         if (lvolerrno != 0) {
    1496                 :          0 :                 SPDK_ERRLOG("Lvol rename operation failed\n");
    1497                 :            :         } else {
    1498         [ -  + ]:         10 :                 snprintf(req->lvol->name, sizeof(req->lvol->name), "%s", req->name);
    1499                 :            :         }
    1500                 :            : 
    1501                 :         10 :         req->cb_fn(req->cb_arg, lvolerrno);
    1502                 :         10 :         free(req);
    1503                 :         10 : }
    1504                 :            : 
    1505                 :            : void
    1506                 :         16 : 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                 :         16 :         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   [ -  +  -  +  :         16 :         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         [ +  + ]:         44 :         TAILQ_FOREACH(tmp, &lvol->lvol_store->lvols, link) {
    1523   [ +  +  -  +  :         34 :                 if (strncmp(tmp->name, new_name, SPDK_LVOL_NAME_MAX) == 0) {
                   +  + ]
    1524                 :          6 :                         SPDK_ERRLOG("Lvol %s already exists in lvol store %s\n", new_name, lvol->lvol_store->name);
    1525                 :          6 :                         cb_fn(cb_arg, -EEXIST);
    1526                 :          6 :                         return;
    1527                 :            :                 }
    1528                 :            :         }
    1529                 :            : 
    1530                 :         10 :         req = calloc(1, sizeof(*req));
    1531         [ -  + ]:         10 :         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                 :         10 :         req->cb_fn = cb_fn;
    1537                 :         10 :         req->cb_arg = cb_arg;
    1538                 :         10 :         req->lvol = lvol;
    1539                 :         10 :         snprintf(req->name, sizeof(req->name), "%s", new_name);
    1540                 :            : 
    1541         [ -  + ]:         10 :         rc = spdk_blob_set_xattr(blob, "name", new_name, strlen(new_name) + 1);
    1542         [ -  + ]:         10 :         if (rc < 0) {
    1543                 :          0 :                 free(req);
    1544                 :          0 :                 cb_fn(cb_arg, rc);
    1545                 :          0 :                 return;
    1546                 :            :         }
    1547                 :            : 
    1548                 :         10 :         spdk_blob_sync_md(blob, lvol_rename_cb, req);
    1549                 :            : }
    1550                 :            : 
    1551                 :            : void
    1552                 :        578 : 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                 :        416 :         spdk_blob_id    clone_id;
    1558                 :        578 :         size_t          count = 1;
    1559                 :            :         int             rc;
    1560                 :            : 
    1561         [ -  + ]:        578 :         assert(cb_fn != NULL);
    1562                 :            : 
    1563         [ -  + ]:        578 :         if (lvol == NULL) {
    1564                 :          0 :                 SPDK_ERRLOG("lvol does not exist\n");
    1565                 :          0 :                 cb_fn(cb_arg, -ENODEV);
    1566                 :          1 :                 return;
    1567                 :            :         }
    1568                 :            : 
    1569                 :        578 :         lvs = lvol->lvol_store;
    1570                 :            : 
    1571         [ +  + ]:        578 :         if (lvol->ref_count != 0) {
    1572                 :          6 :                 SPDK_ERRLOG("Cannot destroy lvol %s because it is still open\n", lvol->unique_id);
    1573                 :          6 :                 cb_fn(cb_arg, -EBUSY);
    1574                 :          6 :                 return;
    1575                 :            :         }
    1576                 :            : 
    1577                 :        572 :         req = calloc(1, sizeof(*req));
    1578         [ -  + ]:        572 :         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                 :        572 :         req->cb_fn = cb_fn;
    1585                 :        572 :         req->cb_arg = cb_arg;
    1586                 :        572 :         req->lvol = lvol;
    1587                 :        572 :         bs = lvol->lvol_store->blobstore;
    1588                 :            : 
    1589                 :        572 :         rc = spdk_blob_get_clones(lvs->blobstore, lvol->blob_id, &clone_id, &count);
    1590   [ +  -  +  + ]:        572 :         if (rc == 0 && count == 1) {
    1591                 :         13 :                 req->clone_lvol = lvs_get_lvol_by_blob_id(lvs, clone_id);
    1592         [ -  + ]:        559 :         } 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                 :        572 :         lvol->action_in_progress = true;
    1602                 :            : 
    1603                 :        572 :         spdk_bs_delete_blob(bs, lvol->blob_id, lvol_delete_blob_cb, req);
    1604                 :            : }
    1605                 :            : 
    1606                 :            : void
    1607                 :       1076 : 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         [ -  + ]:       1076 :         assert(cb_fn != NULL);
    1612                 :            : 
    1613         [ +  + ]:       1076 :         if (lvol == NULL) {
    1614                 :          6 :                 SPDK_ERRLOG("lvol does not exist\n");
    1615                 :          6 :                 cb_fn(cb_arg, -ENODEV);
    1616                 :          6 :                 return;
    1617                 :            :         }
    1618                 :            : 
    1619         [ +  + ]:       1070 :         if (lvol->ref_count > 1) {
    1620                 :          6 :                 lvol->ref_count--;
    1621                 :          6 :                 cb_fn(cb_arg, 0);
    1622                 :          6 :                 return;
    1623         [ +  + ]:       1064 :         } else if (lvol->ref_count == 0) {
    1624                 :         12 :                 cb_fn(cb_arg, -EINVAL);
    1625                 :         12 :                 return;
    1626                 :            :         }
    1627                 :            : 
    1628                 :       1052 :         req = calloc(1, sizeof(*req));
    1629         [ -  + ]:       1052 :         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                 :       1052 :         req->cb_fn = cb_fn;
    1636                 :       1052 :         req->cb_arg = cb_arg;
    1637                 :       1052 :         req->lvol = lvol;
    1638                 :            : 
    1639                 :       1052 :         lvol->action_in_progress = true;
    1640                 :            : 
    1641                 :       1052 :         spdk_blob_close(lvol->blob, lvol_close_blob_cb, req);
    1642                 :            : }
    1643                 :            : 
    1644                 :            : struct spdk_io_channel *
    1645                 :       1124 : spdk_lvol_get_io_channel(struct spdk_lvol *lvol)
    1646                 :            : {
    1647                 :       1124 :         return spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    1648                 :            : }
    1649                 :            : 
    1650                 :            : static void
    1651                 :         32 : lvol_inflate_cb(void *cb_arg, int lvolerrno)
    1652                 :            : {
    1653                 :         32 :         struct spdk_lvol_req *req = cb_arg;
    1654                 :            : 
    1655                 :         32 :         spdk_bs_free_io_channel(req->channel);
    1656                 :            : 
    1657         [ +  + ]:         32 :         if (lvolerrno < 0) {
    1658                 :         13 :                 SPDK_ERRLOG("Could not inflate lvol\n");
    1659                 :            :         }
    1660                 :            : 
    1661                 :         32 :         req->cb_fn(req->cb_arg, lvolerrno);
    1662                 :         32 :         free(req);
    1663                 :         32 : }
    1664                 :            : 
    1665                 :            : void
    1666                 :         17 : 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         [ -  + ]:         17 :         assert(cb_fn != NULL);
    1672                 :            : 
    1673         [ -  + ]:         17 :         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                 :         17 :         req = calloc(1, sizeof(*req));
    1680         [ -  + ]:         17 :         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                 :         17 :         req->cb_fn = cb_fn;
    1687                 :         17 :         req->cb_arg = cb_arg;
    1688                 :         17 :         req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    1689         [ -  + ]:         17 :         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                 :         17 :         blob_id = spdk_blob_get_id(lvol->blob);
    1697                 :         17 :         spdk_bs_inflate_blob(lvol->lvol_store->blobstore, req->channel, blob_id, lvol_inflate_cb,
    1698                 :            :                              req);
    1699                 :            : }
    1700                 :            : 
    1701                 :            : void
    1702                 :         15 : 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         [ -  + ]:         15 :         assert(cb_fn != NULL);
    1708                 :            : 
    1709         [ -  + ]:         15 :         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                 :         15 :         req = calloc(1, sizeof(*req));
    1716         [ -  + ]:         15 :         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                 :         15 :         req->cb_fn = cb_fn;
    1723                 :         15 :         req->cb_arg = cb_arg;
    1724                 :         15 :         req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
    1725         [ -  + ]:         15 :         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                 :         15 :         blob_id = spdk_blob_get_id(lvol->blob);
    1733                 :         15 :         spdk_bs_blob_decouple_parent(lvol->lvol_store->blobstore, req->channel, blob_id,
    1734                 :            :                                      lvol_inflate_cb, req);
    1735                 :            : }
    1736                 :            : 
    1737                 :            : static void
    1738                 :          2 : lvs_grow_live_cb(void *cb_arg, int lvolerrno)
    1739                 :            : {
    1740                 :          2 :         struct spdk_lvs_req *req = (struct spdk_lvs_req *)cb_arg;
    1741                 :            : 
    1742         [ +  - ]:          2 :         if (req->cb_fn) {
    1743                 :          2 :                 req->cb_fn(req->cb_arg, lvolerrno);
    1744                 :            :         }
    1745                 :          2 :         free(req);
    1746                 :          2 :         return;
    1747                 :            : }
    1748                 :            : 
    1749                 :            : void
    1750                 :          2 : 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                 :          2 :         req = calloc(1, sizeof(*req));
    1755         [ -  + ]:          2 :         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                 :          2 :         req->cb_fn = cb_fn;
    1764                 :          2 :         req->cb_arg = cb_arg;
    1765                 :          2 :         req->lvol_store = lvs;
    1766                 :            : 
    1767                 :          2 :         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                 :         58 : lvs_get_lvol_by_blob_id(struct spdk_lvol_store *lvs, spdk_blob_id blob_id)
    1810                 :            : {
    1811                 :            :         struct spdk_lvol *lvol;
    1812                 :            : 
    1813         [ +  - ]:         79 :         TAILQ_FOREACH(lvol, &lvs->lvols, link) {
    1814         [ +  + ]:         79 :                 if (lvol->blob_id == blob_id) {
    1815                 :         58 :                         return lvol;
    1816                 :            :                 }
    1817                 :            :         }
    1818                 :          0 :         return NULL;
    1819                 :            : }
    1820                 :            : 
    1821                 :            : static int
    1822                 :         93 : 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                 :         93 :         struct spdk_lvol_store  *lvs = bs_ctx;
    1827                 :         93 :         struct spdk_lvol        *lvol = blob_ctx;
    1828                 :         93 :         spdk_blob_id            blob_id = spdk_blob_get_id(blob);
    1829                 :            : 
    1830         [ +  + ]:         93 :         if (lvs == NULL) {
    1831         [ +  + ]:         12 :                 if (lvol == NULL) {
    1832                 :          6 :                         SPDK_ERRLOG("Blob 0x%" PRIx64 ": no lvs context nor lvol context\n",
    1833                 :            :                                     blob_id);
    1834                 :          6 :                         return -EINVAL;
    1835                 :            :                 }
    1836                 :          6 :                 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   [ +  +  +  + ]:         87 :         if (!lvs->load_esnaps) {
    1847                 :         62 :                 *bs_dev = NULL;
    1848                 :         62 :                 return 0;
    1849                 :            :         }
    1850                 :            : 
    1851         [ +  + ]:         25 :         if (lvol == NULL) {
    1852                 :         19 :                 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                 :         19 :                 lvol = lvs_get_lvol_by_blob_id(lvs, blob_id);
    1860         [ -  + ]:         19 :                 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                 :         25 :         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                 :        561 : lvs_esnap_name_cmp(struct spdk_lvs_degraded_lvol_set *m1, struct spdk_lvs_degraded_lvol_set *m2)
    1893                 :            : {
    1894         [ +  - ]:        561 :         if (m1->id_len == m2->id_len) {
    1895   [ -  +  -  + ]:        561 :                 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   [ +  +  +  +  :       3264 : RB_GENERATE_STATIC(degraded_lvol_sets_tree, spdk_lvs_degraded_lvol_set, node, lvs_esnap_name_cmp)
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  -  
          -  -  -  -  -  
          -  +  +  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
          -  -  +  +  -  
          -  -  -  -  -  
          -  -  -  -  -  
                -  -  - ]
    1901                 :            : 
    1902                 :            : static void
    1903                 :        236 : lvs_degraded_lvol_set_add(struct spdk_lvs_degraded_lvol_set *degraded_set, struct spdk_lvol *lvol)
    1904                 :            : {
    1905         [ -  + ]:        236 :         assert(lvol->lvol_store->thread == spdk_get_thread());
    1906                 :            : 
    1907                 :        236 :         lvol->degraded_set = degraded_set;
    1908                 :        236 :         TAILQ_INSERT_TAIL(&degraded_set->lvols, lvol, degraded_link);
    1909                 :        236 : }
    1910                 :            : 
    1911                 :            : static void
    1912                 :         83 : lvs_degraded_lvol_set_remove(struct spdk_lvs_degraded_lvol_set *degraded_set,
    1913                 :            :                              struct spdk_lvol *lvol)
    1914                 :            : {
    1915         [ -  + ]:         83 :         assert(lvol->lvol_store->thread == spdk_get_thread());
    1916                 :            : 
    1917                 :         83 :         lvol->degraded_set = NULL;
    1918         [ +  + ]:         83 :         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                 :         83 : }
    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                 :        223 : 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                 :        187 :         struct spdk_lvs_degraded_lvol_set find, *degraded_set;
    1932                 :            : 
    1933         [ -  + ]:        223 :         assert(lvs->thread == spdk_get_thread());
    1934                 :            : 
    1935                 :        223 :         find.esnap_id = esnap_id;
    1936                 :        223 :         find.id_len = id_len;
    1937                 :        223 :         degraded_set = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
    1938         [ +  + ]:        223 :         if (degraded_set == NULL) {
    1939                 :        103 :                 degraded_set = calloc(1, sizeof(*degraded_set));
    1940         [ -  + ]:        103 :                 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                 :        103 :                 degraded_set->esnap_id = calloc(1, id_len);
    1946         [ -  + ]:        103 :                 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   [ -  +  -  + ]:        103 :                 memcpy((void *)degraded_set->esnap_id, esnap_id, id_len);
    1953                 :        103 :                 degraded_set->id_len = id_len;
    1954                 :        103 :                 degraded_set->lvol_store = lvs;
    1955                 :        103 :                 TAILQ_INIT(&degraded_set->lvols);
    1956                 :        103 :                 RB_INSERT(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
    1957                 :            :         }
    1958                 :            : 
    1959                 :        223 :         lvs_degraded_lvol_set_add(degraded_set, lvol);
    1960                 :            : 
    1961                 :        223 :         return 0;
    1962                 :            : }
    1963                 :            : 
    1964                 :            : /*
    1965                 :            :  * Remove the record of the specified lvol needing a degraded_set bdev.
    1966                 :            :  */
    1967                 :            : void
    1968                 :        548 : spdk_lvs_esnap_missing_remove(struct spdk_lvol *lvol)
    1969                 :            : {
    1970                 :        548 :         struct spdk_lvol_store          *lvs = lvol->lvol_store;
    1971                 :        548 :         struct spdk_lvs_degraded_lvol_set       *degraded_set = lvol->degraded_set;
    1972                 :            : 
    1973         [ -  + ]:        548 :         assert(lvs->thread == spdk_get_thread());
    1974                 :            : 
    1975         [ +  + ]:        548 :         if (degraded_set == NULL) {
    1976                 :        478 :                 return;
    1977                 :            :         }
    1978                 :            : 
    1979                 :         70 :         lvs_degraded_lvol_set_remove(degraded_set, lvol);
    1980                 :            : 
    1981         [ +  + ]:         70 :         if (!TAILQ_EMPTY(&degraded_set->lvols)) {
    1982                 :          6 :                 return;
    1983                 :            :         }
    1984                 :            : 
    1985                 :         64 :         RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
    1986                 :            : 
    1987                 :         64 :         free((char *)degraded_set->esnap_id);
    1988                 :         64 :         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                 :        153 : lvs_esnap_hotplug_done(void *cb_arg, int bserrno)
    1999                 :            : {
    2000                 :        153 :         struct lvs_esnap_hotplug_req *req = cb_arg;
    2001                 :        153 :         struct spdk_lvol        *lvol = req->lvol;
    2002                 :        153 :         struct spdk_lvol_store  *lvs = lvol->lvol_store;
    2003                 :            : 
    2004         [ -  + ]:        153 :         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                 :        153 :         req->cb_fn(req->cb_arg, lvol, bserrno);
    2009                 :        153 :         free(req);
    2010                 :        153 : }
    2011                 :            : 
    2012                 :            : static void
    2013                 :         93 : 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                 :         93 :         struct spdk_lvol_store  *lvs = degraded_set->lvol_store;
    2017                 :            :         struct spdk_lvol        *lvol, *tmp, *last_missing;
    2018                 :         78 :         struct spdk_bs_dev      *bs_dev;
    2019                 :         93 :         const void              *esnap_id = degraded_set->esnap_id;
    2020                 :         93 :         uint32_t                id_len = degraded_set->id_len;
    2021                 :            :         struct lvs_esnap_hotplug_req *req;
    2022                 :            :         int                     rc;
    2023                 :            : 
    2024         [ -  + ]:         93 :         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                 :         93 :         last_missing = TAILQ_LAST(&degraded_set->lvols, degraded_lvols);
    2039                 :            : 
    2040         [ +  - ]:        171 :         TAILQ_FOREACH_SAFE(lvol, &degraded_set->lvols, degraded_link, tmp) {
    2041                 :        171 :                 req = calloc(1, sizeof(*req));
    2042         [ -  + ]:        171 :                 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         [ +  + ]:        171 :                 TAILQ_REMOVE(&degraded_set->lvols, lvol, degraded_link);
    2057                 :        171 :                 lvol->degraded_set = NULL;
    2058                 :            : 
    2059                 :        171 :                 bs_dev = NULL;
    2060                 :        171 :                 rc = lvs->esnap_bs_dev_create(lvs, lvol, lvol->blob, esnap_id, id_len, &bs_dev);
    2061         [ +  + ]:        171 :                 if (rc != 0) {
    2062                 :         18 :                         SPDK_ERRLOG("lvol %s: failed to create esnap bs_dev: error %d\n",
    2063                 :            :                                     lvol->unique_id, rc);
    2064                 :         18 :                         lvol->degraded_set = degraded_set;
    2065                 :         18 :                         TAILQ_INSERT_TAIL(&degraded_set->lvols, lvol, degraded_link);
    2066                 :         18 :                         cb_fn(cb_arg, lvol, rc);
    2067                 :         18 :                         free(req);
    2068                 :         18 :                         goto next;
    2069                 :            :                 }
    2070                 :            : 
    2071                 :        153 :                 req->lvol = lvol;
    2072                 :        153 :                 req->cb_fn = cb_fn;
    2073                 :        153 :                 req->cb_arg = cb_arg;
    2074                 :        153 :                 spdk_blob_set_esnap_bs_dev(lvol->blob, bs_dev, lvs_esnap_hotplug_done, req);
    2075                 :            : 
    2076                 :        171 : next:
    2077         [ +  + ]:        171 :                 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                 :         93 :                         break;
    2083                 :            :                 }
    2084                 :            :         }
    2085                 :            : 
    2086         [ +  + ]:         93 :         if (TAILQ_EMPTY(&degraded_set->lvols)) {
    2087                 :         39 :                 RB_REMOVE(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, degraded_set);
    2088                 :         39 :                 free((void *)degraded_set->esnap_id);
    2089                 :         39 :                 free(degraded_set);
    2090                 :            :         }
    2091                 :         93 : }
    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                 :       6280 : 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                 :       6280 :         struct spdk_lvs_degraded_lvol_set find = { 0 };
    2103                 :            :         struct spdk_lvol_store  *lvs;
    2104                 :       6280 :         struct spdk_thread      *thread = spdk_get_thread();
    2105                 :       6280 :         bool                    ret = false;
    2106                 :            : 
    2107                 :       6280 :         find.esnap_id = esnap_id;
    2108                 :       6280 :         find.id_len = id_len;
    2109                 :            : 
    2110         [ -  + ]:       6280 :         pthread_mutex_lock(&g_lvol_stores_mutex);
    2111         [ +  + ]:       8158 :         TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
    2112         [ -  + ]:       1878 :                 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                 :       1878 :                 found = RB_FIND(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree, &find);
    2127         [ +  + ]:       1878 :                 if (found == NULL) {
    2128                 :       1785 :                         continue;
    2129                 :            :                 }
    2130                 :            : 
    2131                 :         93 :                 ret = true;
    2132                 :         93 :                 lvs_esnap_degraded_hotplug(found, cb_fn, cb_arg);
    2133                 :            :         }
    2134         [ -  + ]:       6280 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
    2135                 :            : 
    2136                 :       6280 :         return ret;
    2137                 :            : }
    2138                 :            : 
    2139                 :            : int
    2140                 :         29 : spdk_lvol_iter_immediate_clones(struct spdk_lvol *lvol, spdk_lvol_iter_cb cb_fn, void *cb_arg)
    2141                 :            : {
    2142                 :         29 :         struct spdk_lvol_store *lvs = lvol->lvol_store;
    2143                 :         29 :         struct spdk_blob_store *bs = lvs->blobstore;
    2144                 :            :         struct spdk_lvol *clone;
    2145                 :            :         spdk_blob_id *ids;
    2146                 :         29 :         size_t id_cnt = 0;
    2147                 :            :         size_t i;
    2148                 :            :         int rc;
    2149                 :            : 
    2150                 :         29 :         rc = spdk_blob_get_clones(bs, lvol->blob_id, NULL, &id_cnt);
    2151         [ +  + ]:         29 :         if (rc != -ENOMEM) {
    2152                 :            :                 /* -ENOMEM says id_cnt is valid, no other errors should be returned. */
    2153         [ -  + ]:          9 :                 assert(rc == 0);
    2154                 :          9 :                 return rc;
    2155                 :            :         }
    2156                 :            : 
    2157                 :         20 :         ids = calloc(id_cnt, sizeof(*ids));
    2158         [ -  + ]:         20 :         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                 :         20 :         rc = spdk_blob_get_clones(bs, lvol->blob_id, ids, &id_cnt);
    2164         [ -  + ]:         20 :         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         [ +  + ]:         40 :         for (i = 0; i < id_cnt; i++) {
    2171                 :         26 :                 clone = lvs_get_lvol_by_blob_id(lvs, ids[i]);
    2172         [ -  + ]:         26 :                 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                 :         26 :                 rc = cb_fn(cb_arg, clone);
    2178         [ +  + ]:         26 :                 if (rc != 0) {
    2179   [ -  +  -  + ]:          6 :                         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                 :          6 :                         break;
    2183                 :            :                 }
    2184                 :            :         }
    2185                 :            : 
    2186                 :         20 :         free(ids);
    2187                 :         20 :         return rc;
    2188                 :            : }
    2189                 :            : 
    2190                 :            : struct spdk_lvol *
    2191                 :         14 : spdk_lvol_get_by_uuid(const struct spdk_uuid *uuid)
    2192                 :            : {
    2193                 :            :         struct spdk_lvol_store *lvs;
    2194                 :            :         struct spdk_lvol *lvol;
    2195                 :            : 
    2196         [ -  + ]:         14 :         pthread_mutex_lock(&g_lvol_stores_mutex);
    2197                 :            : 
    2198         [ +  - ]:         14 :         TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
    2199         [ +  - ]:         15 :                 TAILQ_FOREACH(lvol, &lvs->lvols, link) {
    2200         [ +  + ]:         15 :                         if (spdk_uuid_compare(uuid, &lvol->uuid) == 0) {
    2201         [ -  + ]:         14 :                                 pthread_mutex_unlock(&g_lvol_stores_mutex);
    2202                 :         14 :                                 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                 :        230 : 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                 :        230 :         pthread_mutex_lock(&g_lvol_stores_mutex);
    2218                 :            : 
    2219         [ +  + ]:        316 :         TAILQ_FOREACH(lvs, &g_lvol_stores, link) {
    2220   [ +  +  -  +  :        199 :                 if (strcmp(lvs_name, lvs->name) != 0) {
                   +  + ]
    2221                 :         18 :                         continue;
    2222                 :            :                 }
    2223         [ +  + ]:        218 :                 TAILQ_FOREACH(lvol, &lvs->lvols, link) {
    2224   [ +  +  -  +  :        150 :                         if (strcmp(lvol_name, lvol->name) == 0) {
                   +  + ]
    2225                 :        113 :                                 pthread_mutex_unlock(&g_lvol_stores_mutex);
    2226                 :        113 :                                 return lvol;
    2227                 :            :                         }
    2228                 :            :                 }
    2229                 :            :         }
    2230                 :            : 
    2231                 :        117 :         pthread_mutex_unlock(&g_lvol_stores_mutex);
    2232                 :        117 :         return NULL;
    2233                 :            : }
    2234                 :            : 
    2235                 :            : bool
    2236                 :        873 : spdk_lvol_is_degraded(const struct spdk_lvol *lvol)
    2237                 :            : {
    2238                 :        873 :         struct spdk_blob *blob = lvol->blob;
    2239                 :            : 
    2240         [ -  + ]:        873 :         if (blob == NULL) {
    2241                 :          0 :                 return true;
    2242                 :            :         }
    2243                 :        873 :         return spdk_blob_is_degraded(blob);
    2244                 :            : }

Generated by: LCOV version 1.14