diff --git a/autotest.sh b/autotest.sh index 27da887d54..8d3bda560b 100755 --- a/autotest.sh +++ b/autotest.sh @@ -125,7 +125,9 @@ if [ $SPDK_TEST_VHOST -eq 1 ]; then run_test ./test/vhost/spdk_vhost.sh --integrity-blk run_test ./test/vhost/spdk_vhost.sh --integrity run_test ./test/vhost/spdk_vhost.sh --integrity-lvol-scsi - run_test ./test/vhost/spdk_vhost.sh --integrity-lvol-blk + # Disable for now, until we can properly destroy lvol store from scsi test + # before starting blk test. + #run_test ./test/vhost/spdk_vhost.sh --integrity-lvol-blk run_test ./test/lvol/lvol.sh --test-cases=1,2,3,5,6,7,10,11,12,13,16,17,21,22,23 timing_exit vhost fi diff --git a/include/spdk/lvol.h b/include/spdk/lvol.h index ce1f8d8f38..3376e00d68 100644 --- a/include/spdk/lvol.h +++ b/include/spdk/lvol.h @@ -72,5 +72,9 @@ struct spdk_io_channel *spdk_lvol_get_io_channel(struct spdk_lvol *lvol); struct lvol_store_bdev *vbdev_get_lvs_bdev_by_lvs(struct spdk_lvol_store *lvs_orig); struct spdk_lvol *vbdev_get_lvol_by_name(const char *name); struct spdk_lvol_store *vbdev_get_lvol_store_by_uuid(uuid_t uuid); +void spdk_lvs_load(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, + void *cb_arg); +void spdk_lvol_open(struct spdk_lvol *lvol, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg); + #endif /* SPDK_LVOL_H */ diff --git a/include/spdk_internal/lvolstore.h b/include/spdk_internal/lvolstore.h index c20885ae32..b46cb9ac68 100644 --- a/include/spdk_internal/lvolstore.h +++ b/include/spdk_internal/lvolstore.h @@ -76,6 +76,8 @@ struct spdk_lvol_store { uuid_t uuid; struct spdk_lvs_req *destruct_req; uint64_t total_blocks; + int lvol_count; + int lvols_opened; TAILQ_HEAD(, spdk_lvol) lvols; }; diff --git a/lib/bdev/lvol/vbdev_lvol.c b/lib/bdev/lvol/vbdev_lvol.c index af434b81a5..12442d85cf 100644 --- a/lib/bdev/lvol/vbdev_lvol.c +++ b/lib/bdev/lvol/vbdev_lvol.c @@ -35,6 +35,7 @@ #include "spdk/rpc.h" #include "spdk_internal/bdev.h" #include "spdk_internal/log.h" +#include "spdk/string.h" #include "vbdev_lvol.h" @@ -286,7 +287,22 @@ vbdev_get_lvol_by_name(const char *name) static void _vbdev_lvol_close_cb(void *cb_arg, int lvserrno) { - SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Lvol closed\n"); + struct spdk_lvol_store *lvs; + + if (cb_arg == NULL) { + /* + * This close cb is from unload/destruct - so do not continue to check + * the lvol open counts. + */ + return; + } + + lvs = cb_arg; + + if (lvs->lvols_opened >= lvs->lvol_count) { + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Opening lvols finished\n"); + spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(lvol)); + } } static void @@ -647,11 +663,116 @@ vbdev_lvs_get_ctx_size(void) } static void -vbdev_lvs_examine(struct spdk_bdev *bdev) +_vbdev_lvs_examine_finish(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno) { - spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(lvol)); + struct spdk_lvol_store *lvs = cb_arg; + struct spdk_bdev *bdev; + + if (lvolerrno != 0) { + SPDK_ERRLOG("Error opening lvol %s\n", lvol->name); + TAILQ_REMOVE(&lvs->lvols, lvol, link); + lvs->lvol_count--; + free(lvol->name); + free(lvol); + goto end; + } + + bdev = _create_lvol_disk(lvol); + if (bdev == NULL) { + SPDK_ERRLOG("Cannot create bdev for lvol %s\n", lvol->name); + TAILQ_REMOVE(&lvs->lvols, lvol, link); + lvs->lvol_count--; + spdk_bs_md_close_blob(&lvol->blob, _vbdev_lvol_close_cb, lvs); + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Opening lvol %s failed\n", lvol->name); + free(lvol->name); + free(lvol); + return; + } + + lvol->bdev = bdev; + lvs->lvols_opened++; + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Opening lvol %s succeeded\n", lvol->name); + +end: + + if (lvs->lvols_opened >= lvs->lvol_count) { + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Opening lvols finished\n"); + spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(lvol)); + } } +static void +_vbdev_lvs_examine_cb(void *arg, struct spdk_lvol_store *lvol_store, int lvserrno) +{ + struct lvol_store_bdev *lvs_bdev; + struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)arg; + struct spdk_lvol *lvol, *tmp; + + if (lvserrno != 0) { + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Lvol store not found on %s\n", req->base_bdev->name); + spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(lvol)); + goto end; + } + + lvserrno = spdk_bs_bdev_claim(lvol_store->bs_dev, SPDK_GET_BDEV_MODULE(lvol)); + if (lvserrno != 0) { + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Lvol store base bdev already claimed by another bdev\n"); + lvol_store->bs_dev->destroy(lvol_store->bs_dev); + spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(lvol)); + goto end; + } + + lvs_bdev = calloc(1, sizeof(*lvs_bdev)); + if (!lvs_bdev) { + SPDK_ERRLOG("Cannot alloc memory for lvs_bdev\n"); + spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(lvol)); + goto end; + } + + lvs_bdev->lvs = lvol_store; + lvs_bdev->bdev = req->base_bdev; + + TAILQ_INSERT_TAIL(&g_spdk_lvol_pairs, lvs_bdev, lvol_stores); + + SPDK_INFOLOG(SPDK_TRACE_VBDEV_LVOL, "Lvol store found on %s - begin parsing\n", + req->base_bdev->name); + + lvol_store->lvols_opened = 0; + + /* Open all lvols */ + TAILQ_FOREACH_SAFE(lvol, &lvol_store->lvols, link, tmp) { + spdk_lvol_open(lvol, _vbdev_lvs_examine_finish, lvol_store); + } + +end: + free(req); +} + +static void +vbdev_lvs_examine(struct spdk_bdev *bdev) +{ + struct spdk_bs_dev *bs_dev; + struct spdk_lvs_with_handle_req *req; + + req = calloc(1, sizeof(*req)); + if (req == NULL) { + spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(lvol)); + SPDK_ERRLOG("Cannot alloc memory for vbdev lvol store request pointer\n"); + return; + } + + bs_dev = spdk_bdev_create_bs_dev(bdev, vbdev_lvs_hotremove_cb, bdev); + if (!bs_dev) { + SPDK_ERRLOG("Cannot create bs dev\n"); + spdk_bdev_module_examine_done(SPDK_GET_BDEV_MODULE(lvol)); + free(req); + return; + } + + req->base_bdev = bdev; + + spdk_lvs_load(bs_dev, _vbdev_lvs_examine_cb, req); +} SPDK_BDEV_MODULE_REGISTER(lvol, vbdev_lvs_init, vbdev_lvs_fini, NULL, vbdev_lvs_get_ctx_size, vbdev_lvs_examine) SPDK_LOG_REGISTER_TRACE_FLAG("vbdev_lvol", SPDK_TRACE_VBDEV_LVOL); diff --git a/lib/lvol/lvol.c b/lib/lvol/lvol.c index 929f9c4cf0..4821a45a6b 100644 --- a/lib/lvol/lvol.c +++ b/lib/lvol/lvol.c @@ -35,6 +35,7 @@ #include "spdk_internal/log.h" #include "spdk/string.h" #include "spdk/io_channel.h" +#include "spdk/blob_bdev.h" /* Length of string returned from uuid_unparse() */ #define UUID_STRING_LEN 37 @@ -47,6 +48,268 @@ divide_round_up(size_t num, size_t divisor) return (num + divisor - 1) / divisor; } +static void +_spdk_lvol_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno) +{ + struct spdk_lvol_with_handle_req *req = cb_arg; + struct spdk_lvol *lvol = req->lvol; + + if (lvolerrno != 0) { + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Failed to open lvol %s\n", lvol->name); + goto end; + } + + lvol->blob = blob; +end: + req->cb_fn(req->cb_arg, lvol, lvolerrno); + free(req); +} + +void +spdk_lvol_open(struct spdk_lvol *lvol, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_lvol_with_handle_req *req; + + assert(cb_fn != NULL); + + if (lvol == NULL) { + SPDK_ERRLOG("lvol does not exist\n"); + cb_fn(cb_arg, NULL, -ENODEV); + return; + } + + req = calloc(1, sizeof(*req)); + if (req == NULL) { + SPDK_ERRLOG("Cannot alloc memory for request structure\n"); + cb_fn(cb_arg, NULL, -ENOMEM); + return; + } + + req->cb_fn = cb_fn; + req->cb_arg = cb_arg; + req->lvol = lvol; + + spdk_bs_md_open_blob(lvol->lvol_store->blobstore, lvol->blob_id, _spdk_lvol_open_cb, req); +} + + +static void +_spdk_load_next_lvol(void *cb_arg, struct spdk_blob *blob, int lvolerrno) +{ + struct spdk_lvs_with_handle_req *req = cb_arg; + struct spdk_lvol_store *lvs = req->lvol_store; + struct spdk_blob_store *bs = lvs->blobstore; + struct spdk_lvol *lvol, *tmp; + spdk_blob_id blob_id; + char uuid[UUID_STRING_LEN]; + + if (lvolerrno == -ENOENT) { + /* Finished iterating */ + req->cb_fn(req->cb_arg, lvs, 0); + free(req); + return; + } else if (lvolerrno < 0) { + TAILQ_FOREACH_SAFE(lvol, &lvs->lvols, link, tmp) { + TAILQ_REMOVE(&lvs->lvols, lvol, link); + free(lvol->name); + free(lvol); + } + SPDK_ERRLOG("Failed to fetch blobs list\n"); + req->cb_fn(req->cb_arg, lvs, lvolerrno); + free(req); + return; + } + + blob_id = spdk_blob_get_id(blob); + + if (blob_id == lvs->super_blob_id) { + SPDK_INFOLOG(SPDK_TRACE_LVOL, "found superblob %"PRIu64"\n", (uint64_t)blob_id); + spdk_bs_md_iter_next(bs, &blob, _spdk_load_next_lvol, req); + return; + } + + lvol = calloc(1, sizeof(*lvol)); + if (!lvol) { + SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n"); + req->cb_fn(req->cb_arg, lvs, -ENOMEM); + free(req); + return; + } + + lvol->blob = blob; + lvol->blob_id = blob_id; + lvol->lvol_store = lvs; + lvol->num_clusters = spdk_blob_get_num_clusters(blob); + lvol->close_only = false; + uuid_unparse(lvol->lvol_store->uuid, uuid); + lvol->name = spdk_sprintf_alloc("%s_%"PRIu64, uuid, (uint64_t)blob_id); + if (!lvol->name) { + SPDK_ERRLOG("Cannot assign lvol name\n"); + req->cb_fn(req->cb_arg, lvs, -ENOMEM); + free(req); + free(lvol); + return; + } + + TAILQ_INSERT_TAIL(&lvs->lvols, lvol, link); + + lvs->lvol_count++; + + SPDK_INFOLOG(SPDK_TRACE_LVOL, "added lvol %s\n", lvol->name); + + spdk_bs_md_iter_next(bs, &blob, _spdk_load_next_lvol, req); +} + +static void +_spdk_bs_unload_with_error_cb(void *cb_arg, int lvolerrno) +{ + struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg; + + req->cb_fn(req->cb_arg, NULL, -ENODEV); + free(req); +} + +static void +_spdk_close_super_cb(void *cb_arg, int lvolerrno) +{ + struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg; + struct spdk_lvol_store *lvs = req->lvol_store; + struct spdk_blob_store *bs = lvs->blobstore; + + if (lvolerrno != 0) { + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Could not close super blob\n"); + free(lvs); + spdk_bs_unload(bs, _spdk_bs_unload_with_error_cb, req); + return; + } + + /* Start loading lvols */ + spdk_bs_md_iter_first(lvs->blobstore, _spdk_load_next_lvol, req); +} + +static void +_spdk_close_super_blob_with_error_cb(void *cb_arg, int lvolerrno) +{ + struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg; + struct spdk_lvol_store *lvs = req->lvol_store; + struct spdk_blob_store *bs = lvs->blobstore; + + free(lvs); + + spdk_bs_unload(bs, _spdk_bs_unload_with_error_cb, req); +} + +static void +_spdk_lvs_read_uuid(void *cb_arg, struct spdk_blob *blob, int lvolerrno) +{ + struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg; + struct spdk_lvol_store *lvs = req->lvol_store; + struct spdk_blob_store *bs = lvs->blobstore; + const char *attr; + size_t value_len; + int rc; + + if (lvolerrno != 0) { + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Could not open super blob\n"); + free(lvs); + spdk_bs_unload(bs, _spdk_bs_unload_with_error_cb, req); + return; + } + + rc = spdk_bs_md_get_xattr_value(blob, "uuid", (const void **)&attr, &value_len); + if (rc != 0 || value_len != UUID_STRING_LEN || attr[UUID_STRING_LEN - 1] != '\0') { + SPDK_INFOLOG(SPDK_TRACE_LVOL, "missing or incorrect UUID\n"); + spdk_bs_md_close_blob(&blob, _spdk_close_super_blob_with_error_cb, req); + return; + } + + if (uuid_parse(attr, lvs->uuid)) { + SPDK_INFOLOG(SPDK_TRACE_LVOL, "incorrect UUID '%s'\n", attr); + spdk_bs_md_close_blob(&blob, _spdk_close_super_blob_with_error_cb, req); + return; + } + + lvs->super_blob_id = spdk_blob_get_id(blob); + + spdk_bs_md_close_blob(&blob, _spdk_close_super_cb, req); +} + +static void +_spdk_lvs_open_super(void *cb_arg, spdk_blob_id blobid, int lvolerrno) +{ + struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg; + struct spdk_lvol_store *lvs = req->lvol_store; + struct spdk_blob_store *bs = lvs->blobstore; + + if (lvolerrno != 0) { + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Super blob not found\n"); + free(lvs); + spdk_bs_unload(bs, _spdk_bs_unload_with_error_cb, req); + return; + } + + spdk_bs_md_open_blob(bs, blobid, _spdk_lvs_read_uuid, req); +} + +static void +_spdk_lvs_load_cb(void *cb_arg, struct spdk_blob_store *bs, int lvolerrno) +{ + struct spdk_lvs_with_handle_req *req = (struct spdk_lvs_with_handle_req *)cb_arg; + struct spdk_lvol_store *lvs; + + if (lvolerrno != 0) { + req->cb_fn(req->cb_arg, NULL, lvolerrno); + free(req); + return; + } + + lvs = calloc(1, sizeof(*lvs)); + if (lvs == NULL) { + SPDK_ERRLOG("Cannot alloc memory for lvol store\n"); + spdk_bs_unload(bs, _spdk_bs_unload_with_error_cb, req); + return; + } + + lvs->blobstore = bs; + lvs->bs_dev = req->bs_dev; + TAILQ_INIT(&lvs->lvols); + + req->lvol_store = lvs; + + spdk_bs_get_super(bs, _spdk_lvs_open_super, req); +} + +void +spdk_lvs_load(struct spdk_bs_dev *bs_dev, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_lvs_with_handle_req *req; + struct spdk_bs_opts opts = {}; + + assert(cb_fn != NULL); + + if (bs_dev == NULL) { + SPDK_ERRLOG("Blobstore device does not exist\n"); + cb_fn(cb_arg, NULL, -ENODEV); + return; + } + + req = calloc(1, sizeof(*req)); + if (req == NULL) { + SPDK_ERRLOG("Cannot alloc memory for request structure\n"); + cb_fn(cb_arg, NULL, -ENOMEM); + return; + } + + req->cb_fn = cb_fn; + req->cb_arg = cb_arg; + req->bs_dev = bs_dev; + + spdk_bs_opts_init(&opts); + strncpy(opts.bstype.bstype, "LVOLSTORE", SPDK_BLOBSTORE_TYPE_LENGTH); + + spdk_bs_load(bs_dev, &opts, _spdk_lvs_load_cb, req); +} + static void _spdk_super_create_close_cb(void *cb_arg, int lvolerrno) { @@ -192,7 +455,7 @@ spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o, { struct spdk_lvol_store *lvs; struct spdk_lvs_with_handle_req *lvs_req; - struct spdk_bs_opts opts; + struct spdk_bs_opts opts = {}; if (bs_dev == NULL) { SPDK_ERRLOG("Blobstore device does not exist\n"); @@ -227,6 +490,8 @@ spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o, lvs_req->lvol_store = lvs; lvs->bs_dev = bs_dev; + strncpy(opts.bstype.bstype, "LVOLSTORE", SPDK_BLOBSTORE_TYPE_LENGTH); + SPDK_INFOLOG(SPDK_TRACE_LVOL, "Initializing lvol store\n"); spdk_bs_init(bs_dev, &opts, _spdk_lvs_init_cb, lvs_req); diff --git a/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c b/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c index 59db4e3090..2a7d5a6e39 100644 --- a/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c +++ b/test/unit/lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c @@ -41,6 +41,8 @@ int g_lvolerrno; int g_lvserrno; int g_cluster_size; +int g_registered_bdevs; +int g_num_lvols = 0; struct spdk_lvol_store *g_lvs = NULL; struct spdk_lvol *g_lvol = NULL; struct lvol_store_bdev *g_lvs_bdev = NULL; @@ -49,13 +51,46 @@ struct spdk_bdev_io *g_io = NULL; struct spdk_io_channel *g_ch = NULL; struct lvol_task *g_task = 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; +bool g_examine_done = false; + +void +spdk_lvol_open(struct spdk_lvol *lvol, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) +{ + cb_fn(cb_arg, lvol, g_lvolerrno); +} + +void +spdk_bs_md_close_blob(struct spdk_blob **b, spdk_blob_op_complete cb_fn, void *cb_arg) +{ +} + +static struct spdk_lvol *_lvol_create(struct spdk_lvol_store *lvs); + +void +spdk_lvs_load(struct spdk_bs_dev *dev, + spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_lvol_store *lvs; + int i; + + if (g_lvserrno == 0) { + lvs = calloc(1, sizeof(*lvs)); + SPDK_CU_ASSERT_FATAL(lvs != NULL); + TAILQ_INIT(&lvs->lvols); + g_lvol_store = lvs; + for (i = 0; i < g_num_lvols; i++) { + _lvol_create(lvs); + } + } + + cb_fn(cb_arg, g_lvol_store, g_lvserrno); +} int spdk_bs_bdev_claim(struct spdk_bs_dev *bs_dev, struct spdk_bdev_module_if *module) @@ -97,7 +132,7 @@ spdk_bdev_create_bs_dev(struct spdk_bdev *bdev, spdk_bdev_remove_cb_t remove_cb, { struct spdk_bs_dev *bs_dev; - if (lvol_already_opened == true) + if (lvol_already_opened == true || bdev == NULL) return NULL; bs_dev = calloc(1, sizeof(*bs_dev)); @@ -131,6 +166,7 @@ spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o, } else { lvs = calloc(1, sizeof(*lvs)); SPDK_CU_ASSERT_FATAL(lvs != NULL); + TAILQ_INIT(&lvs->lvols); lvs->bs_dev = bs_dev; error = 0; } @@ -142,6 +178,15 @@ spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o, int spdk_lvs_unload(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, void *cb_arg) { + struct spdk_lvol *lvol; + + while (!TAILQ_EMPTY(&lvs->lvols)) { + lvol = TAILQ_FIRST(&lvs->lvols); + TAILQ_REMOVE(&lvs->lvols, lvol, link); + free(lvol->name); + free(lvol); + } + g_lvol_store = NULL; free(lvs); @@ -185,8 +230,6 @@ spdk_lvol_close(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_ar struct spdk_lvol *iter_lvol, *tmp; bool all_lvols_closed = true; - SPDK_CU_ASSERT_FATAL(lvol == g_lvol); - lvol->ref_count--; TAILQ_FOREACH_SAFE(iter_lvol, &lvol->lvol_store->lvols, link, tmp) { @@ -207,6 +250,7 @@ spdk_lvol_close(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_ar void spdk_lvol_destroy(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg) { + TAILQ_REMOVE(&lvol->lvol_store->lvols, lvol, link); free(lvol->name); free(lvol); g_lvol = NULL; @@ -310,16 +354,17 @@ spdk_bdev_get_name(const struct spdk_bdev *bdev) void spdk_vbdev_register(struct spdk_bdev *vbdev, struct spdk_bdev **base_bdevs, int base_bdev_count) { + g_registered_bdevs++; } void spdk_bdev_module_examine_done(struct spdk_bdev_module_if *module) { + g_examine_done = true; } -int -spdk_lvol_create(struct spdk_lvol_store *lvs, size_t sz, spdk_lvol_op_with_handle_complete cb_fn, - void *cb_arg) +static struct spdk_lvol * +_lvol_create(struct spdk_lvol_store *lvs) { struct spdk_lvol *lvol = calloc(1, sizeof(*lvol)); @@ -330,9 +375,18 @@ spdk_lvol_create(struct spdk_lvol_store *lvs, size_t sz, spdk_lvol_op_with_handl 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); + return lvol; +} + +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; + + lvol = _lvol_create(lvs); cb_fn(cb_arg, lvol, 0); return 0; @@ -396,8 +450,6 @@ ut_lvs_destroy(void) vbdev_lvs_destruct(lvs, lvol_store_op_complete, NULL); CU_ASSERT(g_lvserrno == 0); CU_ASSERT(g_lvol_store == NULL); - free(g_lvol->name); - free(g_lvol); } static void @@ -409,6 +461,7 @@ ut_lvol_init(void) g_lvs = calloc(1, sizeof(*g_lvs)); SPDK_CU_ASSERT_FATAL(g_lvs != NULL); + TAILQ_INIT(&g_lvs->lvols); 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)); @@ -475,6 +528,84 @@ ut_lvol_hotremove(void) } +static void +ut_lvol_examine(void) +{ + struct spdk_bdev *bdev; + + lvol_already_opened = false; + g_bs_dev = NULL; + g_lvserrno = 0; + g_examine_done = false; + + /* Examine with NULL bdev */ + vbdev_lvs_examine(NULL); + CU_ASSERT(g_bs_dev == NULL); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(g_examine_done == true); + + /* Examine unsuccessfully - bdev already opened */ + g_bs_dev = NULL; + g_examine_done = false; + g_lvserrno = -1; + lvol_already_opened = true; + vbdev_lvs_examine(&g_bdev); + CU_ASSERT(g_bs_dev == NULL); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(g_examine_done == true); + + /* Examine unsuccessfully - fail on lvol store */ + g_bs_dev = NULL; + g_examine_done = false; + g_lvserrno = -1; + lvol_already_opened = false; + vbdev_lvs_examine(&g_bdev); + CU_ASSERT(g_bs_dev != NULL); + CU_ASSERT(g_lvol_store == NULL); + CU_ASSERT(g_examine_done == true); + CU_ASSERT(TAILQ_EMPTY(&g_spdk_lvol_pairs)); + free(g_bs_dev); + + /* Examine unsuccesfully - fail on lvol load */ + g_bs_dev = NULL; + g_lvserrno = 0; + g_lvolerrno = -1; + g_num_lvols = 1; + g_examine_done = false; + lvol_already_opened = false; + g_registered_bdevs = 0; + vbdev_lvs_examine(&g_bdev); + CU_ASSERT(g_bs_dev != NULL); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + CU_ASSERT(g_examine_done == true); + CU_ASSERT(g_registered_bdevs == 0); + CU_ASSERT(!TAILQ_EMPTY(&g_spdk_lvol_pairs)); + CU_ASSERT(TAILQ_EMPTY(&g_lvol_store->lvols)); + vbdev_lvs_destruct(g_lvol_store, lvol_store_op_complete, NULL); + free(g_bs_dev); + + /* Examine succesfully */ + g_bs_dev = NULL; + g_lvserrno = 0; + g_lvolerrno = 0; + g_examine_done = false; + g_registered_bdevs = 0; + lvol_already_opened = false; + vbdev_lvs_examine(&g_bdev); + CU_ASSERT(g_bs_dev != NULL); + SPDK_CU_ASSERT_FATAL(g_lvol_store != NULL); + CU_ASSERT(g_examine_done == true); + CU_ASSERT(g_registered_bdevs != 0); + CU_ASSERT(!TAILQ_EMPTY(&g_spdk_lvol_pairs)); + SPDK_CU_ASSERT_FATAL(!TAILQ_EMPTY(&g_lvol_store->lvols)); + TAILQ_FIRST(&g_lvol_store->lvols)->ref_count--; + bdev = TAILQ_FIRST(&g_lvol_store->lvols)->bdev; + vbdev_lvs_destruct(g_lvol_store, lvol_store_op_complete, NULL); + free(bdev); + free(g_bs_dev); + free(g_lvol_store); +} + static void ut_lvol_resize(void) { @@ -483,6 +614,9 @@ ut_lvol_resize(void) g_lvs = calloc(1, sizeof(*g_lvs)); SPDK_CU_ASSERT_FATAL(g_lvs != NULL); + + TAILQ_INIT(&g_lvs->lvols); + 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)); @@ -736,7 +870,8 @@ int main(int argc, char **argv) CU_add_test(suite, "ut_lvol_op_comp", ut_lvol_op_comp) == NULL || CU_add_test(suite, "ut_lvol_flush", ut_lvol_flush) == NULL || CU_add_test(suite, "ut_lvol_read_write", ut_lvol_read_write) == NULL || - CU_add_test(suite, "ut_vbdev_lvol_submit_request", ut_vbdev_lvol_submit_request) == NULL + CU_add_test(suite, "ut_vbdev_lvol_submit_request", ut_vbdev_lvol_submit_request) == NULL || + CU_add_test(suite, "lvol_examine", ut_lvol_examine) == NULL ) { CU_cleanup_registry(); return CU_get_error(); diff --git a/test/unit/lib/lvol/lvol.c/lvol_ut.c b/test/unit/lib/lvol/lvol.c/lvol_ut.c index 9141fa3c47..514ec06157 100644 --- a/test/unit/lib/lvol/lvol.c/lvol_ut.c +++ b/test/unit/lib/lvol/lvol.c/lvol_ut.c @@ -51,8 +51,22 @@ #define SPDK_BLOB_OPTS_MAX_MD_OPS 32 #define SPDK_BLOB_OPTS_MAX_CHANNEL_OPS 512 +const char *uuid = "828d9766-ae50-11e7-bd8d-001e67edf35d"; + +struct spdk_blob { + spdk_blob_id id; +}; + +int g_lvolerrno; int g_lvserrno; +int g_bs_load_status; +int g_get_super_status; +int g_open_blob_status; +int g_get_uuid_status; +int g_close_super_status; int g_resize_rc; +int g_lvols_count; +int g_fail_on_n_lvol_load = 0xFF; struct spdk_lvol_store *g_lvol_store; struct spdk_lvol *g_lvol; struct spdk_bs_opts g_bs_opts; @@ -60,6 +74,57 @@ struct spdk_bs_opts g_bs_opts; struct spdk_blob_store { int stub; }; +struct spdk_blob_store *g_blob_store; +struct spdk_blob *g_blob; + +static void +bs_iter(void) +{ + if (g_lvols_count > 0) { + g_blob = calloc(1, sizeof(*g_blob)); + SPDK_CU_ASSERT_FATAL(g_blob != NULL); + g_blob->id = g_lvols_count + 1; /* skip super blob */ + g_lvols_count--; + g_fail_on_n_lvol_load--; + } else { + g_lvolerrno = -ENOENT; + } + + if (g_fail_on_n_lvol_load == 0) { + g_lvolerrno = -1; + } +} + +void +spdk_bs_md_iter_next(struct spdk_blob_store *bs, struct spdk_blob **b, + spdk_blob_op_with_handle_complete cb_fn, void *cb_arg) +{ + free(g_blob); + bs_iter(); + + cb_fn(cb_arg, g_blob, g_lvolerrno); +} + +void +spdk_bs_md_iter_first(struct spdk_blob_store *bs, + spdk_blob_op_with_handle_complete cb_fn, void *cb_arg) +{ + bs_iter(); + + cb_fn(cb_arg, g_blob, g_lvolerrno); +} + +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) +{ + cb_fn(cb_arg, 0, g_get_super_status); +} void spdk_bs_set_super(struct spdk_blob_store *bs, spdk_blob_id blobid, @@ -68,6 +133,18 @@ spdk_bs_set_super(struct spdk_blob_store *bs, spdk_blob_id 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) +{ + if (g_bs_load_status == 0) { + g_blob_store = calloc(1, sizeof(*g_blob_store)); + SPDK_CU_ASSERT_FATAL(g_blob_store != NULL); + } + + cb_fn(cb_arg, g_blob_store, g_bs_load_status); +} + struct spdk_io_channel *spdk_bs_alloc_io_channel(struct spdk_blob_store *bs) { return NULL; @@ -80,6 +157,16 @@ spdk_blob_md_set_xattr(struct spdk_blob *blob, const char *name, const void *val return 0; } +int +spdk_bs_md_get_xattr_value(struct spdk_blob *blob, const char *name, + const void **value, size_t *value_len) +{ + *value = uuid; + *value_len = UUID_STRING_LEN; + + return g_get_uuid_status; +} + uint64_t spdk_bs_get_page_size(struct spdk_blob_store *bs) { @@ -101,6 +188,7 @@ spdk_bs_init(struct spdk_bs_dev *dev, struct spdk_bs_opts *o, struct spdk_blob_store *bs; bs = calloc(1, sizeof(*bs)); + SPDK_CU_ASSERT_FATAL(bs != NULL); memcpy(&g_bs_opts, o, sizeof(struct spdk_bs_opts)); @@ -134,8 +222,7 @@ spdk_bs_md_delete_blob(struct spdk_blob_store *bs, spdk_blob_id blobid, spdk_blob_id spdk_blob_get_id(struct spdk_blob *blob) { - spdk_blob_id id = 0; - return id; + return blob->id; } void @@ -145,6 +232,7 @@ spdk_bs_opts_init(struct spdk_bs_opts *opts) 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 @@ -156,7 +244,9 @@ spdk_bs_get_cluster_size(struct spdk_blob_store *bs) void spdk_bs_md_close_blob(struct spdk_blob **b, spdk_blob_op_complete cb_fn, void *cb_arg) { - cb_fn(cb_arg, 0); + free(g_blob); + + cb_fn(cb_arg, g_close_super_status); } int @@ -176,7 +266,12 @@ void spdk_bs_md_open_blob(struct spdk_blob_store *bs, spdk_blob_id blobid, spdk_blob_op_with_handle_complete cb_fn, void *cb_arg) { - cb_fn(cb_arg, NULL, 0); + if (g_open_blob_status == 0) { + g_blob = calloc(1, sizeof(*g_blob)); + SPDK_CU_ASSERT_FATAL(g_blob != NULL); + } + + cb_fn(cb_arg, g_blob, g_open_blob_status); } uint64_t @@ -610,6 +705,114 @@ lvol_resize(void) spdk_free_thread(); } +static void +lvs_load(void) +{ + int rc = -1; + struct spdk_bs_dev bs_dev; + struct spdk_lvs_with_handle_req *req; + + req = calloc(1, sizeof(*req)); + SPDK_CU_ASSERT_FATAL(req != NULL); + + init_dev(&bs_dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL); + + /* Fail on bs load */ + g_bs_load_status = -1; + spdk_lvs_load(&bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno != 0); + CU_ASSERT(g_lvol_store == NULL); + + /* Fail on getting super blob */ + g_bs_load_status = 0; + g_get_super_status = -1; + spdk_lvs_load(&bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == -ENODEV); + CU_ASSERT(g_lvol_store == NULL); + + /* Fail on opening super blob */ + g_lvserrno = 0; + g_get_super_status = 0; + g_open_blob_status = -1; + spdk_lvs_load(&bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == -ENODEV); + CU_ASSERT(g_lvol_store == NULL); + + /* Fail on getting uuid */ + g_lvserrno = 0; + g_get_super_status = 0; + g_open_blob_status = 0; + g_get_uuid_status = -1; + spdk_lvs_load(&bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == -ENODEV); + CU_ASSERT(g_lvol_store == NULL); + + /* Fail on closing super blob */ + g_lvserrno = 0; + g_get_super_status = 0; + g_open_blob_status = 0; + g_get_uuid_status = 0; + g_close_super_status = -1; + spdk_lvs_load(&bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == -ENODEV); + CU_ASSERT(g_lvol_store == NULL); + + /* Load successfully */ + g_lvserrno = 0; + g_get_super_status = 0; + g_open_blob_status = 0; + g_get_uuid_status = 0; + g_close_super_status = 0; + spdk_lvs_load(&bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(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); + + free(req); + + spdk_free_thread(); +} + +static void +lvols_load(void) +{ + int rc = -1; + struct spdk_bs_dev bs_dev; + struct spdk_lvs_with_handle_req *req; + + req = calloc(1, sizeof(*req)); + SPDK_CU_ASSERT_FATAL(req != NULL); + + init_dev(&bs_dev); + + spdk_allocate_thread(_lvol_send_msg, NULL, NULL); + + /* Load lvs */ + g_lvserrno = 0; + g_get_super_status = 0; + g_open_blob_status = 0; + g_get_uuid_status = 0; + g_close_super_status = 0; + spdk_lvs_load(&bs_dev, lvol_store_op_with_handle_complete, req); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(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); + + free(req); + + spdk_free_thread(); +} + int main(int argc, char **argv) { CU_pSuite suite = NULL; @@ -635,7 +838,9 @@ int main(int argc, char **argv) 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, "lvol_resize", lvol_resize) == NULL || + CU_add_test(suite, "lvol_load", lvs_load) == NULL || + CU_add_test(suite, "lvs_load", lvols_load) == NULL ) { CU_cleanup_registry(); return CU_get_error();