LCOV - code coverage report
Current view: top level - spdk/test/lvol/esnap - esnap.c (source / functions) Hit Total Coverage
Test: Combined Lines: 485 500 97.0 %
Date: 2024-07-12 19:47:42 Functions: 22 23 95.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 111 212 52.4 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
       3                 :            :  */
       4                 :            : 
       5                 :            : #include "spdk/stdinc.h"
       6                 :            : #include "spdk_internal/cunit.h"
       7                 :            : #include "spdk/string.h"
       8                 :            : #include "spdk/init.h"
       9                 :            : 
      10                 :            : #include "common/lib/ut_multithread.c"
      11                 :            : 
      12                 :            : #include "bdev/bdev.c"
      13                 :            : #include "lvol/lvol.c"
      14                 :            : #include "bdev/malloc/bdev_malloc.c"
      15                 :            : #include "bdev/lvol/vbdev_lvol.c"
      16                 :            : #include "accel/accel_sw.c"
      17                 :            : #include "bdev/part.c"
      18                 :            : #include "blob/blobstore.h"
      19                 :            : #include "bdev/aio/bdev_aio.h"
      20                 :            : 
      21                 :            : #include "unit/lib/json_mock.c"
      22                 :            : 
      23                 :            : #ifdef SPDK_CONFIG_PMDK
      24                 :            : DEFINE_STUB(pmem_msync, int, (const void *addr, size_t len), 0);
      25                 :            : DEFINE_STUB(pmem_memcpy_persist, void *, (void *pmemdest, const void *src, size_t len), NULL);
      26                 :            : DEFINE_STUB(pmem_is_pmem, int, (const void *addr, size_t len), 0);
      27                 :            : DEFINE_STUB(pmem_memset_persist, void *, (void *pmemdest, int c, size_t len), NULL);
      28                 :            : #endif
      29                 :            : 
      30                 :            : char g_testdir[PATH_MAX];
      31                 :            : 
      32                 :            : static void
      33                 :          1 : set_testdir(const char *path)
      34                 :            : {
      35                 :            :         char *tmp;
      36                 :            : 
      37                 :          1 :         tmp = realpath(path, NULL);
      38   [ +  -  -  + ]:          1 :         snprintf(g_testdir, sizeof(g_testdir), "%s", tmp ? dirname(tmp) : ".");
      39                 :          1 :         free(tmp);
      40                 :          1 : }
      41                 :            : 
      42                 :            : static int
      43                 :          3 : make_test_file(size_t size, char *path, size_t len, const char *name)
      44                 :            : {
      45                 :            :         int fd;
      46                 :            :         int rc;
      47                 :            : 
      48                 :          3 :         CU_ASSERT(len <= INT32_MAX);
      49         [ -  + ]:          3 :         if (snprintf(path, len, "%s/%s", g_testdir, name) >= (int)len) {
      50                 :          0 :                 return -ENAMETOOLONG;
      51                 :            :         }
      52         [ -  + ]:          3 :         unlink(path);
      53         [ -  + ]:          3 :         fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
      54         [ -  + ]:          3 :         if (fd < 0) {
      55                 :          0 :                 return -errno;
      56                 :            :         }
      57                 :          3 :         rc = ftruncate(fd, size);
      58         [ -  + ]:          3 :         if (rc != 0) {
      59                 :          0 :                 rc = -errno;
      60         [ #  # ]:          0 :                 unlink(path);
      61                 :            :         }
      62                 :          3 :         close(fd);
      63                 :          3 :         return rc;
      64                 :            : }
      65                 :            : 
      66                 :            : static void
      67                 :          8 : unregister_cb(void *ctx, int bdeverrno)
      68                 :            : {
      69                 :          8 :         int *rc = ctx;
      70                 :            : 
      71         [ +  - ]:          8 :         if (rc != NULL) {
      72                 :          8 :                 *rc = bdeverrno;
      73                 :            :         }
      74                 :          8 : }
      75                 :            : 
      76                 :            : struct op_with_handle_data {
      77                 :            :         union {
      78                 :            :                 struct spdk_lvol_store *lvs;
      79                 :            :                 struct spdk_lvol *lvol;
      80                 :            :         } u;
      81                 :            :         int lvserrno;
      82                 :            : };
      83                 :            : 
      84                 :            : static struct op_with_handle_data *
      85                 :         10 : clear_owh(struct op_with_handle_data *owh)
      86                 :            : {
      87         [ -  + ]:         10 :         memset(owh, 0, sizeof(*owh));
      88                 :         10 :         owh->lvserrno = 0xbad;
      89                 :            : 
      90                 :         10 :         return owh;
      91                 :            : }
      92                 :            : 
      93                 :            : /* spdk_poll_threads() doesn't have visibility into uncompleted aio operations. */
      94                 :            : static void
      95                 :         23 : poll_error_updated(int *error)
      96                 :            : {
      97         [ +  + ]:       2327 :         while (*error == 0xbad) {
      98                 :       2304 :                 poll_threads();
      99                 :            :         }
     100                 :         23 : }
     101                 :            : 
     102                 :            : static void
     103                 :          4 : lvs_op_with_handle_cb(void *cb_arg, struct spdk_lvol_store *lvs, int lvserrno)
     104                 :            : {
     105                 :          4 :         struct op_with_handle_data *data = cb_arg;
     106                 :            : 
     107                 :          4 :         data->u.lvs = lvs;
     108                 :          4 :         data->lvserrno = lvserrno;
     109                 :          4 : }
     110                 :            : 
     111                 :            : static void
     112                 :          6 : lvol_op_with_handle_cb(void *cb_arg, struct spdk_lvol *lvol, int lvserrno)
     113                 :            : {
     114                 :          6 :         struct op_with_handle_data *data = cb_arg;
     115                 :            : 
     116                 :          6 :         data->u.lvol = lvol;
     117                 :          6 :         data->lvserrno = lvserrno;
     118                 :          6 : }
     119                 :            : 
     120                 :            : static void
     121                 :         60 : lvol_op_complete_cb(void *cb_arg, int lvolerrno)
     122                 :            : {
     123                 :         60 :         int *err = cb_arg;
     124                 :            : 
     125                 :         60 :         *err = lvolerrno;
     126                 :         60 : }
     127                 :            : 
     128                 :            : static void
     129                 :          0 : ut_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
     130                 :            : {
     131                 :          0 : }
     132                 :            : 
     133                 :            : static void
     134                 :        171 : io_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
     135                 :            : {
     136                 :        171 :         int *err = cb_arg;
     137                 :            : 
     138                 :        171 :         spdk_bdev_free_io(bdev_io);
     139         [ -  + ]:        171 :         SPDK_CU_ASSERT_FATAL(success);
     140                 :            : 
     141                 :        171 :         *err = 0;
     142                 :        171 : }
     143                 :            : 
     144                 :            : static void
     145                 :        203 : prepare_block(char *buf, size_t bufsz, const char *uuid_str, uint64_t block)
     146                 :            : {
     147         [ -  + ]:        203 :         memset(buf, 0, bufsz);
     148         [ -  + ]:        203 :         snprintf(buf, bufsz, "%s %8" PRIu64, uuid_str, block);
     149                 :        203 : }
     150                 :            : 
     151                 :            : static void
     152                 :          3 : scribble(struct spdk_bdev_desc *desc, uint64_t start, uint64_t count)
     153                 :          3 : {
     154                 :          3 :         struct spdk_bdev *bdev = desc->bdev;
     155                 :          3 :         const uint32_t blocklen = desc->bdev->blocklen;
     156                 :          3 :         struct spdk_io_channel *ch = spdk_bdev_get_io_channel(desc);
     157                 :          3 :         char uuid_str[SPDK_UUID_STRING_LEN];
     158   [ -  +  -  + ]:          3 :         char buf[count][blocklen];
     159                 :          3 :         int err = 0xbad;
     160                 :            :         uint64_t i;
     161                 :            : 
     162   [ +  -  +  -  :          3 :         SPDK_CU_ASSERT_FATAL(count > 0 && count < INT32_MAX);
                   -  + ]
     163         [ -  + ]:          3 :         SPDK_CU_ASSERT_FATAL(ch != NULL);
     164                 :            : 
     165                 :          3 :         spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &bdev->uuid);
     166                 :            : 
     167         [ +  + ]:         38 :         for (i = 0; i < count; i++) {
     168                 :         35 :                 prepare_block(buf[i], sizeof(buf[i]), uuid_str, start + i);
     169                 :            :         }
     170                 :            : 
     171                 :          3 :         spdk_bdev_write(desc, ch, buf, start * blocklen, sizeof(buf), io_done, &err);
     172                 :          3 :         poll_threads();
     173         [ -  + ]:          3 :         SPDK_CU_ASSERT_FATAL(err == 0);
     174                 :          3 :         spdk_put_io_channel(ch);
     175                 :          3 :         poll_threads();
     176                 :          3 : }
     177                 :            : 
     178                 :            : #define verify(desc, bdev, start, count) _verify(desc, bdev, start, count, __FILE__, __LINE__)
     179                 :            : 
     180                 :            : static bool
     181                 :         12 : _verify(struct spdk_bdev_desc *desc, struct spdk_bdev *bdev, uint64_t start, uint64_t count,
     182                 :            :         const char *file, int line)
     183                 :         12 : {
     184                 :         12 :         struct spdk_io_channel *ch = spdk_bdev_get_io_channel(desc);
     185                 :         12 :         const uint32_t blocklen = desc->bdev->blocklen;
     186                 :         12 :         char uuid_str[SPDK_UUID_STRING_LEN];
     187         [ -  + ]:         12 :         char buf[blocklen];
     188         [ -  + ]:         12 :         char expect[blocklen];
     189                 :         12 :         int err = 0xbad;
     190                 :         12 :         bool ret = true;
     191                 :            :         uint64_t i;
     192                 :            : 
     193   [ +  -  +  -  :         12 :         SPDK_CU_ASSERT_FATAL(count > 0 && count < INT32_MAX);
                   -  + ]
     194         [ -  + ]:         12 :         SPDK_CU_ASSERT_FATAL(ch != NULL);
     195                 :            : 
     196                 :         12 :         spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &bdev->uuid);
     197                 :            : 
     198         [ +  + ]:        180 :         for (i = 0; i < count; i++) {
     199                 :        168 :                 uint64_t block = start + i;
     200                 :            : 
     201                 :        168 :                 spdk_bdev_read(desc, ch, buf, block * blocklen, sizeof(buf), io_done, &err);
     202                 :        168 :                 poll_threads();
     203         [ -  + ]:        168 :                 SPDK_CU_ASSERT_FATAL(err == 0);
     204                 :        168 :                 prepare_block(expect, sizeof(expect), uuid_str, block);
     205   [ -  +  -  +  :        168 :                 if (memcmp(expect, buf, blocklen) != 0) {
                   -  + ]
     206                 :          0 :                         printf("%s:%d: ERROR: expected '%s' got '%s'\n", file, line,
     207                 :            :                                expect, buf);
     208                 :          0 :                         ret = false;
     209                 :            :                 }
     210                 :            :         }
     211                 :            : 
     212                 :         12 :         spdk_put_io_channel(ch);
     213                 :         12 :         poll_threads();
     214                 :            : 
     215                 :         12 :         return ret;
     216                 :            : }
     217                 :            : 
     218                 :            : static bool
     219                 :         12 : cluster_is_allocated(struct spdk_blob *blob, uint32_t cluster)
     220                 :            : {
     221                 :         12 :         return bs_io_unit_is_allocated(blob, cluster * blob->bs->pages_per_cluster);
     222                 :            : }
     223                 :            : 
     224                 :            : static void
     225                 :          1 : esnap_clone_io(void)
     226                 :            : {
     227                 :          1 :         struct spdk_lvol_store *lvs = NULL;
     228                 :          1 :         struct spdk_bdev *bs_bdev = NULL;
     229                 :          1 :         struct spdk_bdev *esnap_bdev = NULL;
     230                 :          1 :         struct spdk_bdev *lvol_bdev = NULL;
     231                 :          1 :         struct spdk_bdev_desc *esnap_desc = NULL;
     232                 :          1 :         struct spdk_bdev_desc *lvol_desc = NULL;
     233                 :          1 :         const char bs_malloc_uuid[SPDK_UUID_STRING_LEN] = "11110049-cf29-4681-ab4b-5dd16de6cd81";
     234                 :          1 :         const char esnap_uuid[SPDK_UUID_STRING_LEN] = "222251be-1ece-434d-8513-6944d5c93a53";
     235                 :          1 :         struct malloc_bdev_opts malloc_opts = { 0 };
     236                 :          1 :         const uint32_t bs_size_bytes = 10 * 1024 * 1024;
     237                 :          1 :         const uint32_t bs_block_size = 4096;
     238                 :          1 :         const uint32_t cluster_size = 32 * 1024;
     239         [ -  + ]:          1 :         const uint32_t blocks_per_cluster = cluster_size / bs_block_size;
     240                 :          1 :         const uint32_t esnap_size_bytes = 4 * cluster_size;
     241                 :          1 :         struct op_with_handle_data owh_data = { 0 };
     242                 :            :         struct lvol_bdev *_lvol_bdev;
     243                 :            :         struct spdk_blob *blob;
     244                 :            :         int rc;
     245                 :            : 
     246                 :          1 :         g_bdev_opts.bdev_auto_examine = false;
     247                 :            : 
     248                 :            :         /* Create device for lvstore */
     249                 :          1 :         spdk_uuid_parse(&malloc_opts.uuid, bs_malloc_uuid);
     250                 :          1 :         malloc_opts.name = "bs_malloc";
     251         [ -  + ]:          1 :         malloc_opts.num_blocks = bs_size_bytes / bs_block_size;
     252                 :          1 :         malloc_opts.block_size = bs_block_size;
     253                 :          1 :         rc = create_malloc_disk(&bs_bdev, &malloc_opts);
     254         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     255                 :            : 
     256                 :            :         /* Create lvstore */
     257                 :          1 :         rc = vbdev_lvs_create("bs_malloc", "lvs1", cluster_size, 0, 0,
     258                 :          1 :                               lvs_op_with_handle_cb, clear_owh(&owh_data));
     259         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     260                 :          1 :         poll_error_updated(&owh_data.lvserrno);
     261         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.lvserrno == 0);
     262         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.u.lvs != NULL);
     263                 :          1 :         lvs = owh_data.u.lvs;
     264                 :            : 
     265                 :            :         /* Create esnap device */
     266         [ -  + ]:          1 :         memset(&malloc_opts, 0, sizeof(malloc_opts));
     267                 :          1 :         spdk_uuid_parse(&malloc_opts.uuid, esnap_uuid);
     268                 :          1 :         malloc_opts.name = "esnap_malloc";
     269         [ -  + ]:          1 :         malloc_opts.num_blocks = esnap_size_bytes / bs_block_size;
     270                 :          1 :         malloc_opts.block_size = bs_block_size;
     271                 :          1 :         rc = create_malloc_disk(&esnap_bdev, &malloc_opts);
     272         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     273                 :            : 
     274                 :            :         /* Fill esnap device with pattern */
     275                 :          1 :         rc = spdk_bdev_open_ext(esnap_uuid, true, ut_event_cb, NULL, &esnap_desc);
     276         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     277                 :          1 :         scribble(esnap_desc, 0, esnap_bdev->blockcnt);
     278                 :            : 
     279                 :            :         /* Reopen the external snapshot read-only for verification later */
     280                 :          1 :         spdk_bdev_close(esnap_desc);
     281                 :          1 :         poll_threads();
     282                 :          1 :         rc = spdk_bdev_open_ext(esnap_uuid, false, ut_event_cb, NULL, &esnap_desc);
     283         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     284                 :            : 
     285                 :            :         /* Create esnap clone */
     286                 :          1 :         vbdev_lvol_create_bdev_clone(esnap_uuid, lvs, "clone1",
     287                 :          1 :                                      lvol_op_with_handle_cb, clear_owh(&owh_data));
     288                 :          1 :         poll_error_updated(&owh_data.lvserrno);
     289         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.lvserrno == 0);
     290         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.u.lvol != NULL);
     291                 :            : 
     292                 :            :         /* Open the esnap clone */
     293                 :          1 :         rc = spdk_bdev_open_ext("lvs1/clone1", true, ut_event_cb, NULL, &lvol_desc);
     294         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     295                 :          1 :         lvol_bdev = lvol_desc->bdev;
     296                 :          1 :         _lvol_bdev = (struct lvol_bdev *)lvol_bdev;
     297                 :          1 :         blob = _lvol_bdev->lvol->blob;
     298                 :          1 :         CU_ASSERT(blob->active.num_clusters == 4);
     299                 :          1 :         CU_ASSERT(!cluster_is_allocated(blob, 0));
     300                 :          1 :         CU_ASSERT(!cluster_is_allocated(blob, 1));
     301                 :          1 :         CU_ASSERT(!cluster_is_allocated(blob, 2));
     302                 :          1 :         CU_ASSERT(!cluster_is_allocated(blob, 3));
     303                 :            : 
     304                 :            :         /* Be sure the esnap and the clone see the same content. */
     305                 :          1 :         CU_ASSERT(verify(esnap_desc, esnap_bdev, 0, esnap_bdev->blockcnt));
     306                 :          1 :         CU_ASSERT(verify(lvol_desc, esnap_bdev, 0, esnap_bdev->blockcnt));
     307                 :            : 
     308                 :            :         /* Overwrite the second block of the first cluster then verify the whole first cluster */
     309                 :          1 :         scribble(lvol_desc, 1, 1);
     310                 :          1 :         CU_ASSERT(cluster_is_allocated(blob, 0));
     311                 :          1 :         CU_ASSERT(!cluster_is_allocated(blob, 1));
     312                 :          1 :         CU_ASSERT(!cluster_is_allocated(blob, 2));
     313                 :          1 :         CU_ASSERT(!cluster_is_allocated(blob, 3));
     314                 :          1 :         CU_ASSERT(verify(lvol_desc, esnap_bdev, 0, 1));
     315                 :          1 :         CU_ASSERT(verify(lvol_desc, lvol_bdev, 1, 1));
     316                 :          1 :         CU_ASSERT(verify(lvol_desc, esnap_bdev, 2, blocks_per_cluster - 2));
     317                 :            :         /* And be sure no writes made it to the external snapshot */
     318                 :          1 :         CU_ASSERT(verify(esnap_desc, esnap_bdev, 0, esnap_bdev->blockcnt));
     319                 :            : 
     320                 :            :         /* Overwrite the two blocks that span the end of the first cluster and the start of the
     321                 :            :          * second cluster
     322                 :            :          */
     323                 :          1 :         scribble(lvol_desc, blocks_per_cluster - 1, 2);
     324                 :            :         /* The first part of the first cluster was written previously - it should be the same. */
     325                 :          1 :         CU_ASSERT(cluster_is_allocated(blob, 0));
     326                 :          1 :         CU_ASSERT(cluster_is_allocated(blob, 1));
     327                 :          1 :         CU_ASSERT(!cluster_is_allocated(blob, 2));
     328                 :          1 :         CU_ASSERT(!cluster_is_allocated(blob, 3));
     329                 :          1 :         CU_ASSERT(verify(lvol_desc, esnap_bdev, 0, 1));
     330                 :          1 :         CU_ASSERT(verify(lvol_desc, lvol_bdev, 1, 1));
     331                 :          1 :         CU_ASSERT(verify(lvol_desc, esnap_bdev, 2, blocks_per_cluster - 2 - 1));
     332                 :            :         /* Check the newly written area spanning the first two clusters. */
     333                 :          1 :         CU_ASSERT(verify(lvol_desc, lvol_bdev, blocks_per_cluster - 1, 2));
     334                 :            :         /* The rest should not have changed. */
     335                 :          1 :         CU_ASSERT(verify(lvol_desc, esnap_bdev, blocks_per_cluster + 1,
     336                 :            :                          esnap_bdev->blockcnt - blocks_per_cluster - 1));
     337                 :            :         /* And be sure no writes made it to the external snapshot */
     338                 :          1 :         CU_ASSERT(verify(esnap_desc, esnap_bdev, 0, esnap_bdev->blockcnt));
     339                 :            : 
     340                 :            :         /* Clean up */
     341                 :          1 :         bdev_close(lvol_bdev, lvol_desc);
     342                 :          1 :         bdev_close(esnap_bdev, esnap_desc);
     343                 :          1 :         delete_malloc_disk("esnap_malloc", NULL, 0);
     344                 :            :         /* This triggers spdk_lvs_unload() */
     345                 :          1 :         delete_malloc_disk("bs_malloc", NULL, 0);
     346                 :          1 :         poll_threads();
     347                 :          1 : }
     348                 :            : 
     349                 :            : static void
     350                 :          2 : esnap_wait_for_examine(void *ctx)
     351                 :            : {
     352                 :          2 :         int *flag = ctx;
     353                 :            : 
     354                 :          2 :         *flag = 0;
     355                 :          2 : }
     356                 :            : 
     357                 :            : static void
     358                 :          1 : esnap_hotplug(void)
     359                 :            : {
     360                 :          1 :         const char *uuid_esnap = "22218fb6-6743-483d-88b1-de643dc7c0bc";
     361                 :          1 :         struct malloc_bdev_opts malloc_opts = { 0 };
     362                 :          1 :         const uint32_t bs_size_bytes = 10 * 1024 * 1024;
     363                 :          1 :         const uint32_t bs_block_size = 4096;
     364                 :          1 :         const uint32_t cluster_size = 32 * 1024;
     365                 :          1 :         const uint32_t esnap_size_bytes = 2 * cluster_size;
     366                 :          1 :         struct op_with_handle_data owh_data = { 0 };
     367                 :          1 :         struct spdk_bdev *malloc_bdev = NULL, *bdev;
     368                 :            :         struct spdk_lvol_store *lvs;
     369                 :            :         struct spdk_lvol *lvol;
     370                 :          1 :         char aiopath[PATH_MAX];
     371                 :          1 :         int rc, rc2;
     372                 :            : 
     373                 :          1 :         g_bdev_opts.bdev_auto_examine = true;
     374                 :            : 
     375                 :            :         /* Create aio device to hold the lvstore. */
     376                 :          1 :         rc = make_test_file(bs_size_bytes, aiopath, sizeof(aiopath), "esnap_hotplug.aio");
     377         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     378                 :          1 :         rc = create_aio_bdev("aio1", aiopath, bs_block_size, false, false);
     379         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     380                 :          1 :         poll_threads();
     381                 :            : 
     382                 :          1 :         rc = vbdev_lvs_create("aio1", "lvs1", cluster_size, 0, 0,
     383                 :          1 :                               lvs_op_with_handle_cb, clear_owh(&owh_data));
     384         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     385                 :          1 :         poll_error_updated(&owh_data.lvserrno);
     386         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.lvserrno == 0);
     387         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.u.lvs != NULL);
     388                 :          1 :         lvs = owh_data.u.lvs;
     389                 :            : 
     390                 :            :         /* Create esnap device */
     391                 :          1 :         spdk_uuid_parse(&malloc_opts.uuid, uuid_esnap);
     392                 :          1 :         malloc_opts.name = "esnap_malloc";
     393         [ -  + ]:          1 :         malloc_opts.num_blocks = esnap_size_bytes / bs_block_size;
     394                 :          1 :         malloc_opts.block_size = bs_block_size;
     395                 :          1 :         rc = create_malloc_disk(&malloc_bdev, &malloc_opts);
     396         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     397                 :            : 
     398                 :            :         /* Create esnap clone */
     399                 :          1 :         vbdev_lvol_create_bdev_clone(uuid_esnap, lvs, "clone1",
     400                 :          1 :                                      lvol_op_with_handle_cb, clear_owh(&owh_data));
     401                 :          1 :         poll_error_updated(&owh_data.lvserrno);
     402         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.lvserrno == 0);
     403         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.u.lvol != NULL);
     404                 :            : 
     405                 :            :         /* Verify that lvol bdev exists */
     406                 :          1 :         bdev = spdk_bdev_get_by_name("lvs1/clone1");
     407         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(bdev != NULL);
     408                 :            : 
     409                 :            :         /* Unload the lvstore and verify the bdev is gone. */
     410                 :          1 :         rc = rc2 = 0xbad;
     411                 :          1 :         bdev_aio_delete("aio1", unregister_cb, &rc);
     412                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name(uuid_esnap) != NULL)
     413                 :          1 :         delete_malloc_disk(malloc_bdev->name, unregister_cb, &rc2);
     414                 :          1 :         malloc_bdev = NULL;
     415                 :          1 :         poll_error_updated(&rc);
     416                 :          1 :         poll_error_updated(&rc2);
     417         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     418         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc2 == 0);
     419         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(spdk_bdev_get_by_name("lvs1/clone1") == NULL);
     420         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(spdk_bdev_get_by_name(uuid_esnap) == NULL);
     421                 :            : 
     422                 :            :         /* Trigger the reload of the lvstore */
     423                 :          1 :         rc = create_aio_bdev("aio1", aiopath, bs_block_size, false, false);
     424         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     425                 :          1 :         rc = 0xbad;
     426                 :          1 :         spdk_bdev_wait_for_examine(esnap_wait_for_examine, &rc);
     427                 :          1 :         poll_error_updated(&rc);
     428                 :            : 
     429                 :            :         /* Verify the lvol is loaded without creating a bdev. */
     430                 :          1 :         lvol = spdk_lvol_get_by_names("lvs1", "clone1");
     431                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/clone1") == NULL)
     432         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(lvol != NULL);
     433         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(lvol->degraded_set != NULL);
     434                 :            : 
     435                 :            :         /* Create the esnap device and verify that the bdev is created. */
     436                 :          1 :         rc = create_malloc_disk(&malloc_bdev, &malloc_opts);
     437         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     438                 :          1 :         poll_threads();
     439                 :          1 :         CU_ASSERT(malloc_bdev != NULL);
     440                 :          1 :         CU_ASSERT(lvol->degraded_set == NULL);
     441                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/clone1") != NULL);
     442                 :            : 
     443                 :            :         /* Clean up */
     444                 :          1 :         rc = rc2 = 0xbad;
     445                 :          1 :         bdev_aio_delete("aio1", unregister_cb, &rc);
     446                 :          1 :         poll_error_updated(&rc);
     447                 :          1 :         CU_ASSERT(rc == 0);
     448         [ +  - ]:          1 :         if (malloc_bdev != NULL) {
     449                 :          1 :                 delete_malloc_disk(malloc_bdev->name, unregister_cb, &rc2);
     450                 :          1 :                 poll_threads();
     451                 :          1 :                 CU_ASSERT(rc2 == 0);
     452                 :            :         }
     453         [ -  + ]:          1 :         rc = unlink(aiopath);
     454                 :          1 :         CU_ASSERT(rc == 0);
     455                 :          1 : }
     456                 :            : 
     457                 :            : static void
     458                 :          1 : esnap_remove_degraded(void)
     459                 :            : {
     460                 :          1 :         const char *uuid_esnap = "33358eb9-3dcf-4275-b089-0becc126fc3d";
     461                 :          1 :         struct malloc_bdev_opts malloc_opts = { 0 };
     462                 :          1 :         const uint32_t bs_size_bytes = 10 * 1024 * 1024;
     463                 :          1 :         const uint32_t bs_block_size = 4096;
     464                 :          1 :         const uint32_t cluster_size = 32 * 1024;
     465                 :          1 :         const uint32_t esnap_size_bytes = 2 * cluster_size;
     466                 :          1 :         struct op_with_handle_data owh_data = { 0 };
     467                 :            :         struct spdk_lvol_store *lvs;
     468                 :          1 :         struct spdk_bdev *malloc_bdev = NULL;
     469                 :            :         struct spdk_lvol *vol1, *vol2, *vol3;
     470                 :          1 :         char aiopath[PATH_MAX];
     471                 :          1 :         int rc, rc2;
     472                 :            : 
     473                 :          1 :         g_bdev_opts.bdev_auto_examine = true;
     474                 :            : 
     475                 :            :         /* Create aio device to hold the lvstore. */
     476                 :          1 :         rc = make_test_file(bs_size_bytes, aiopath, sizeof(aiopath), "remove_degraded.aio");
     477         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     478                 :          1 :         rc = create_aio_bdev("aio1", aiopath, bs_block_size, false, false);
     479         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     480                 :          1 :         poll_threads();
     481                 :            : 
     482                 :          1 :         rc = vbdev_lvs_create("aio1", "lvs1", cluster_size, 0, 0,
     483                 :          1 :                               lvs_op_with_handle_cb, clear_owh(&owh_data));
     484         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     485                 :          1 :         poll_error_updated(&owh_data.lvserrno);
     486         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.lvserrno == 0);
     487         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.u.lvs != NULL);
     488                 :          1 :         lvs = owh_data.u.lvs;
     489                 :            : 
     490                 :            :         /* Create esnap device */
     491                 :          1 :         spdk_uuid_parse(&malloc_opts.uuid, uuid_esnap);
     492                 :          1 :         malloc_opts.name = "esnap";
     493         [ -  + ]:          1 :         malloc_opts.num_blocks = esnap_size_bytes / bs_block_size;
     494                 :          1 :         malloc_opts.block_size = bs_block_size;
     495                 :          1 :         rc = create_malloc_disk(&malloc_bdev, &malloc_opts);
     496         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     497                 :            : 
     498                 :            :         /* Create a snapshot of vol1.
     499                 :            :          * State:
     500                 :            :          *   esnap <-- vol1
     501                 :            :          */
     502                 :          1 :         vbdev_lvol_create_bdev_clone(uuid_esnap, lvs, "vol1",
     503                 :          1 :                                      lvol_op_with_handle_cb, clear_owh(&owh_data));
     504                 :          1 :         poll_error_updated(&owh_data.lvserrno);
     505         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.lvserrno == 0);
     506         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.u.lvol != NULL);
     507                 :          1 :         vol1 = owh_data.u.lvol;
     508                 :            : 
     509                 :            :         /* Create a snapshot of vol1.
     510                 :            :          * State:
     511                 :            :          *   esnap <-- vol2 <-- vol1
     512                 :            :          */
     513                 :          1 :         vbdev_lvol_create_snapshot(vol1, "vol2", lvol_op_with_handle_cb, clear_owh(&owh_data));
     514                 :          1 :         poll_error_updated(&owh_data.lvserrno);
     515         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.lvserrno == 0);
     516         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.u.lvol != NULL);
     517                 :          1 :         vol2 = owh_data.u.lvol;
     518                 :            : 
     519                 :            :         /* Create a clone of vol2.
     520                 :            :          * State:
     521                 :            :          *   esnap <-- vol2 <-- vol1
     522                 :            :          *                `---- vol3
     523                 :            :          */
     524                 :          1 :         vbdev_lvol_create_clone(vol2, "vol3", lvol_op_with_handle_cb, clear_owh(&owh_data));
     525                 :          1 :         poll_error_updated(&owh_data.lvserrno);
     526         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.lvserrno == 0);
     527         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.u.lvol != NULL);
     528                 :          1 :         vol3 = owh_data.u.lvol;
     529                 :            : 
     530                 :            :         /* Unload the lvstore and delete esnap */
     531                 :          1 :         rc = rc2 = 0xbad;
     532                 :          1 :         bdev_aio_delete("aio1", unregister_cb, &rc);
     533                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name(uuid_esnap) != NULL)
     534                 :          1 :         delete_malloc_disk(malloc_bdev->name, unregister_cb, &rc2);
     535                 :          1 :         malloc_bdev = NULL;
     536                 :          1 :         poll_error_updated(&rc);
     537                 :          1 :         poll_error_updated(&rc2);
     538         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     539         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc2 == 0);
     540                 :            : 
     541                 :            :         /* Trigger the reload of the lvstore.
     542                 :            :          * State:
     543                 :            :          *   (missing) <-- vol2 <-- vol1
     544                 :            :          *                    `---- vol3
     545                 :            :          */
     546                 :          1 :         rc = create_aio_bdev("aio1", aiopath, bs_block_size, false, false);
     547         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     548                 :          1 :         rc = 0xbad;
     549                 :          1 :         spdk_bdev_wait_for_examine(esnap_wait_for_examine, &rc);
     550                 :          1 :         poll_error_updated(&rc);
     551                 :            : 
     552                 :            :         /* Verify vol1 is as described in diagram above */
     553                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/vol1") == NULL);
     554                 :          1 :         vol1 = spdk_lvol_get_by_names("lvs1", "vol1");
     555         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(vol1 != NULL);
     556                 :          1 :         lvs = vol1->lvol_store;
     557                 :          1 :         CU_ASSERT(spdk_blob_is_clone(vol1->blob));
     558                 :          1 :         CU_ASSERT(!spdk_blob_is_esnap_clone(vol1->blob));
     559                 :          1 :         CU_ASSERT(!spdk_blob_is_snapshot(vol1->blob));
     560                 :          1 :         CU_ASSERT(vol1->degraded_set == NULL);
     561                 :            : 
     562                 :            :         /* Verify vol2 is as described in diagram above */
     563                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/vol2") == NULL);
     564                 :          1 :         vol2 = spdk_lvol_get_by_names("lvs1", "vol2");
     565         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(vol2 != NULL);
     566                 :          1 :         CU_ASSERT(!spdk_blob_is_clone(vol2->blob));
     567                 :          1 :         CU_ASSERT(spdk_blob_is_esnap_clone(vol2->blob));
     568                 :          1 :         CU_ASSERT(spdk_blob_is_snapshot(vol2->blob));
     569                 :          1 :         CU_ASSERT(RB_MIN(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree) == vol2->degraded_set);
     570                 :          1 :         CU_ASSERT(TAILQ_FIRST(&vol2->degraded_set->lvols) == vol2);
     571                 :            : 
     572                 :            :         /* Verify vol3 is as described in diagram above */
     573                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/vol3") == NULL);
     574                 :          1 :         vol3 = spdk_lvol_get_by_names("lvs1", "vol3");
     575         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(vol3 != NULL);
     576                 :          1 :         CU_ASSERT(spdk_blob_is_clone(vol3->blob));
     577                 :          1 :         CU_ASSERT(!spdk_blob_is_esnap_clone(vol3->blob));
     578                 :          1 :         CU_ASSERT(!spdk_blob_is_snapshot(vol3->blob));
     579                 :          1 :         CU_ASSERT(vol3->degraded_set == NULL);
     580                 :            : 
     581                 :            :         /* Try to delete vol2. Should fail because it has multiple clones. */
     582                 :          1 :         rc = 0xbad;
     583                 :          1 :         vbdev_lvol_destroy(vol2, lvol_op_complete_cb, &rc);
     584                 :          1 :         poll_error_updated(&rc);
     585                 :          1 :         CU_ASSERT(rc == -EPERM);
     586                 :            : 
     587                 :            :         /* Delete vol1
     588                 :            :          * New state:
     589                 :            :          *   (missing) <-- vol2 <-- vol3
     590                 :            :          */
     591                 :          1 :         rc = 0xbad;
     592                 :          1 :         vbdev_lvol_destroy(vol1, lvol_op_complete_cb, &rc);
     593                 :          1 :         poll_error_updated(&rc);
     594                 :          1 :         CU_ASSERT(rc == 0);
     595                 :            : 
     596                 :            :         /* Verify vol1 is gone */
     597                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/vol1") == NULL);
     598                 :          1 :         vol1 = spdk_lvol_get_by_names("lvs1", "vol1");
     599                 :          1 :         CU_ASSERT(vol1 == NULL);
     600                 :            : 
     601                 :            :         /* Verify vol2 is as described in diagram above */
     602                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/vol2") == NULL);
     603                 :          1 :         vol2 = spdk_lvol_get_by_names("lvs1", "vol2");
     604         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(vol2 != NULL);
     605                 :          1 :         CU_ASSERT(!spdk_blob_is_clone(vol2->blob));
     606                 :          1 :         CU_ASSERT(spdk_blob_is_esnap_clone(vol2->blob));
     607                 :          1 :         CU_ASSERT(spdk_blob_is_snapshot(vol2->blob));
     608                 :          1 :         CU_ASSERT(RB_MIN(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree) == vol2->degraded_set);
     609                 :          1 :         CU_ASSERT(TAILQ_FIRST(&vol2->degraded_set->lvols) == vol2);
     610                 :            : 
     611                 :            :         /* Verify vol3 is as described in diagram above */
     612                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/vol3") == NULL);
     613                 :          1 :         vol3 = spdk_lvol_get_by_names("lvs1", "vol3");
     614         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(vol3 != NULL);
     615                 :          1 :         CU_ASSERT(spdk_blob_is_clone(vol3->blob));
     616                 :          1 :         CU_ASSERT(!spdk_blob_is_esnap_clone(vol3->blob));
     617                 :          1 :         CU_ASSERT(!spdk_blob_is_snapshot(vol3->blob));
     618                 :          1 :         CU_ASSERT(vol3->degraded_set == NULL);
     619                 :            : 
     620                 :            :         /* Delete vol2
     621                 :            :          * New state:
     622                 :            :          *   (missing) <-- vol3
     623                 :            :          */
     624                 :          1 :         rc = 0xbad;
     625                 :          1 :         vbdev_lvol_destroy(vol2, lvol_op_complete_cb, &rc);
     626                 :          1 :         poll_error_updated(&rc);
     627                 :          1 :         CU_ASSERT(rc == 0);
     628                 :            : 
     629                 :            :         /* Verify vol2 is gone */
     630                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/vol2") == NULL);
     631                 :          1 :         vol2 = spdk_lvol_get_by_names("lvs1", "vol2");
     632         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(vol2 == NULL);
     633                 :            : 
     634                 :            :         /* Verify vol3 is as described in diagram above */
     635                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/vol3") == NULL);
     636                 :          1 :         vol3 = spdk_lvol_get_by_names("lvs1", "vol3");
     637         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(vol3 != NULL);
     638                 :          1 :         CU_ASSERT(!spdk_blob_is_clone(vol3->blob));
     639                 :          1 :         CU_ASSERT(spdk_blob_is_esnap_clone(vol3->blob));
     640                 :          1 :         CU_ASSERT(!spdk_blob_is_snapshot(vol3->blob));
     641                 :          1 :         CU_ASSERT(RB_MIN(degraded_lvol_sets_tree, &lvs->degraded_lvol_sets_tree) == vol3->degraded_set);
     642                 :          1 :         CU_ASSERT(TAILQ_FIRST(&vol3->degraded_set->lvols) == vol3);
     643                 :            : 
     644                 :            :         /* Delete vol3
     645                 :            :          * New state:
     646                 :            :          *   (nothing)
     647                 :            :          */
     648                 :          1 :         rc = 0xbad;
     649                 :          1 :         vbdev_lvol_destroy(vol3, lvol_op_complete_cb, &rc);
     650                 :          1 :         poll_error_updated(&rc);
     651                 :          1 :         CU_ASSERT(rc == 0);
     652                 :            : 
     653                 :            :         /* Verify vol3 is gone */
     654                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/vol3") == NULL);
     655                 :          1 :         vol3 = spdk_lvol_get_by_names("lvs1", "vol3");
     656         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(vol3 == NULL);
     657                 :            : 
     658                 :            :         /* Nothing depends on the missing bdev, so it is no longer missing. */
     659                 :          1 :         CU_ASSERT(RB_EMPTY(&lvs->degraded_lvol_sets_tree));
     660                 :            : 
     661                 :            :         /* Clean up */
     662                 :          1 :         rc = rc2 = 0xbad;
     663                 :          1 :         bdev_aio_delete("aio1", unregister_cb, &rc);
     664                 :          1 :         poll_error_updated(&rc);
     665                 :          1 :         CU_ASSERT(rc == 0);
     666         [ -  + ]:          1 :         if (malloc_bdev != NULL) {
     667                 :          0 :                 delete_malloc_disk(malloc_bdev->name, unregister_cb, &rc2);
     668                 :          0 :                 poll_threads();
     669                 :          0 :                 CU_ASSERT(rc2 == 0);
     670                 :            :         }
     671         [ -  + ]:          1 :         rc = unlink(aiopath);
     672                 :          1 :         CU_ASSERT(rc == 0);
     673                 :          1 : }
     674                 :            : 
     675                 :            : static void
     676                 :          1 : late_delete(void)
     677                 :            : {
     678                 :          1 :         char aiopath[PATH_MAX];
     679                 :          1 :         struct spdk_lvol_store *lvs = NULL;
     680                 :          1 :         const uint32_t bs_size_bytes = 10 * 1024 * 1024;
     681                 :          1 :         const uint32_t bs_block_size = 4096;
     682                 :          1 :         const uint32_t cluster_size = 32 * 1024;
     683                 :          1 :         struct op_with_handle_data owh_data;
     684                 :            :         struct lvol_bdev *lvol_bdev;
     685                 :            :         struct spdk_lvol *lvol;
     686                 :          1 :         int rc, rc2;
     687                 :            :         int count;
     688                 :            : 
     689                 :            :         /* Create device for lvstore. This cannot be a malloc bdev because we need to sneak a
     690                 :            :          * deletion in while blob_persist() is in progress.
     691                 :            :          */
     692                 :          1 :         rc = make_test_file(bs_size_bytes, aiopath, sizeof(aiopath), "late_delete.aio");
     693         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     694                 :          1 :         rc = create_aio_bdev("aio1", aiopath, bs_block_size, false, false);
     695         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     696                 :          1 :         poll_threads();
     697                 :            : 
     698                 :            :         /* Create lvstore */
     699                 :          1 :         rc = vbdev_lvs_create("aio1", "lvs1", cluster_size, 0, 0,
     700                 :          1 :                               lvs_op_with_handle_cb, clear_owh(&owh_data));
     701         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(rc == 0);
     702                 :          1 :         poll_error_updated(&owh_data.lvserrno);
     703         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.lvserrno == 0);
     704         [ -  + ]:          1 :         SPDK_CU_ASSERT_FATAL(owh_data.u.lvs != NULL);
     705                 :          1 :         lvs = owh_data.u.lvs;
     706                 :            : 
     707                 :            :         /* Create an lvol */
     708                 :          1 :         vbdev_lvol_create(lvs, "lvol", 1, true, LVOL_CLEAR_WITH_DEFAULT,
     709                 :          1 :                           lvol_op_with_handle_cb, clear_owh(&owh_data));
     710                 :          1 :         poll_error_updated(&owh_data.lvserrno);
     711                 :          1 :         CU_ASSERT(owh_data.lvserrno == 0);
     712                 :          1 :         CU_ASSERT(owh_data.u.lvol != NULL);
     713                 :            : 
     714                 :            :         /* Verify the lvol can be found both ways */
     715                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/lvol") != NULL);
     716                 :          1 :         CU_ASSERT(spdk_lvol_get_by_names("lvs1", "lvol") != NULL);
     717                 :            : 
     718                 :            :         /*
     719                 :            :          * Once the lvolstore deletion starts, it will briefly be possible to look up lvol bdevs and
     720                 :            :          * degraded lvols in that lvolstore but any attempt to delete them will fail with -ENODEV.
     721                 :            :          */
     722                 :          1 :         rc = 0xbad;
     723                 :          1 :         count = 0;
     724                 :          1 :         vbdev_lvs_destruct(lvs, lvol_op_complete_cb, &rc);
     725                 :            :         do {
     726                 :        125 :                 lvol_bdev = (struct lvol_bdev *)spdk_bdev_get_by_name("lvs1/lvol");
     727         [ +  + ]:        125 :                 if (lvol_bdev != NULL) {
     728                 :          2 :                         rc2 = 0xbad;
     729                 :          2 :                         vbdev_lvol_destroy(lvol_bdev->lvol, lvol_op_complete_cb, &rc2);
     730                 :          2 :                         CU_ASSERT(rc2 == -ENODEV);
     731                 :            :                 }
     732                 :        125 :                 lvol = spdk_lvol_get_by_names("lvs1", "lvol");
     733         [ +  + ]:        125 :                 if (lvol != NULL) {
     734                 :            :                         /* If we are here, we are likely reproducing #2998 */
     735                 :         53 :                         rc2 = 0xbad;
     736                 :         53 :                         vbdev_lvol_destroy(lvol, lvol_op_complete_cb, &rc2);
     737                 :         53 :                         CU_ASSERT(rc2 == -ENODEV);
     738                 :         53 :                         count++;
     739                 :            :                 }
     740                 :            : 
     741                 :        125 :                 spdk_thread_poll(g_ut_threads[0].thread, 0, 0);
     742         [ +  + ]:        125 :         } while (rc == 0xbad);
     743                 :            : 
     744                 :            :         /* Ensure that the test exercised the race */
     745                 :          1 :         CU_ASSERT(count != 0);
     746                 :            : 
     747                 :            :         /* The lvol is now gone */
     748                 :          1 :         CU_ASSERT(spdk_bdev_get_by_name("lvs1/lvol") == NULL);
     749                 :          1 :         CU_ASSERT(spdk_lvol_get_by_names("lvs1", "lvol") == NULL);
     750                 :            : 
     751                 :            :         /* Clean up */
     752                 :          1 :         rc = 0xbad;
     753                 :          1 :         bdev_aio_delete("aio1", unregister_cb, &rc);
     754                 :          1 :         poll_error_updated(&rc);
     755                 :          1 :         CU_ASSERT(rc == 0);
     756         [ -  + ]:          1 :         rc = unlink(aiopath);
     757                 :          1 :         CU_ASSERT(rc == 0);
     758                 :          1 : }
     759                 :            : 
     760                 :            : static void
     761                 :          1 : bdev_init_cb(void *arg, int rc)
     762                 :            : {
     763         [ -  + ]:          1 :         assert(rc == 0);
     764                 :          1 : }
     765                 :            : 
     766                 :            : static void
     767                 :          1 : subsystem_init_cb(int rc, void *ctx)
     768                 :            : {
     769         [ -  + ]:          1 :         assert(rc == 0);
     770                 :          1 : }
     771                 :            : 
     772                 :            : static void
     773                 :          3 : bdev_fini_cb(void *arg)
     774                 :            : {
     775                 :          3 : }
     776                 :            : 
     777                 :            : int
     778                 :          1 : main(int argc, char **argv)
     779                 :            : {
     780                 :          1 :         CU_pSuite       suite = NULL;
     781                 :            :         unsigned int    num_failures;
     782                 :            :         int rc;
     783                 :            : 
     784                 :          1 :         set_testdir(argv[0]);
     785                 :            : 
     786                 :          1 :         CU_initialize_registry();
     787                 :            : 
     788                 :          1 :         suite = CU_add_suite("esnap_io", NULL, NULL);
     789                 :            : 
     790                 :          1 :         CU_ADD_TEST(suite, esnap_clone_io);
     791                 :          1 :         CU_ADD_TEST(suite, esnap_hotplug);
     792                 :          1 :         CU_ADD_TEST(suite, esnap_remove_degraded);
     793                 :          1 :         CU_ADD_TEST(suite, late_delete);
     794                 :            : 
     795                 :          1 :         allocate_threads(2);
     796                 :          1 :         set_thread(0);
     797                 :            : 
     798                 :            :         /*
     799                 :            :          * This is a non-standard way of initializing libraries. It works for this test but
     800                 :            :          * shouldn't be used as an example elsewhere, except for maybe other tests.
     801                 :            :          */
     802                 :          1 :         spdk_subsystem_init(subsystem_init_cb, NULL);
     803                 :          1 :         rc = spdk_iobuf_initialize();
     804         [ -  + ]:          1 :         if (rc != 0) {
     805                 :          0 :                 SPDK_ERRLOG("Failed to initialize iobuf\n");
     806                 :          0 :                 abort();
     807                 :            :         }
     808                 :          1 :         rc = spdk_accel_initialize();
     809         [ -  + ]:          1 :         if (rc != 0) {
     810                 :          0 :                 SPDK_ERRLOG("Failed to initialize accel\n");
     811                 :          0 :                 abort();
     812                 :            :         }
     813                 :          1 :         spdk_bdev_initialize(bdev_init_cb, NULL);
     814                 :            : 
     815                 :          1 :         num_failures = spdk_ut_run_tests(argc, argv, NULL);
     816                 :          1 :         CU_cleanup_registry();
     817                 :            : 
     818                 :          1 :         spdk_bdev_finish(bdev_fini_cb, NULL);
     819                 :          1 :         spdk_accel_finish(bdev_fini_cb, NULL);
     820                 :          1 :         spdk_iobuf_finish(bdev_fini_cb, NULL);
     821                 :            : 
     822                 :          1 :         free_threads();
     823                 :            : 
     824                 :          1 :         return num_failures;
     825                 :            : }

Generated by: LCOV version 1.14