diff options
Diffstat (limited to 'src/spdk/test/unit/lib/lvol')
-rw-r--r-- | src/spdk/test/unit/lib/lvol/Makefile | 44 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/lvol/lvol.c/.gitignore | 1 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/lvol/lvol.c/Makefile | 40 | ||||
-rw-r--r-- | src/spdk/test/unit/lib/lvol/lvol.c/lvol_ut.c | 2127 |
4 files changed, 2212 insertions, 0 deletions
diff --git a/src/spdk/test/unit/lib/lvol/Makefile b/src/spdk/test/unit/lib/lvol/Makefile new file mode 100644 index 00000000..c9276de4 --- /dev/null +++ b/src/spdk/test/unit/lib/lvol/Makefile @@ -0,0 +1,44 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk + +DIRS-y = lvol.c + +.PHONY: all clean $(DIRS-y) + +all: $(DIRS-y) +clean: $(DIRS-y) + +include $(SPDK_ROOT_DIR)/mk/spdk.subdirs.mk diff --git a/src/spdk/test/unit/lib/lvol/lvol.c/.gitignore b/src/spdk/test/unit/lib/lvol/lvol.c/.gitignore new file mode 100644 index 00000000..57e92bfe --- /dev/null +++ b/src/spdk/test/unit/lib/lvol/lvol.c/.gitignore @@ -0,0 +1 @@ +lvol_ut diff --git a/src/spdk/test/unit/lib/lvol/lvol.c/Makefile b/src/spdk/test/unit/lib/lvol/lvol.c/Makefile new file mode 100644 index 00000000..917f4ef6 --- /dev/null +++ b/src/spdk/test/unit/lib/lvol/lvol.c/Makefile @@ -0,0 +1,40 @@ +# +# BSD LICENSE +# +# Copyright (c) Intel Corporation. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..) +include $(SPDK_ROOT_DIR)/mk/spdk.common.mk +include $(SPDK_ROOT_DIR)/mk/spdk.app.mk + +TEST_FILE = lvol_ut.c + +include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk diff --git a/src/spdk/test/unit/lib/lvol/lvol.c/lvol_ut.c b/src/spdk/test/unit/lib/lvol/lvol.c/lvol_ut.c new file mode 100644 index 00000000..0aebbe1a --- /dev/null +++ b/src/spdk/test/unit/lib/lvol/lvol.c/lvol_ut.c @@ -0,0 +1,2127 @@ +/*- + * BSD LICENSE + * + * Copyright (c) Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "spdk_cunit.h" +#include "spdk/blob.h" +#include "spdk/thread.h" +#include "spdk/util.h" + +#include "common/lib/test_env.c" + +#include "lvol/lvol.c" + +#define DEV_BUFFER_SIZE (64 * 1024 * 1024) +#define DEV_BUFFER_BLOCKLEN (4096) +#define DEV_BUFFER_BLOCKCNT (DEV_BUFFER_SIZE / DEV_BUFFER_BLOCKLEN) +#define BS_CLUSTER_SIZE (1024 * 1024) +#define BS_FREE_CLUSTERS (DEV_BUFFER_SIZE / BS_CLUSTER_SIZE) +#define BS_PAGE_SIZE (4096) + +#define SPDK_BLOB_OPTS_CLUSTER_SZ (1024 * 1024) +#define SPDK_BLOB_OPTS_NUM_MD_PAGES UINT32_MAX +#define SPDK_BLOB_OPTS_MAX_MD_OPS 32 +#define SPDK_BLOB_OPTS_MAX_CHANNEL_OPS 512 + +#define SPDK_BLOB_THIN_PROV (1ULL << 0) + +const char *uuid = "828d9766-ae50-11e7-bd8d-001e67edf350"; + +struct spdk_blob { + spdk_blob_id id; + uint32_t ref; + struct spdk_blob_store *bs; + int close_status; + int open_status; + int load_status; + TAILQ_ENTRY(spdk_blob) link; + char uuid[SPDK_UUID_STRING_LEN]; + char name[SPDK_LVS_NAME_MAX]; + bool thin_provisioned; +}; + +int g_lvolerrno; +int g_lvserrno; +int g_close_super_status; +int g_resize_rc; +int g_inflate_rc; +bool g_lvs_rename_blob_open_error = false; +struct spdk_lvol_store *g_lvol_store; +struct spdk_lvol *g_lvol; +spdk_blob_id g_blobid = 1; +struct spdk_io_channel *g_io_channel; + +struct spdk_blob_store { + struct spdk_bs_opts bs_opts; + spdk_blob_id super_blobid; + TAILQ_HEAD(, spdk_blob) blobs; + int get_super_status; +}; + +struct lvol_ut_bs_dev { + struct spdk_bs_dev bs_dev; + int init_status; + int load_status; + struct spdk_blob_store *bs; +}; + +void spdk_bs_inflate_blob(struct spdk_blob_store *bs, struct spdk_io_channel *channel, + spdk_blob_id blobid, spdk_blob_op_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, g_inflate_rc); +} + +void spdk_bs_blob_decouple_parent(struct spdk_blob_store *bs, struct spdk_io_channel *channel, + spdk_blob_id blobid, spdk_blob_op_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, g_inflate_rc); +} + +void +spdk_bs_iter_next(struct spdk_blob_store *bs, struct spdk_blob *b, + spdk_blob_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_blob *next; + int _errno = 0; + + next = TAILQ_NEXT(b, link); + if (next == NULL) { + _errno = -ENOENT; + } else if (next->load_status != 0) { + _errno = next->load_status; + } + + cb_fn(cb_arg, next, _errno); +} + +void +spdk_bs_iter_first(struct spdk_blob_store *bs, + spdk_blob_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_blob *first; + int _errno = 0; + + first = TAILQ_FIRST(&bs->blobs); + if (first == NULL) { + _errno = -ENOENT; + } else if (first->load_status != 0) { + _errno = first->load_status; + } + + cb_fn(cb_arg, first, _errno); +} + +uint64_t spdk_blob_get_num_clusters(struct spdk_blob *blob) +{ + return 0; +} + +void +spdk_bs_get_super(struct spdk_blob_store *bs, + spdk_blob_op_with_id_complete cb_fn, void *cb_arg) +{ + if (bs->get_super_status != 0) { + cb_fn(cb_arg, 0, bs->get_super_status); + } else { + cb_fn(cb_arg, bs->super_blobid, 0); + } +} + +void +spdk_bs_set_super(struct spdk_blob_store *bs, spdk_blob_id blobid, + spdk_bs_op_complete cb_fn, void *cb_arg) +{ + bs->super_blobid = blobid; + cb_fn(cb_arg, 0); +} + +void +spdk_bs_load(struct spdk_bs_dev *dev, struct spdk_bs_opts *opts, + spdk_bs_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct lvol_ut_bs_dev *ut_dev = SPDK_CONTAINEROF(dev, struct lvol_ut_bs_dev, bs_dev); + struct spdk_blob_store *bs = NULL; + + if (ut_dev->load_status == 0) { + bs = ut_dev->bs; + } + + cb_fn(cb_arg, bs, ut_dev->load_status); +} + +struct spdk_io_channel *spdk_bs_alloc_io_channel(struct spdk_blob_store *bs) +{ + if (g_io_channel == NULL) { + g_io_channel = calloc(1, sizeof(struct spdk_io_channel)); + SPDK_CU_ASSERT_FATAL(g_io_channel != NULL); + } + g_io_channel->ref++; + return g_io_channel; +} + +void spdk_bs_free_io_channel(struct spdk_io_channel *channel) +{ + g_io_channel->ref--; + if (g_io_channel->ref == 0) { + free(g_io_channel); + g_io_channel = NULL; + } + return; +} + +int +spdk_blob_set_xattr(struct spdk_blob *blob, const char *name, const void *value, + uint16_t value_len) +{ + if (!strcmp(name, "uuid")) { + CU_ASSERT(value_len == SPDK_UUID_STRING_LEN); + memcpy(blob->uuid, value, SPDK_UUID_STRING_LEN); + } else if (!strcmp(name, "name")) { + CU_ASSERT(value_len <= SPDK_LVS_NAME_MAX); + memcpy(blob->name, value, value_len); + } + + return 0; +} + +int +spdk_blob_get_xattr_value(struct spdk_blob *blob, const char *name, + const void **value, size_t *value_len) +{ + if (!strcmp(name, "uuid") && strnlen(blob->uuid, SPDK_UUID_STRING_LEN) != 0) { + CU_ASSERT(strnlen(blob->uuid, SPDK_UUID_STRING_LEN) == (SPDK_UUID_STRING_LEN - 1)); + *value = blob->uuid; + *value_len = SPDK_UUID_STRING_LEN; + return 0; + } else if (!strcmp(name, "name") && strnlen(blob->name, SPDK_LVS_NAME_MAX) != 0) { + *value = blob->name; + *value_len = strnlen(blob->name, SPDK_LVS_NAME_MAX) + 1; + return 0; + } + + return -ENOENT; +} + +int +spdk_blob_get_clones(struct spdk_blob_store *bs, spdk_blob_id blobid, spdk_blob_id *ids, + size_t *count) +{ + return 0; +} + +uint64_t +spdk_bs_get_page_size(struct spdk_blob_store *bs) +{ + return BS_PAGE_SIZE; +} + +int +spdk_bdev_notify_blockcnt_change(struct spdk_bdev *bdev, uint64_t size) +{ + bdev->blockcnt = size; + return 0; +} + +static void +init_dev(struct lvol_ut_bs_dev *dev) +{ + memset(dev, 0, sizeof(*dev)); + dev->bs_dev.blockcnt = DEV_BUFFER_BLOCKCNT; + dev->bs_dev.blocklen = DEV_BUFFER_BLOCKLEN; +} + +static void +free_dev(struct lvol_ut_bs_dev *dev) +{ + struct spdk_blob_store *bs = dev->bs; + struct spdk_blob *blob, *tmp; + + if (bs == NULL) { + return; + } + + TAILQ_FOREACH_SAFE(blob, &bs->blobs, link, tmp) { + TAILQ_REMOVE(&bs->blobs, blob, link); + free(blob); + } + + free(bs); + dev->bs = NULL; +} + +void +spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o, + spdk_bs_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct lvol_ut_bs_dev *ut_dev = SPDK_CONTAINEROF(dev, struct lvol_ut_bs_dev, bs_dev); + struct spdk_blob_store *bs; + + bs = calloc(1, sizeof(*bs)); + SPDK_CU_ASSERT_FATAL(bs != NULL); + + TAILQ_INIT(&bs->blobs); + + ut_dev->bs = bs; + + memcpy(&bs->bs_opts, o, sizeof(struct spdk_bs_opts)); + + cb_fn(cb_arg, bs, 0); +} + +void +spdk_bs_unload(struct spdk_blob_store *bs, spdk_bs_op_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, 0); +} + +void +spdk_bs_destroy(struct spdk_blob_store *bs, spdk_bs_op_complete cb_fn, + void *cb_arg) +{ + free(bs); + + cb_fn(cb_arg, 0); +} + +void +spdk_bs_delete_blob(struct spdk_blob_store *bs, spdk_blob_id blobid, + spdk_blob_op_complete cb_fn, void *cb_arg) +{ + struct spdk_blob *blob; + + TAILQ_FOREACH(blob, &bs->blobs, link) { + if (blob->id == blobid) { + TAILQ_REMOVE(&bs->blobs, blob, link); + free(blob); + break; + } + } + + cb_fn(cb_arg, 0); +} + +spdk_blob_id +spdk_blob_get_id(struct spdk_blob *blob) +{ + return blob->id; +} + +void +spdk_bs_opts_init(struct spdk_bs_opts *opts) +{ + opts->cluster_sz = SPDK_BLOB_OPTS_CLUSTER_SZ; + opts->num_md_pages = SPDK_BLOB_OPTS_NUM_MD_PAGES; + opts->max_md_ops = SPDK_BLOB_OPTS_MAX_MD_OPS; + opts->max_channel_ops = SPDK_BLOB_OPTS_MAX_CHANNEL_OPS; + memset(&opts->bstype, 0, sizeof(opts->bstype)); +} + +uint64_t +spdk_bs_get_cluster_size(struct spdk_blob_store *bs) +{ + return BS_CLUSTER_SIZE; +} + +void spdk_blob_close(struct spdk_blob *b, spdk_blob_op_complete cb_fn, void *cb_arg) +{ + b->ref--; + + cb_fn(cb_arg, b->close_status); +} + +void +spdk_blob_resize(struct spdk_blob *blob, uint64_t sz, spdk_blob_op_complete cb_fn, void *cb_arg) +{ + if (g_resize_rc != 0) { + return cb_fn(cb_arg, g_resize_rc); + } else if (sz > DEV_BUFFER_SIZE / BS_CLUSTER_SIZE) { + return cb_fn(cb_arg, -ENOMEM); + } + cb_fn(cb_arg, 0); +} + +void +spdk_blob_sync_md(struct spdk_blob *blob, spdk_blob_op_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, 0); +} + +void +spdk_bs_open_blob(struct spdk_blob_store *bs, spdk_blob_id blobid, + spdk_blob_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_blob *blob; + + if (!g_lvs_rename_blob_open_error) { + TAILQ_FOREACH(blob, &bs->blobs, link) { + if (blob->id == blobid) { + blob->ref++; + cb_fn(cb_arg, blob, blob->open_status); + return; + } + } + } + + cb_fn(cb_arg, NULL, -ENOENT); +} + +uint64_t +spdk_bs_free_cluster_count(struct spdk_blob_store *bs) +{ + return BS_FREE_CLUSTERS; +} + +void +spdk_blob_opts_init(struct spdk_blob_opts *opts) +{ + opts->num_clusters = 0; + opts->thin_provision = false; + opts->xattrs.count = 0; + opts->xattrs.names = NULL; + opts->xattrs.ctx = NULL; + opts->xattrs.get_value = NULL; +} + +void +spdk_bs_create_blob(struct spdk_blob_store *bs, + spdk_blob_op_with_id_complete cb_fn, void *cb_arg) +{ + spdk_bs_create_blob_ext(bs, NULL, cb_fn, cb_arg); +} + +void +spdk_bs_create_blob_ext(struct spdk_blob_store *bs, const struct spdk_blob_opts *opts, + spdk_blob_op_with_id_complete cb_fn, void *cb_arg) +{ + struct spdk_blob *b; + + if (opts && opts->num_clusters > DEV_BUFFER_SIZE / BS_CLUSTER_SIZE) { + cb_fn(cb_arg, 0, -1); + return; + } + + b = calloc(1, sizeof(*b)); + SPDK_CU_ASSERT_FATAL(b != NULL); + + b->id = g_blobid++; + if (opts != NULL && opts->thin_provision) { + b->thin_provisioned = true; + } + b->bs = bs; + + TAILQ_INSERT_TAIL(&bs->blobs, b, link); + cb_fn(cb_arg, b->id, 0); +} + +void +spdk_bs_create_snapshot(struct spdk_blob_store *bs, spdk_blob_id blobid, + const struct spdk_blob_xattr_opts *snapshot_xattrs, + spdk_blob_op_with_id_complete cb_fn, void *cb_arg) +{ + spdk_bs_create_blob_ext(bs, NULL, cb_fn, cb_arg); +} + +void +spdk_bs_create_clone(struct spdk_blob_store *bs, spdk_blob_id blobid, + const struct spdk_blob_xattr_opts *clone_xattrs, + spdk_blob_op_with_id_complete cb_fn, void *cb_arg) +{ + spdk_bs_create_blob_ext(bs, NULL, cb_fn, cb_arg); +} + +static void +_lvol_send_msg(spdk_thread_fn fn, void *ctx, void *thread_ctx) +{ + fn(ctx); +} + +static void +lvol_store_op_with_handle_complete(void *cb_arg, struct spdk_lvol_store *lvol_store, int lvserrno) +{ + g_lvol_store = lvol_store; + g_lvserrno = lvserrno; +} + +static void +lvol_op_complete(void *cb_arg, int lvolerrno) +{ + g_lvolerrno = lvolerrno; +} + +static void +lvol_op_with_handle_complete(void *cb_arg, struct spdk_lvol *lvol, int lvserrno) +{ + g_lvol = lvol; + g_lvserrno = lvserrno; +} + +static void +lvol_store_op_complete(void *cb_arg, int lvserrno) +{ + g_lvserrno = lvserrno; +} + +static void +close_cb(void *cb_arg, int lvolerrno) +{ + g_lvserrno = lvolerrno; +} + +static void +destroy_cb(void *cb_arg, int lvolerrno) +{ + g_lvserrno = lvolerrno; +} + +static void +lvs_init_unload_success(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + CU_ASSERT(!TAILQ_EMPTY(&g_lvol_stores)); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + /* Lvol store has an open lvol, this unload should fail. */ + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == -EBUSY); + CU_ASSERT(g_lvserrno == -EBUSY); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + CU_ASSERT(!TAILQ_EMPTY(&g_lvol_stores)); + + /* Lvol has to be closed (or destroyed) before unloading lvol store. */ + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvs_init_destroy_success(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + /* Lvol store contains one lvol, this destroy should fail. */ + g_lvserrno = -1; + rc = spdk_lvs_destroy(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == -EBUSY); + CU_ASSERT(g_lvserrno == -EBUSY); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + spdk_lvol_destroy(g_lvol, destroy_cb, NULL); + + g_lvserrno = -1; + rc = spdk_lvs_destroy(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} + +static void +lvs_init_opts_success(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + g_lvserrno = -1; + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + opts.cluster_sz = 8192; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(dev.bs->bs_opts.cluster_sz == opts.cluster_sz); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvs_unload_lvs_is_null_fail(void) +{ + int rc = 0; + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + g_lvserrno = -1; + rc = spdk_lvs_unload(NULL, lvol_store_op_complete, NULL); + CU_ASSERT(rc == -ENODEV); + CU_ASSERT(g_lvserrno == -1); + + spdk_free_thread(); +} + +static void +lvs_names(void) +{ + struct lvol_ut_bs_dev dev_x, dev_y, dev_x2; + struct spdk_lvs_opts opts_none, opts_x, opts_y, opts_full; + struct spdk_lvol_store *lvs_x, *lvs_y, *lvs_x2; + int rc = 0; + + init_dev(&dev_x); + init_dev(&dev_y); + init_dev(&dev_x2); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts_none); + spdk_lvs_opts_init(&opts_x); + opts_x.name[0] = 'x'; + spdk_lvs_opts_init(&opts_y); + opts_y.name[0] = 'y'; + spdk_lvs_opts_init(&opts_full); + memset(opts_full.name, 'a', sizeof(opts_full.name)); + + /* Test that opts with no name fails spdk_lvs_init(). */ + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + rc = spdk_lvs_init(&dev_x.bs_dev, &opts_none, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc != 0); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + + /* Test that opts with no null terminator for name fails spdk_lvs_init(). */ + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + rc = spdk_lvs_init(&dev_x.bs_dev, &opts_full, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc != 0); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + + /* Test that we can create an lvolstore with name 'x'. */ + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + g_lvol_store = NULL; + rc = spdk_lvs_init(&dev_x.bs_dev, &opts_x, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(!TAILQ_EMPTY(&g_lvol_stores)); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + lvs_x = g_lvol_store; + + /* Test that we can create an lvolstore with name 'y'. */ + g_lvol_store = NULL; + rc = spdk_lvs_init(&dev_y.bs_dev, &opts_y, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + lvs_y = g_lvol_store; + + /* Test that we cannot create another lvolstore with name 'x'. */ + rc = spdk_lvs_init(&dev_x2.bs_dev, &opts_x, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == -EEXIST); + + /* Now destroy lvolstore 'x' and then confirm we can create a new lvolstore with name 'x'. */ + g_lvserrno = -1; + rc = spdk_lvs_destroy(lvs_x, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + rc = spdk_lvs_init(&dev_x.bs_dev, &opts_x, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + lvs_x = g_lvol_store; + + /* + * Unload lvolstore 'x'. Then we should be able to create another lvolstore with name 'x'. + */ + g_lvserrno = -1; + rc = spdk_lvs_unload(lvs_x, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + rc = spdk_lvs_init(&dev_x2.bs_dev, &opts_x, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + lvs_x2 = g_lvol_store; + + /* Confirm that we cannot load the first lvolstore 'x'. */ + g_lvserrno = 0; + spdk_lvs_load(&dev_x.bs_dev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno != 0); + + /* Destroy the second lvolstore 'x'. Then we should be able to load the first lvolstore 'x'. */ + g_lvserrno = -1; + rc = spdk_lvs_destroy(lvs_x2, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + spdk_lvs_load(&dev_x.bs_dev, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + lvs_x = g_lvol_store; + + g_lvserrno = -1; + rc = spdk_lvs_destroy(lvs_x, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_destroy(lvs_y, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + + spdk_free_thread(); +} + +static void +lvol_create_destroy_success(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + spdk_lvol_destroy(g_lvol, destroy_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_create_fail(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvol_store = NULL; + g_lvserrno = 0; + rc = spdk_lvs_init(NULL, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc != 0); + CU_ASSERT(g_lvol_store == NULL); + + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + g_lvol = NULL; + rc = spdk_lvol_create(NULL, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc != 0); + CU_ASSERT(g_lvol == NULL); + + g_lvol = NULL; + rc = spdk_lvol_create(g_lvol_store, "lvol", DEV_BUFFER_SIZE + 1, false, + lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno != 0); + CU_ASSERT(g_lvol == NULL); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_destroy_fail(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + spdk_lvol_destroy(g_lvol, destroy_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_close_fail(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_close_success(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_resize(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_resize_rc = 0; + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + /* Resize to same size */ + spdk_lvol_resize(g_lvol, 10, lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + + /* Resize to smaller size */ + spdk_lvol_resize(g_lvol, 5, lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + + /* Resize to bigger size */ + spdk_lvol_resize(g_lvol, 15, lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + + /* Resize to size = 0 */ + spdk_lvol_resize(g_lvol, 0, lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + + /* Resize to bigger size than available */ + g_lvserrno = 0; + spdk_lvol_resize(g_lvol, 0xFFFFFFFF, lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno != 0); + + /* Fail resize */ + g_resize_rc = -1; + g_lvserrno = 0; + spdk_lvol_resize(g_lvol, 10, lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno != 0); + g_resize_rc = 0; + + g_resize_rc = 0; + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + spdk_lvol_destroy(g_lvol, destroy_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +null_cb(void *ctx, struct spdk_blob_store *bs, int bserrno) +{ + SPDK_CU_ASSERT_FATAL(bs != NULL); +} + +static void +lvs_load(void) +{ + int rc = -1; + struct lvol_ut_bs_dev dev; + struct spdk_lvs_with_handle_req *req; + struct spdk_bs_opts bs_opts = {}; + struct spdk_blob *super_blob; + + req = calloc(1, sizeof(*req)); + SPDK_CU_ASSERT_FATAL(req != NULL); + + init_dev(&dev); + spdk_bs_opts_init(&bs_opts); + snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "LVOLSTORE"); + spdk_bs_init(&dev.bs_dev, &bs_opts, null_cb, NULL); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + /* Fail on bs load */ + dev.load_status = -1; + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno != 0); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + + /* Fail on getting super blob */ + dev.load_status = 0; + dev.bs->get_super_status = -1; + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == -ENODEV); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + + /* Fail on opening super blob */ + g_lvserrno = 0; + super_blob = calloc(1, sizeof(*super_blob)); + super_blob->id = 0x100; + super_blob->open_status = -1; + TAILQ_INSERT_TAIL(&dev.bs->blobs, super_blob, link); + dev.bs->super_blobid = 0x100; + dev.bs->get_super_status = 0; + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == -ENODEV); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + + /* Fail on getting uuid */ + g_lvserrno = 0; + super_blob->open_status = 0; + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == -EINVAL); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + + /* Fail on getting name */ + g_lvserrno = 0; + spdk_blob_set_xattr(super_blob, "uuid", uuid, SPDK_UUID_STRING_LEN); + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == -EINVAL); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + + /* Fail on closing super blob */ + g_lvserrno = 0; + spdk_blob_set_xattr(super_blob, "name", "lvs", strnlen("lvs", SPDK_LVS_NAME_MAX) + 1); + super_blob->close_status = -1; + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == -ENODEV); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + + /* Load successfully */ + g_lvserrno = 0; + super_blob->close_status = 0; + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(g_lvol_store != NULL); + CU_ASSERT(!TAILQ_EMPTY(&g_lvol_stores)); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(TAILQ_EMPTY(&g_lvol_stores)); + + free(req); + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvols_load(void) +{ + int rc = -1; + struct lvol_ut_bs_dev dev; + struct spdk_lvs_with_handle_req *req; + struct spdk_bs_opts bs_opts; + struct spdk_blob *super_blob, *blob1, *blob2, *blob3; + + req = calloc(1, sizeof(*req)); + SPDK_CU_ASSERT_FATAL(req != NULL); + + init_dev(&dev); + spdk_bs_opts_init(&bs_opts); + snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "LVOLSTORE"); + spdk_bs_init(&dev.bs_dev, &bs_opts, null_cb, NULL); + super_blob = calloc(1, sizeof(*super_blob)); + SPDK_CU_ASSERT_FATAL(super_blob != NULL); + super_blob->id = 0x100; + spdk_blob_set_xattr(super_blob, "uuid", uuid, SPDK_UUID_STRING_LEN); + spdk_blob_set_xattr(super_blob, "name", "lvs", strnlen("lvs", SPDK_LVS_NAME_MAX) + 1); + TAILQ_INSERT_TAIL(&dev.bs->blobs, super_blob, link); + dev.bs->super_blobid = 0x100; + + /* + * Create 3 blobs, write different char values to the last char in the UUID + * to make sure they are unique. + */ + blob1 = calloc(1, sizeof(*blob1)); + SPDK_CU_ASSERT_FATAL(blob1 != NULL); + blob1->id = 0x1; + spdk_blob_set_xattr(blob1, "uuid", uuid, SPDK_UUID_STRING_LEN); + spdk_blob_set_xattr(blob1, "name", "lvol1", strnlen("lvol1", SPDK_LVOL_NAME_MAX) + 1); + blob1->uuid[SPDK_UUID_STRING_LEN - 2] = '1'; + + blob2 = calloc(1, sizeof(*blob2)); + SPDK_CU_ASSERT_FATAL(blob2 != NULL); + blob2->id = 0x2; + spdk_blob_set_xattr(blob2, "uuid", uuid, SPDK_UUID_STRING_LEN); + spdk_blob_set_xattr(blob2, "name", "lvol2", strnlen("lvol2", SPDK_LVOL_NAME_MAX) + 1); + blob2->uuid[SPDK_UUID_STRING_LEN - 2] = '2'; + + blob3 = calloc(1, sizeof(*blob3)); + SPDK_CU_ASSERT_FATAL(blob3 != NULL); + blob3->id = 0x2; + spdk_blob_set_xattr(blob3, "uuid", uuid, SPDK_UUID_STRING_LEN); + spdk_blob_set_xattr(blob3, "name", "lvol3", strnlen("lvol3", SPDK_LVOL_NAME_MAX) + 1); + blob3->uuid[SPDK_UUID_STRING_LEN - 2] = '3'; + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + /* Load lvs with 0 blobs */ + g_lvserrno = 0; + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(g_lvol_store != NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + + TAILQ_INSERT_TAIL(&dev.bs->blobs, blob1, link); + TAILQ_INSERT_TAIL(&dev.bs->blobs, blob2, link); + TAILQ_INSERT_TAIL(&dev.bs->blobs, blob3, link); + + /* Load lvs again with 3 blobs, but fail on 1st one */ + g_lvol_store = NULL; + g_lvserrno = 0; + blob1->load_status = -1; + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno != 0); + CU_ASSERT(g_lvol_store == NULL); + + /* Load lvs again with 3 blobs, but fail on 3rd one */ + g_lvol_store = NULL; + g_lvserrno = 0; + blob1->load_status = 0; + blob2->load_status = 0; + blob3->load_status = -1; + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno != 0); + CU_ASSERT(g_lvol_store == NULL); + + /* Load lvs again with 3 blobs, with success */ + g_lvol_store = NULL; + g_lvserrno = 0; + blob1->load_status = 0; + blob2->load_status = 0; + blob3->load_status = 0; + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + CU_ASSERT(!TAILQ_EMPTY(&g_lvol_store->lvols)); + + g_lvserrno = -1; + /* rc = */ spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + /* + * Disable these two asserts for now. lvolstore should allow unload as long + * as the lvols were not opened - but this is coming a future patch. + */ + /* CU_ASSERT(rc == 0); */ + /* CU_ASSERT(g_lvserrno == 0); */ + + free(req); + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_open(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_with_handle_req *req; + struct spdk_bs_opts bs_opts; + struct spdk_blob *super_blob, *blob1, *blob2, *blob3; + struct spdk_lvol *lvol, *tmp; + + req = calloc(1, sizeof(*req)); + SPDK_CU_ASSERT_FATAL(req != NULL); + + init_dev(&dev); + spdk_bs_opts_init(&bs_opts); + snprintf(bs_opts.bstype.bstype, sizeof(bs_opts.bstype.bstype), "LVOLSTORE"); + spdk_bs_init(&dev.bs_dev, &bs_opts, null_cb, NULL); + super_blob = calloc(1, sizeof(*super_blob)); + SPDK_CU_ASSERT_FATAL(super_blob != NULL); + super_blob->id = 0x100; + spdk_blob_set_xattr(super_blob, "uuid", uuid, SPDK_UUID_STRING_LEN); + spdk_blob_set_xattr(super_blob, "name", "lvs", strnlen("lvs", SPDK_LVS_NAME_MAX) + 1); + TAILQ_INSERT_TAIL(&dev.bs->blobs, super_blob, link); + dev.bs->super_blobid = 0x100; + + /* + * Create 3 blobs, write different char values to the last char in the UUID + * to make sure they are unique. + */ + blob1 = calloc(1, sizeof(*blob1)); + SPDK_CU_ASSERT_FATAL(blob1 != NULL); + blob1->id = 0x1; + spdk_blob_set_xattr(blob1, "uuid", uuid, SPDK_UUID_STRING_LEN); + spdk_blob_set_xattr(blob1, "name", "lvol1", strnlen("lvol1", SPDK_LVOL_NAME_MAX) + 1); + blob1->uuid[SPDK_UUID_STRING_LEN - 2] = '1'; + + blob2 = calloc(1, sizeof(*blob2)); + SPDK_CU_ASSERT_FATAL(blob2 != NULL); + blob2->id = 0x2; + spdk_blob_set_xattr(blob2, "uuid", uuid, SPDK_UUID_STRING_LEN); + spdk_blob_set_xattr(blob2, "name", "lvol2", strnlen("lvol2", SPDK_LVOL_NAME_MAX) + 1); + blob2->uuid[SPDK_UUID_STRING_LEN - 2] = '2'; + + blob3 = calloc(1, sizeof(*blob3)); + SPDK_CU_ASSERT_FATAL(blob3 != NULL); + blob3->id = 0x2; + spdk_blob_set_xattr(blob3, "uuid", uuid, SPDK_UUID_STRING_LEN); + spdk_blob_set_xattr(blob3, "name", "lvol3", strnlen("lvol3", SPDK_LVOL_NAME_MAX) + 1); + blob3->uuid[SPDK_UUID_STRING_LEN - 2] = '3'; + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + TAILQ_INSERT_TAIL(&dev.bs->blobs, blob1, link); + TAILQ_INSERT_TAIL(&dev.bs->blobs, blob2, link); + TAILQ_INSERT_TAIL(&dev.bs->blobs, blob3, link); + + /* Load lvs with 3 blobs */ + g_lvol_store = NULL; + g_lvserrno = 0; + spdk_lvs_load(&dev.bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&g_lvol_stores)); + + blob1->open_status = -1; + blob2->open_status = -1; + blob3->open_status = -1; + + /* Fail opening all lvols */ + TAILQ_FOREACH_SAFE(lvol, &g_lvol_store->lvols, link, tmp) { + spdk_lvol_open(lvol, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno != 0); + } + + blob1->open_status = 0; + blob2->open_status = 0; + blob3->open_status = 0; + + /* Open all lvols */ + TAILQ_FOREACH_SAFE(lvol, &g_lvol_store->lvols, link, tmp) { + spdk_lvol_open(lvol, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + } + + /* Close all lvols */ + TAILQ_FOREACH_SAFE(lvol, &g_lvol_store->lvols, link, tmp) { + spdk_lvol_close(lvol, lvol_op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + } + + g_lvserrno = -1; + spdk_lvs_destroy(g_lvol_store, lvol_store_op_complete, NULL); + + free(req); + free(blob1); + free(blob2); + free(blob3); + + spdk_free_thread(); +} + +static void +lvol_snapshot(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvol *lvol; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, true, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + lvol = g_lvol; + + spdk_lvol_create_snapshot(lvol, "snap", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + CU_ASSERT_STRING_EQUAL(g_lvol->name, "snap"); + + /* Lvol has to be closed (or destroyed) before unloading lvol store. */ + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + + spdk_lvol_close(lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_snapshot_fail(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvol *lvol, *snap; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, true, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + lvol = g_lvol; + + spdk_lvol_create_snapshot(NULL, "snap", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno < 0); + SPDK_CU_ASSERT_FATAL(g_lvol == NULL); + + spdk_lvol_create_snapshot(lvol, "", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno < 0); + SPDK_CU_ASSERT_FATAL(g_lvol == NULL); + + spdk_lvol_create_snapshot(lvol, NULL, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno < 0); + SPDK_CU_ASSERT_FATAL(g_lvol == NULL); + + spdk_lvol_create_snapshot(lvol, "snap", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + CU_ASSERT_STRING_EQUAL(g_lvol->name, "snap"); + + snap = g_lvol; + + spdk_lvol_create_snapshot(lvol, "snap", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno < 0); + + spdk_lvol_close(lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + + spdk_lvol_close(snap, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_clone(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvol *lvol; + struct spdk_lvol *snap; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, true, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + lvol = g_lvol; + + spdk_lvol_create_snapshot(lvol, "snap", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + CU_ASSERT_STRING_EQUAL(g_lvol->name, "snap"); + + snap = g_lvol; + + spdk_lvol_create_clone(snap, "clone", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + CU_ASSERT_STRING_EQUAL(g_lvol->name, "clone"); + + /* Lvol has to be closed (or destroyed) before unloading lvol store. */ + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + + spdk_lvol_close(snap, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + + spdk_lvol_close(lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_clone_fail(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvol *lvol; + struct spdk_lvol *snap; + struct spdk_lvol *clone; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, true, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + lvol = g_lvol; + + spdk_lvol_create_snapshot(lvol, "snap", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + CU_ASSERT_STRING_EQUAL(g_lvol->name, "snap"); + + snap = g_lvol; + + spdk_lvol_create_clone(NULL, "clone", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno < 0); + + spdk_lvol_create_clone(snap, "", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno < 0); + + spdk_lvol_create_clone(snap, NULL, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno < 0); + + spdk_lvol_create_clone(snap, "clone", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + CU_ASSERT_STRING_EQUAL(g_lvol->name, "clone"); + + clone = g_lvol; + + spdk_lvol_create_clone(snap, "clone", lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno < 0); + + /* Lvol has to be closed (or destroyed) before unloading lvol store. */ + spdk_lvol_close(clone, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + + spdk_lvol_close(snap, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + + spdk_lvol_close(lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + g_lvserrno = -1; + + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_names(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + struct spdk_lvol_store *lvs; + struct spdk_lvol *lvol, *lvol2; + char fullname[SPDK_LVOL_NAME_MAX]; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + g_lvol_store = NULL; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + lvs = g_lvol_store; + + rc = spdk_lvol_create(lvs, NULL, 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == -EINVAL); + + rc = spdk_lvol_create(lvs, "", 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == -EINVAL); + + memset(fullname, 'x', sizeof(fullname)); + rc = spdk_lvol_create(lvs, fullname, 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == -EINVAL); + + g_lvserrno = -1; + rc = spdk_lvol_create(lvs, "lvol", 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + lvol = g_lvol; + + rc = spdk_lvol_create(lvs, "lvol", 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == -EEXIST); + + g_lvserrno = -1; + rc = spdk_lvol_create(lvs, "lvol2", 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + lvol2 = g_lvol; + + spdk_lvol_close(lvol, close_cb, NULL); + spdk_lvol_destroy(lvol, lvol_op_complete, NULL); + + g_lvserrno = -1; + g_lvol = NULL; + rc = spdk_lvol_create(lvs, "lvol", 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + lvol = g_lvol; + + spdk_lvol_close(lvol, close_cb, NULL); + spdk_lvol_destroy(lvol, destroy_cb, NULL); + + spdk_lvol_close(lvol2, close_cb, NULL); + spdk_lvol_destroy(lvol2, destroy_cb, NULL); + + /* Simulate creating two lvols with same name simultaneously. */ + lvol = calloc(1, sizeof(*lvol)); + SPDK_CU_ASSERT_FATAL(lvol != NULL); + snprintf(lvol->name, sizeof(lvol->name), "tmp_name"); + TAILQ_INSERT_TAIL(&lvs->pending_lvols, lvol, link); + rc = spdk_lvol_create(lvs, "tmp_name", 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == -EEXIST); + + /* Remove name from temporary list and try again. */ + TAILQ_REMOVE(&lvs->pending_lvols, lvol, link); + free(lvol); + + rc = spdk_lvol_create(lvs, "tmp_name", 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + lvol = g_lvol; + + spdk_lvol_close(lvol, close_cb, NULL); + spdk_lvol_destroy(lvol, destroy_cb, NULL); + + g_lvserrno = -1; + rc = spdk_lvs_destroy(lvs, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} + +static void +lvol_rename(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + struct spdk_lvol_store *lvs; + struct spdk_lvol *lvol, *lvol2; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + g_lvol_store = NULL; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + lvs = g_lvol_store; + + /* Trying to create new lvol */ + g_lvserrno = -1; + rc = spdk_lvol_create(lvs, "lvol", 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + lvol = g_lvol; + + /* Trying to create second lvol with existing lvol name */ + g_lvserrno = -1; + g_lvol = NULL; + rc = spdk_lvol_create(lvs, "lvol", 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == -EEXIST); + CU_ASSERT(g_lvserrno == -1); + SPDK_CU_ASSERT_FATAL(g_lvol == NULL); + + /* Trying to create second lvol with non existing name */ + g_lvserrno = -1; + rc = spdk_lvol_create(lvs, "lvol2", 1, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + lvol2 = g_lvol; + + /* Trying to rename lvol with not existing name */ + spdk_lvol_rename(lvol, "lvol_new", lvol_op_complete, NULL); + CU_ASSERT(g_lvolerrno == 0); + CU_ASSERT_STRING_EQUAL(lvol->name, "lvol_new"); + + /* Trying to rename lvol with other lvol name */ + spdk_lvol_rename(lvol2, "lvol_new", lvol_op_complete, NULL); + CU_ASSERT(g_lvolerrno == -EEXIST); + CU_ASSERT_STRING_NOT_EQUAL(lvol2->name, "lvol_new"); + + spdk_lvol_close(lvol, close_cb, NULL); + spdk_lvol_destroy(lvol, lvol_op_complete, NULL); + + spdk_lvol_close(lvol2, close_cb, NULL); + spdk_lvol_destroy(lvol2, lvol_op_complete, NULL); + + g_lvserrno = -1; + rc = spdk_lvs_destroy(lvs, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} + +static void +lvs_rename(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + struct spdk_lvol_store *lvs, *lvs2; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + g_lvserrno = -1; + g_lvol_store = NULL; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + lvs = g_lvol_store; + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "unimportant_lvs_name"); + g_lvserrno = -1; + g_lvol_store = NULL; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + lvs2 = g_lvol_store; + + /* Trying to rename lvs with new name */ + spdk_lvs_rename(lvs, "new_lvs_name", lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT_STRING_EQUAL(lvs->name, "new_lvs_name"); + + /* Trying to rename lvs with name lvs already has */ + spdk_lvs_rename(lvs, "new_lvs_name", lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT_STRING_EQUAL(lvs->name, "new_lvs_name"); + + /* Trying to rename lvs with name already existing */ + spdk_lvs_rename(lvs2, "new_lvs_name", lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno == -EEXIST); + CU_ASSERT_STRING_EQUAL(lvs2->name, "unimportant_lvs_name"); + + /* Trying to rename lvs with another rename process started with the same name */ + /* Simulate renaming process in progress */ + snprintf(lvs2->new_name, sizeof(lvs2->new_name), "another_new_lvs_name"); + CU_ASSERT_STRING_EQUAL(lvs2->new_name, "another_new_lvs_name"); + /* Start second process */ + spdk_lvs_rename(lvs, "another_new_lvs_name", lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno == -EEXIST); + CU_ASSERT_STRING_EQUAL(lvs->name, "new_lvs_name"); + /* reverting lvs2 new name to proper value */ + snprintf(lvs2->new_name, sizeof(lvs2->new_name), "unimportant_lvs_name"); + CU_ASSERT_STRING_EQUAL(lvs2->new_name, "unimportant_lvs_name"); + + /* Simulate error while lvs rename */ + g_lvs_rename_blob_open_error = true; + spdk_lvs_rename(lvs, "complete_new_lvs_name", lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno != 0); + CU_ASSERT_STRING_EQUAL(lvs->name, "new_lvs_name"); + CU_ASSERT_STRING_EQUAL(lvs->new_name, "new_lvs_name"); + g_lvs_rename_blob_open_error = false; + + g_lvserrno = -1; + rc = spdk_lvs_destroy(lvs, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + g_lvserrno = -1; + rc = spdk_lvs_destroy(lvs2, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + spdk_free_thread(); +} +static void lvol_refcnt(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + struct spdk_lvol *lvol; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + CU_ASSERT(g_lvol->ref_count == 1); + + lvol = g_lvol; + spdk_lvol_open(g_lvol, lvol_op_with_handle_complete, NULL); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + CU_ASSERT(lvol->ref_count == 2); + + /* Trying to destroy lvol while its open should fail */ + spdk_lvol_destroy(lvol, lvol_op_complete, NULL); + CU_ASSERT(g_lvolerrno != 0); + + spdk_lvol_close(lvol, lvol_op_complete, NULL); + CU_ASSERT(lvol->ref_count == 1); + CU_ASSERT(g_lvolerrno == 0); + + spdk_lvol_close(lvol, lvol_op_complete, NULL); + CU_ASSERT(lvol->ref_count == 0); + CU_ASSERT(g_lvolerrno == 0); + + /* Try to close already closed lvol */ + spdk_lvol_close(lvol, lvol_op_complete, NULL); + CU_ASSERT(lvol->ref_count == 0); + CU_ASSERT(g_lvolerrno != 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_create_thin_provisioned(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + CU_ASSERT(g_lvol->blob->thin_provisioned == false); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + spdk_lvol_destroy(g_lvol, destroy_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + spdk_lvol_create(g_lvol_store, "lvol", 10, true, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + CU_ASSERT(g_lvol->blob->thin_provisioned == true); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + spdk_lvol_destroy(g_lvol, destroy_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + spdk_free_thread(); +} + +static void +lvol_inflate(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + g_inflate_rc = -1; + spdk_lvol_inflate(g_lvol, lvol_op_complete, NULL); + CU_ASSERT(g_lvolerrno != 0); + + g_inflate_rc = 0; + spdk_lvol_inflate(g_lvol, lvol_op_complete, NULL); + CU_ASSERT(g_lvolerrno == 0); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + spdk_lvol_destroy(g_lvol, destroy_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + /* Make sure that all references to the io_channel was closed after + * inflate call + */ + CU_ASSERT(g_io_channel == NULL); + + spdk_free_thread(); +} + +static void +lvol_decouple_parent(void) +{ + struct lvol_ut_bs_dev dev; + struct spdk_lvs_opts opts; + int rc = 0; + + init_dev(&dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev.bs_dev, &opts, lvol_store_op_with_handle_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + + spdk_lvol_create(g_lvol_store, "lvol", 10, false, lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + + g_inflate_rc = -1; + spdk_lvol_decouple_parent(g_lvol, lvol_op_complete, NULL); + CU_ASSERT(g_lvolerrno != 0); + + g_inflate_rc = 0; + spdk_lvol_decouple_parent(g_lvol, lvol_op_complete, NULL); + CU_ASSERT(g_lvolerrno == 0); + + spdk_lvol_close(g_lvol, close_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + spdk_lvol_destroy(g_lvol, destroy_cb, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + g_lvol_store = NULL; + + free_dev(&dev); + + /* Make sure that all references to the io_channel was closed after + * inflate call + */ + CU_ASSERT(g_io_channel == NULL); + + spdk_free_thread(); +} + +int main(int argc, char **argv) +{ + CU_pSuite suite = NULL; + unsigned int num_failures; + + if (CU_initialize_registry() != CUE_SUCCESS) { + return CU_get_error(); + } + + suite = CU_add_suite("lvol", NULL, NULL); + if (suite == NULL) { + CU_cleanup_registry(); + return CU_get_error(); + } + + if ( + CU_add_test(suite, "lvs_init_unload_success", lvs_init_unload_success) == NULL || + CU_add_test(suite, "lvs_init_destroy_success", lvs_init_destroy_success) == NULL || + CU_add_test(suite, "lvs_init_opts_success", lvs_init_opts_success) == NULL || + CU_add_test(suite, "lvs_unload_lvs_is_null_fail", lvs_unload_lvs_is_null_fail) == NULL || + CU_add_test(suite, "lvs_names", lvs_names) == NULL || + CU_add_test(suite, "lvol_create_destroy_success", lvol_create_destroy_success) == NULL || + CU_add_test(suite, "lvol_create_fail", lvol_create_fail) == NULL || + CU_add_test(suite, "lvol_destroy_fail", lvol_destroy_fail) == NULL || + CU_add_test(suite, "lvol_close_fail", lvol_close_fail) == NULL || + CU_add_test(suite, "lvol_close_success", lvol_close_success) == NULL || + CU_add_test(suite, "lvol_resize", lvol_resize) == NULL || + CU_add_test(suite, "lvs_load", lvs_load) == NULL || + CU_add_test(suite, "lvols_load", lvols_load) == NULL || + CU_add_test(suite, "lvol_open", lvol_open) == NULL || + CU_add_test(suite, "lvol_load", lvs_load) == NULL || + CU_add_test(suite, "lvs_load", lvols_load) == NULL || + CU_add_test(suite, "lvol_open", lvol_open) == NULL || + CU_add_test(suite, "lvol_snapshot", lvol_snapshot) == NULL || + CU_add_test(suite, "lvol_snapshot_fail", lvol_snapshot_fail) == NULL || + CU_add_test(suite, "lvol_clone", lvol_clone) == NULL || + CU_add_test(suite, "lvol_clone_fail", lvol_clone_fail) == NULL || + CU_add_test(suite, "lvol_refcnt", lvol_refcnt) == NULL || + CU_add_test(suite, "lvol_names", lvol_names) == NULL || + CU_add_test(suite, "lvol_create_thin_provisioned", lvol_create_thin_provisioned) == NULL || + CU_add_test(suite, "lvol_rename", lvol_rename) == NULL || + CU_add_test(suite, "lvs_rename", lvs_rename) == NULL || + CU_add_test(suite, "lvol_inflate", lvol_inflate) == NULL || + CU_add_test(suite, "lvol_decouple_parent", lvol_decouple_parent) == NULL + ) { + CU_cleanup_registry(); + return CU_get_error(); + } + + CU_basic_set_mode(CU_BRM_VERBOSE); + CU_basic_run_tests(); + num_failures = CU_get_number_of_failures(); + CU_cleanup_registry(); + + return num_failures; +} |