diff --git a/CHANGELOG.md b/CHANGELOG.md index 004b223e8..a5e3ee5bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,9 @@ New function `spdk_env_get_main_core` was added. New API `spdk_lvol_iter_immediate_clones` was added to iterate the clones of an lvol. +New APIs `spdk_lvol_get_by_uuid` and `spdk_lvol_get_by_names` to get lvols by the lvol's UUID or +lvstore and lvol names. + ### nvmf New `spdk_nvmf_request_copy_to/from_buf()` APIs have been added, which support diff --git a/include/spdk/lvol.h b/include/spdk/lvol.h index dd9b0fafd..c362ae936 100644 --- a/include/spdk/lvol.h +++ b/include/spdk/lvol.h @@ -13,6 +13,7 @@ #include "spdk/stdinc.h" #include "spdk/blob.h" +#include "spdk/uuid.h" #ifdef __cplusplus extern "C" { @@ -281,6 +282,23 @@ void spdk_lvol_close(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void * */ int spdk_lvol_iter_immediate_clones(struct spdk_lvol *lvol, spdk_lvol_iter_cb cb_fn, void *cb_arg); +/** + * Get the lvol that has a particular UUID. + * + * \param uuid The lvol's UUID. + * \return A pointer to the requested lvol on success, else NULL. + */ +struct spdk_lvol *spdk_lvol_get_by_uuid(const struct spdk_uuid *uuid); + +/** + * Get the lvol that has the specified name in the specified lvolstore. + * + * \param lvs_name Name of the lvolstore. + * \param lvol_name Name ofthe lvol. + * \return A pointer to the requested lvol on success, else NULL. + */ +struct spdk_lvol *spdk_lvol_get_by_names(const char *lvs_name, const char *lvol_name); + /** * Get I/O channel of bdev associated with specified lvol. * diff --git a/lib/lvol/lvol.c b/lib/lvol/lvol.c index a4fbbadd3..bd68893bf 100644 --- a/lib/lvol/lvol.c +++ b/lib/lvol/lvol.c @@ -2114,3 +2114,48 @@ spdk_lvol_iter_immediate_clones(struct spdk_lvol *lvol, spdk_lvol_iter_cb cb_fn, free(ids); return rc; } + +struct spdk_lvol * +spdk_lvol_get_by_uuid(const struct spdk_uuid *uuid) +{ + struct spdk_lvol_store *lvs; + struct spdk_lvol *lvol; + + pthread_mutex_lock(&g_lvol_stores_mutex); + + TAILQ_FOREACH(lvs, &g_lvol_stores, link) { + TAILQ_FOREACH(lvol, &lvs->lvols, link) { + if (spdk_uuid_compare(uuid, &lvol->uuid) == 0) { + pthread_mutex_unlock(&g_lvol_stores_mutex); + return lvol; + } + } + } + + pthread_mutex_unlock(&g_lvol_stores_mutex); + return NULL; +} + +struct spdk_lvol * +spdk_lvol_get_by_names(const char *lvs_name, const char *lvol_name) +{ + struct spdk_lvol_store *lvs; + struct spdk_lvol *lvol; + + pthread_mutex_lock(&g_lvol_stores_mutex); + + TAILQ_FOREACH(lvs, &g_lvol_stores, link) { + if (strcmp(lvs_name, lvs->name) != 0) { + continue; + } + TAILQ_FOREACH(lvol, &lvs->lvols, link) { + if (strcmp(lvol_name, lvol->name) == 0) { + pthread_mutex_unlock(&g_lvol_stores_mutex); + return lvol; + } + } + } + + pthread_mutex_unlock(&g_lvol_stores_mutex); + return NULL; +} diff --git a/lib/lvol/spdk_lvol.map b/lib/lvol/spdk_lvol.map index 879b96ac6..ab169af12 100644 --- a/lib/lvol/spdk_lvol.map +++ b/lib/lvol/spdk_lvol.map @@ -23,6 +23,8 @@ spdk_lvol_decouple_parent; spdk_lvol_create_esnap_clone; spdk_lvol_iter_immediate_clones; + spdk_lvol_get_by_uuid; + spdk_lvol_get_by_names; # internal functions spdk_lvol_resize; diff --git a/test/unit/lib/lvol/lvol.c/lvol_ut.c b/test/unit/lib/lvol/lvol.c/lvol_ut.c index 9ce8fc21f..c99af211b 100644 --- a/test/unit/lib/lvol/lvol.c/lvol_ut.c +++ b/test/unit/lib/lvol/lvol.c/lvol_ut.c @@ -3167,6 +3167,118 @@ lvol_esnap_hotplug(void) } } +static void +lvol_get_by(void) +{ + struct lvol_ut_bs_dev dev1, dev2; + struct spdk_lvol_store *lvs1, *lvs2; + struct spdk_lvol *lvol1, *lvol2, *lvol3; + struct spdk_lvs_opts opts; + int rc = 0; + struct spdk_uuid uuid; + + init_dev(&dev1); + + spdk_lvs_opts_init(&opts); + snprintf(opts.name, sizeof(opts.name), "lvs"); + + g_lvserrno = -1; + rc = spdk_lvs_init(&dev1.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); + lvs1 = g_lvol_store; + + /* Create lvol name "lvol" */ + spdk_lvol_create(lvs1, "lvol", 10, true, LVOL_CLEAR_WITH_DEFAULT, + lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + lvol1 = g_lvol; + + /* Should be able to look up lvol1 by its name and UUID */ + CU_ASSERT(spdk_lvol_get_by_names("lvs", "lvol") == lvol1); + /* Be sure a pointer comparison isn't used. */ + memcpy(&uuid, &lvol1->uuid, sizeof(uuid)); + CU_ASSERT(spdk_lvol_get_by_uuid(&uuid) == lvol1); + + /* Shorter and longer values for lvol_name must not match. */ + CU_ASSERT(spdk_lvol_get_by_names("lvs", "lvoll") == NULL); + CU_ASSERT(spdk_lvol_get_by_names("lvs", "lvo") == NULL); + + /* Shorter and longer values for lvs_name must not match. */ + CU_ASSERT(spdk_lvol_get_by_names("lvss", "lvol") == NULL); + CU_ASSERT(spdk_lvol_get_by_names("lv", "lvol") == NULL); + + /* Create lvol name "lvol2" */ + spdk_lvol_create(lvs1, "lvol2", 10, true, LVOL_CLEAR_WITH_DEFAULT, + lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + lvol2 = g_lvol; + + /* When there are multiple lvols, the right one is found */ + CU_ASSERT(spdk_lvol_get_by_names("lvs", "lvol") == lvol1); + CU_ASSERT(spdk_lvol_get_by_names("lvs", "lvol2") == lvol2); + + /* Create a second lvolstore */ + init_dev(&dev2); + snprintf(opts.name, sizeof(opts.name), "lvs2"); + g_lvserrno = -1; + rc = spdk_lvs_init(&dev2.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; + + /* Lookups that worked with one lvstore still work */ + memcpy(&uuid, &lvol1->uuid, sizeof(uuid)); + CU_ASSERT(spdk_lvol_get_by_uuid(&uuid) == lvol1); + CU_ASSERT(spdk_lvol_get_by_names("lvs", "lvol") == lvol1); + CU_ASSERT(spdk_lvol_get_by_names("lvs", "lvol2") == lvol2); + + /* Add an lvol name "lvol" in the second lvstore */ + spdk_lvol_create(lvs2, "lvol", 10, true, LVOL_CLEAR_WITH_DEFAULT, + lvol_op_with_handle_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + SPDK_CU_ASSERT_FATAL(g_lvol != NULL); + lvol3 = g_lvol; + + /* Lookups by name find the lvols in the right lvstores */ + CU_ASSERT(spdk_lvol_get_by_names("lvs", "lvol") == lvol1); + CU_ASSERT(spdk_lvol_get_by_names("lvs", "lvol2") == lvol2); + CU_ASSERT(spdk_lvol_get_by_names("lvs2", "lvol") == lvol3); + + /* Clean up */ + g_lvserrno = -1; + spdk_lvol_close(lvol1, op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + spdk_lvol_close(lvol2, op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + spdk_lvol_close(lvol3, op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(lvs1, op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + + g_lvserrno = -1; + rc = spdk_lvs_unload(lvs2, op_complete, NULL); + CU_ASSERT(rc == 0); + CU_ASSERT(g_lvserrno == 0); + + g_lvol_store = NULL; + g_lvol = NULL; + + free_dev(&dev1); + free_dev(&dev2); +} + int main(int argc, char **argv) { @@ -3212,6 +3324,7 @@ main(int argc, char **argv) CU_ADD_TEST(suite, lvol_esnap_load_esnaps); CU_ADD_TEST(suite, lvol_esnap_missing); CU_ADD_TEST(suite, lvol_esnap_hotplug); + CU_ADD_TEST(suite, lvol_get_by); allocate_threads(1); set_thread(0);