/*- * 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/string.h" #include "vbdev_lvol.c" #define SPDK_BS_PAGE_SIZE 0x1000 int g_lvolerrno; int g_lvserrno; int g_cluster_size; struct spdk_lvol_store *g_lvs = NULL; struct spdk_lvol *g_lvol = NULL; struct lvol_store_bdev *g_lvs_bdev = NULL; struct spdk_bdev *g_base_bdev = NULL; static struct spdk_bdev g_bdev = {}; static struct spdk_bs_dev *g_bs_dev = NULL; static struct spdk_lvol_store *g_lvol_store = NULL; bool lvol_store_initialize_fail = false; bool lvol_store_initialize_cb_fail = false; bool lvol_already_opened = false; int spdk_bs_bdev_claim(struct spdk_bs_dev *bs_dev, struct spdk_bdev_module_if *module) { if (lvol_already_opened == true) return -1; lvol_already_opened = true; return 0; } void spdk_vbdev_unregister(struct spdk_bdev *vbdev) { SPDK_CU_ASSERT_FATAL(vbdev != NULL); vbdev->fn_table->destruct(vbdev->ctxt); } uint64_t spdk_bs_get_page_size(struct spdk_blob_store *bs) { return SPDK_BS_PAGE_SIZE; } static void bdev_blob_destroy(struct spdk_bs_dev *bs_dev) { CU_ASSERT(g_bs_dev != NULL); CU_ASSERT(bs_dev != NULL); CU_ASSERT(g_bs_dev == bs_dev); free(bs_dev); g_bs_dev = NULL; lvol_already_opened = false; } struct spdk_bs_dev * spdk_bdev_create_bs_dev(struct spdk_bdev *bdev, spdk_bdev_remove_cb_t remove_cb, void *remove_ctx) { struct spdk_bs_dev *bs_dev; if (lvol_already_opened == true) return NULL; bs_dev = calloc(1, sizeof(*bs_dev)); SPDK_CU_ASSERT_FATAL(bs_dev != NULL); bs_dev->destroy = bdev_blob_destroy; CU_ASSERT(g_bs_dev == NULL); g_bs_dev = bs_dev; return bs_dev; } void spdk_lvs_opts_init(struct spdk_lvs_opts *opts) { } int spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg) { struct spdk_lvol_store *lvs; int error = 0; if (lvol_store_initialize_fail) return -1; if (lvol_store_initialize_cb_fail) { bs_dev->destroy(bs_dev); lvs = NULL; error = -1; } else { lvs = calloc(1, sizeof(*lvs)); SPDK_CU_ASSERT_FATAL(lvs != NULL); lvs->bs_dev = bs_dev; error = 0; } cb_fn(cb_arg, lvs, error); return 0; } int spdk_lvs_unload(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, void *cb_arg) { g_lvol_store = NULL; free(lvs); g_bs_dev->destroy(g_bs_dev); if (cb_fn != NULL) cb_fn(cb_arg, 0); return 0; } int spdk_lvol_resize(struct spdk_lvol *lvol, size_t sz, spdk_lvol_op_complete cb_fn, void *cb_arg) { cb_fn(cb_arg, 0); return 0; } uint64_t spdk_bs_get_cluster_size(struct spdk_blob_store *bs) { return g_cluster_size; } struct spdk_bdev * spdk_bdev_get_by_name(const char *bdev_name) { if (!strcmp(g_base_bdev->name, bdev_name)) { return g_base_bdev; } return NULL; } void spdk_lvol_close(struct spdk_lvol *lvol) { struct spdk_lvs_req *destruct_req; SPDK_CU_ASSERT_FATAL(lvol == g_lvol); TAILQ_REMOVE(&lvol->lvol_store->lvols, lvol, link); destruct_req = lvol->lvol_store->destruct_req; if (destruct_req && TAILQ_EMPTY(&lvol->lvol_store->lvols)) { spdk_lvs_unload(lvol->lvol_store, destruct_req->cb_fn, destruct_req->cb_arg); free(destruct_req); } free(lvol->name); free(lvol); g_lvol = NULL; } void spdk_lvol_destroy(struct spdk_lvol *lvol) { /* Lvol destroy and close are effectively the same from UT perspective */ spdk_lvol_close(lvol); } void spdk_bdev_io_complete(struct spdk_bdev_io *bdev_io, enum spdk_bdev_io_status status) { } struct spdk_io_channel *spdk_lvol_get_io_channel(struct spdk_lvol *lvol) { return NULL; } void spdk_bdev_io_get_buf(struct spdk_bdev_io *bdev_io, spdk_bdev_io_get_buf_cb cb, uint64_t len) { } void spdk_bs_io_read_blob(struct spdk_blob *blob, struct spdk_io_channel *channel, void *payload, uint64_t offset, uint64_t length, spdk_blob_op_complete cb_fn, void *cb_arg) { } void spdk_bs_io_write_blob(struct spdk_blob *blob, struct spdk_io_channel *channel, void *payload, uint64_t offset, uint64_t length, spdk_blob_op_complete cb_fn, void *cb_arg) { } void spdk_bs_io_writev_blob(struct spdk_blob *blob, struct spdk_io_channel *channel, struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length, spdk_blob_op_complete cb_fn, void *cb_arg) { } void spdk_bs_io_readv_blob(struct spdk_blob *blob, struct spdk_io_channel *channel, struct iovec *iov, int iovcnt, uint64_t offset, uint64_t length, spdk_blob_op_complete cb_fn, void *cb_arg) { } void spdk_bs_io_flush_channel(struct spdk_io_channel *channel, spdk_blob_op_complete cb_fn, void *cb_arg) { } void spdk_bdev_module_list_add(struct spdk_bdev_module_if *bdev_module) { } int spdk_json_write_name(struct spdk_json_write_ctx *w, const char *name) { return 0; } int spdk_json_write_string(struct spdk_json_write_ctx *w, const char *val) { return 0; } int spdk_json_write_object_begin(struct spdk_json_write_ctx *w) { return 0; } int spdk_json_write_object_end(struct spdk_json_write_ctx *w) { return 0; } const char * spdk_bdev_get_name(const struct spdk_bdev *bdev) { return "test"; } void spdk_vbdev_register(struct spdk_bdev *vbdev, struct spdk_bdev **base_bdevs, int base_bdev_count) { } void spdk_bdev_module_examine_done(struct spdk_bdev_module_if *module) { } int spdk_lvol_create(struct spdk_lvol_store *lvs, size_t sz, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) { struct spdk_lvol *lvol = calloc(1, sizeof(*lvol)); SPDK_CU_ASSERT_FATAL(lvol != NULL); lvol->lvol_store = lvs; lvol->name = spdk_sprintf_alloc("%s", "UNIT_TEST_UUID"); SPDK_CU_ASSERT_FATAL(lvol->name != NULL); TAILQ_INIT(&lvs->lvols); TAILQ_INSERT_TAIL(&lvol->lvol_store->lvols, lvol, link); cb_fn(cb_arg, lvol, 0); return 0; } static void lvol_store_op_complete(void *cb_arg, int lvserrno) { g_lvserrno = lvserrno; return; } static void lvol_store_op_with_handle_complete(void *cb_arg, struct spdk_lvol_store *lvs, int lvserrno) { g_lvserrno = lvserrno; g_lvol_store = lvs; return; } static void vbdev_lvol_create_complete(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno) { g_lvolerrno = lvolerrno; g_lvol = lvol; } static void vbdev_lvol_resize_complete(void *cb_arg, int lvolerrno) { g_lvolerrno = lvolerrno; } static void ut_lvs_destroy(void) { int rc = 0; int sz = 10; struct spdk_lvol_store *lvs; /* Lvol store is succesfully created */ rc = vbdev_lvs_create(&g_bdev, 0, 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(g_bs_dev != NULL); lvs = g_lvol_store; g_lvol_store = NULL; uuid_generate_time(lvs->uuid); /* Suuccessfully create lvol, which should be destroyed with lvs later */ g_lvolerrno = -1; rc = vbdev_lvol_create(lvs->uuid, sz, vbdev_lvol_create_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvolerrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); /* Destroy lvol store */ vbdev_lvs_destruct(lvs, lvol_store_op_complete, NULL); CU_ASSERT(g_lvserrno == 0); CU_ASSERT(g_lvol_store == NULL); CU_ASSERT(g_lvol == NULL); } static void ut_lvol_init(void) { uuid_t wrong_uuid; int sz = 10; int rc; g_lvs = calloc(1, sizeof(*g_lvs)); SPDK_CU_ASSERT_FATAL(g_lvs != NULL); g_lvs_bdev = calloc(1, sizeof(*g_lvs_bdev)); SPDK_CU_ASSERT_FATAL(g_lvs_bdev != NULL); g_base_bdev = calloc(1, sizeof(*g_base_bdev)); SPDK_CU_ASSERT_FATAL(g_base_bdev != NULL); g_lvs_bdev->lvs = g_lvs; g_lvs_bdev->bdev = g_base_bdev; uuid_generate_time(g_lvs->uuid); uuid_generate_time(wrong_uuid); /* Incorrect uuid set */ g_lvolerrno = 0; rc = vbdev_lvol_create(wrong_uuid, sz, vbdev_lvol_create_complete, NULL); CU_ASSERT(rc == -ENODEV); TAILQ_INSERT_TAIL(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores); /* Successful lvol create */ g_lvolerrno = -1; rc = vbdev_lvol_create(g_lvs->uuid, sz, vbdev_lvol_create_complete, NULL); SPDK_CU_ASSERT_FATAL(rc == 0); CU_ASSERT(g_lvol != NULL); CU_ASSERT(g_lvolerrno == 0); /* Successful lvol destruct */ vbdev_lvol_destruct(g_lvol); CU_ASSERT(g_lvol == NULL); TAILQ_REMOVE(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores); free(g_lvs); free(g_lvs_bdev); free(g_base_bdev); } static void ut_lvol_hotremove(void) { int rc = 0; lvol_store_initialize_fail = false; lvol_store_initialize_cb_fail = false; lvol_already_opened = false; g_bs_dev = NULL; /* Lvol store is succesfully created */ rc = vbdev_lvs_create(&g_bdev, 0, lvol_store_op_with_handle_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvserrno == 0); CU_ASSERT(g_lvol_store != NULL); CU_ASSERT(g_bs_dev != NULL); /* Hot remove callback with NULL - stability check */ vbdev_lvs_hotremove_cb(NULL); /* Hot remove lvs on bdev removal */ vbdev_lvs_hotremove_cb(&g_bdev); CU_ASSERT(g_lvol_store == NULL); CU_ASSERT(TAILQ_EMPTY(&g_spdk_lvol_pairs)); } static void ut_lvol_resize(void) { int sz = 10; int rc = 0; g_lvs = calloc(1, sizeof(*g_lvs)); g_lvs_bdev = calloc(1, sizeof(*g_lvs_bdev)); g_base_bdev = calloc(1, sizeof(*g_base_bdev)); g_lvs_bdev->lvs = g_lvs; g_lvs_bdev->bdev = g_base_bdev; uuid_generate_time(g_lvs->uuid); g_base_bdev->blocklen = 4096; TAILQ_INSERT_TAIL(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores); /* Successful lvol create */ g_lvolerrno = -1; rc = vbdev_lvol_create(g_lvs->uuid, sz, vbdev_lvol_create_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvolerrno == 0); SPDK_CU_ASSERT_FATAL(g_lvol != NULL); g_base_bdev->ctxt = g_lvol; g_base_bdev->name = spdk_sprintf_alloc("%s", g_lvol->name); /* Successful lvol resize */ rc = vbdev_lvol_resize(g_lvol->name, 20, vbdev_lvol_resize_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_base_bdev->blockcnt == 20 * g_cluster_size / g_base_bdev->blocklen); /* Resize with wrong bdev name */ rc = vbdev_lvol_resize("wrong name", 20, vbdev_lvol_resize_complete, NULL); CU_ASSERT(rc != 0); /* Resize with correct bdev name, but wrong lvol name */ free(g_lvol->name); g_lvol->name = strdup("wrong name"); SPDK_CU_ASSERT_FATAL(g_lvol->name != NULL); rc = vbdev_lvol_resize(g_base_bdev->name, 20, vbdev_lvol_resize_complete, NULL); CU_ASSERT(rc != 0); /* Successful lvol destruct */ vbdev_lvol_destruct(g_lvol); CU_ASSERT(g_lvol == NULL); TAILQ_REMOVE(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores); free(g_lvs); free(g_lvs_bdev); free(g_base_bdev->name); free(g_base_bdev); } static void ut_lvs_init(void) { int rc = 0; struct spdk_lvol_store *lvs; struct spdk_bs_dev *bs_dev_temp; /* spdk_lvs_init() fails */ lvol_store_initialize_fail = true; rc = vbdev_lvs_create(&g_bdev, 0, lvol_store_op_with_handle_complete, NULL); CU_ASSERT(rc != 0); CU_ASSERT(g_lvserrno == 0); CU_ASSERT(g_lvol_store == NULL); CU_ASSERT(g_bs_dev == NULL); lvol_store_initialize_fail = false; /* spdk_lvs_init_cb() fails */ lvol_store_initialize_cb_fail = true; rc = vbdev_lvs_create(&g_bdev, 0, lvol_store_op_with_handle_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvserrno != 0); CU_ASSERT(g_lvol_store == NULL); CU_ASSERT(g_bs_dev == NULL); lvol_store_initialize_cb_fail = false; /* Lvol store is succesfully created */ rc = vbdev_lvs_create(&g_bdev, 0, lvol_store_op_with_handle_complete, NULL); CU_ASSERT(rc == 0); CU_ASSERT(g_lvserrno == 0); CU_ASSERT(g_lvol_store != NULL); CU_ASSERT(g_bs_dev != NULL); lvs = g_lvol_store; g_lvol_store = NULL; bs_dev_temp = g_bs_dev; g_bs_dev = NULL; /* Bdev with lvol store already claimed */ rc = vbdev_lvs_create(&g_bdev, 0, lvol_store_op_with_handle_complete, NULL); CU_ASSERT(rc != 0); CU_ASSERT(g_lvserrno == 0); CU_ASSERT(g_lvol_store == NULL); CU_ASSERT(g_bs_dev == NULL); /* Destruct lvol store */ g_bs_dev = bs_dev_temp; vbdev_lvs_destruct(lvs, lvol_store_op_complete, NULL); CU_ASSERT(g_lvserrno == 0); CU_ASSERT(g_lvol_store == NULL); CU_ASSERT(g_bs_dev == NULL); free(g_bs_dev); } 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, "ut_lvs_init", ut_lvs_init) == NULL || CU_add_test(suite, "ut_lvol_init", ut_lvol_init) == NULL || CU_add_test(suite, "ut_lvs_destroy", ut_lvs_destroy) == NULL || CU_add_test(suite, "ut_lvol_resize", ut_lvol_resize) == NULL || CU_add_test(suite, "lvol_hotremove", ut_lvol_hotremove) == 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; }