diff --git a/include/spdk_internal/bdev.h b/include/spdk_internal/bdev.h index 2b49819aa..f8dbb8994 100644 --- a/include/spdk_internal/bdev.h +++ b/include/spdk_internal/bdev.h @@ -182,6 +182,11 @@ enum spdk_bdev_io_status { SPDK_BDEV_IO_STATUS_SUCCESS = 1, }; +struct spdk_bdev_alias { + char *alias; + TAILQ_ENTRY(spdk_bdev_alias) tailq; +}; + struct spdk_bdev { /** User context passed in by the backend */ void *ctxt; @@ -189,6 +194,9 @@ struct spdk_bdev { /** Unique name for this block device. */ char *name; + /** Unique aliases for this block device. */ + TAILQ_HEAD(spdk_bdev_aliases_list, spdk_bdev_alias) aliases; + /** Unique product name for this kind of block device. */ char *product_name; @@ -396,6 +404,31 @@ int spdk_bdev_module_claim_bdev(struct spdk_bdev *bdev, struct spdk_bdev_desc *d struct spdk_bdev_module_if *module); void spdk_bdev_module_release_bdev(struct spdk_bdev *bdev); +/** + * Add alias to block device names list. + * Aliases can be add only to registered bdev. + * + * \param bdev Block device to query. + * \param alias Alias to be added to list. + * + * Return codes + * \return 0 on success + * \return -EEXIST if alias already exists as name or alias on any bdev + * \return -ENOMEM if memory cannot be allocated to store alias + * \return -EINVAL if passed alias is empty + */ +int spdk_bdev_alias_add(struct spdk_bdev *bdev, const char *alias); + +/** + * Removes name from block device names list. + * + * \param bdev Block device to query. + * \param alias Alias to be deleted from list. + * \return 0 on success + * \return -ENOENT if alias does not exists + */ +int spdk_bdev_alias_del(struct spdk_bdev *bdev, const char *alias); + /** * Allocate a buffer for given bdev_io. Allocation will happen * only if the bdev_io has no assigned SGL yet. The buffer will be diff --git a/lib/bdev/bdev.c b/lib/bdev/bdev.c index c3aa063a5..41533634a 100644 --- a/lib/bdev/bdev.c +++ b/lib/bdev/bdev.c @@ -237,12 +237,20 @@ spdk_bdev_next_leaf(struct spdk_bdev *prev) struct spdk_bdev * spdk_bdev_get_by_name(const char *bdev_name) { + struct spdk_bdev_alias *tmp; struct spdk_bdev *bdev = spdk_bdev_first(); while (bdev != NULL) { if (strcmp(bdev_name, bdev->name) == 0) { return bdev; } + + TAILQ_FOREACH(tmp, &bdev->aliases, tailq) { + if (strcmp(bdev_name, tmp->alias) == 0) { + return bdev; + } + } + bdev = spdk_bdev_next(bdev); } @@ -942,6 +950,58 @@ spdk_bdev_channel_destroy(void *io_device, void *ctx_buf) assert(ch->io_outstanding == 0); } +int +spdk_bdev_alias_add(struct spdk_bdev *bdev, const char *alias) +{ + struct spdk_bdev_alias *tmp; + + if (alias == NULL) { + SPDK_ERRLOG("Empty alias passed\n"); + return -EINVAL; + } + + if (spdk_bdev_get_by_name(alias)) { + SPDK_ERRLOG("Bdev name/alias: %s already exists\n", alias); + return -EEXIST; + } + + tmp = calloc(1, sizeof(*tmp)); + if (tmp == NULL) { + SPDK_ERRLOG("Unable to allocate alias\n"); + return -ENOMEM; + } + + tmp->alias = strdup(alias); + if (tmp->alias == NULL) { + free(tmp); + SPDK_ERRLOG("Unable to allocate alias\n"); + return -ENOMEM; + } + + TAILQ_INSERT_TAIL(&bdev->aliases, tmp, tailq); + + return 0; +} + +int +spdk_bdev_alias_del(struct spdk_bdev *bdev, const char *alias) +{ + struct spdk_bdev_alias *tmp; + + TAILQ_FOREACH(tmp, &bdev->aliases, tailq) { + if (strcmp(alias, tmp->alias) == 0) { + TAILQ_REMOVE(&bdev->aliases, tmp, tailq); + free(tmp->alias); + free(tmp); + return 0; + } + } + + SPDK_INFOLOG(SPDK_LOG_BDEV, "Alias %s does not exists\n", alias); + + return -ENOENT; +} + struct spdk_io_channel * spdk_bdev_get_io_channel(struct spdk_bdev_desc *desc) { @@ -1917,6 +1977,8 @@ _spdk_bdev_register(struct spdk_bdev *bdev) TAILQ_INIT(&bdev->vbdevs); TAILQ_INIT(&bdev->base_bdevs); + TAILQ_INIT(&bdev->aliases); + bdev->reset_in_progress = NULL; spdk_io_device_register(bdev, spdk_bdev_channel_create, spdk_bdev_channel_destroy, diff --git a/test/unit/lib/bdev/bdev.c/bdev_ut.c b/test/unit/lib/bdev/bdev.c/bdev_ut.c index 9416ae076..98d635e85 100644 --- a/test/unit/lib/bdev/bdev.c/bdev_ut.c +++ b/test/unit/lib/bdev/bdev.c/bdev_ut.c @@ -83,6 +83,7 @@ static struct spdk_bdev * allocate_bdev(char *name) { struct spdk_bdev *bdev; + int rc; bdev = calloc(1, sizeof(*bdev)); SPDK_CU_ASSERT_FATAL(bdev != NULL); @@ -91,7 +92,8 @@ allocate_bdev(char *name) bdev->fn_table = &fn_table; bdev->module = SPDK_GET_BDEV_MODULE(bdev_ut); - spdk_bdev_register(bdev); + rc = spdk_bdev_register(bdev); + CU_ASSERT(rc == 0); CU_ASSERT(TAILQ_EMPTY(&bdev->base_bdevs)); CU_ASSERT(TAILQ_EMPTY(&bdev->vbdevs)); @@ -103,6 +105,7 @@ allocate_vbdev(char *name, struct spdk_bdev *base1, struct spdk_bdev *base2) { struct spdk_bdev *bdev; struct spdk_bdev *array[2]; + int rc; bdev = calloc(1, sizeof(*bdev)); SPDK_CU_ASSERT_FATAL(bdev != NULL); @@ -117,7 +120,8 @@ allocate_vbdev(char *name, struct spdk_bdev *base1, struct spdk_bdev *base2) array[0] = base1; array[1] = base2; - spdk_vbdev_register(bdev, array, base2 == NULL ? 1 : 2); + rc = spdk_vbdev_register(bdev, array, base2 == NULL ? 1 : 2); + CU_ASSERT(rc == 0); CU_ASSERT(!TAILQ_EMPTY(&bdev->base_bdevs)); CU_ASSERT(TAILQ_EMPTY(&bdev->vbdevs)); @@ -333,6 +337,7 @@ part_test(void) struct spdk_bdev_part part1, part2; struct spdk_bdev bdev_base = {}; SPDK_BDEV_PART_TAILQ tailq = TAILQ_HEAD_INITIALIZER(tailq); + int rc; base = calloc(1, sizeof(*base)); SPDK_CU_ASSERT_FATAL(base != NULL); @@ -340,7 +345,8 @@ part_test(void) bdev_base.name = "base"; bdev_base.fn_table = &base_fn_table; bdev_base.module = SPDK_GET_BDEV_MODULE(bdev_ut); - spdk_bdev_register(&bdev_base); + rc = spdk_bdev_register(&bdev_base); + CU_ASSERT(rc == 0); spdk_bdev_part_base_construct(base, &bdev_base, NULL, SPDK_GET_BDEV_MODULE(vbdev_ut), &part_fn_table, &tailq, __base_free, 0, NULL, NULL); @@ -359,6 +365,73 @@ part_test(void) spdk_bdev_unregister(&bdev_base, NULL, NULL); } +static void +alias_add_del_test(void) +{ + struct spdk_bdev *bdev[2]; + int rc; + + /* Creating and registering bdevs */ + bdev[0] = allocate_bdev("bdev0"); + SPDK_CU_ASSERT_FATAL(bdev[0] != 0); + + bdev[1] = allocate_bdev("bdev1"); + SPDK_CU_ASSERT_FATAL(bdev[1] != 0); + + /* + * Trying adding an alias identical to name. + * Alias is identical to name, so it can not be added to aliases list + */ + rc = spdk_bdev_alias_add(bdev[0], bdev[0]->name); + CU_ASSERT(rc == -EEXIST); + + /* + * Trying to add empty alias, + * this one should fail + */ + rc = spdk_bdev_alias_add(bdev[0], NULL); + CU_ASSERT(rc == -EINVAL); + + /* Trying adding same alias to two different registered bdevs */ + + /* Alias is used first time, so this one should pass */ + rc = spdk_bdev_alias_add(bdev[0], "proper alias 0"); + CU_ASSERT(rc == 0); + + /* Alias was added to another bdev, so this one should fail */ + rc = spdk_bdev_alias_add(bdev[1], "proper alias 0"); + CU_ASSERT(rc == -EEXIST); + + /* Alias is used first time, so this one should pass */ + rc = spdk_bdev_alias_add(bdev[1], "proper alias 1"); + CU_ASSERT(rc == 0); + + /* Trying removing an alias from registered bdevs */ + + /* Alias is not on a bdev aliases list, so this one should fail */ + rc = spdk_bdev_alias_del(bdev[0], "not existing"); + CU_ASSERT(rc == -ENOENT); + + /* Alias is present on a bdev aliases list, so this one should pass */ + rc = spdk_bdev_alias_del(bdev[0], "proper alias 0"); + CU_ASSERT(rc == 0); + + /* Alias is present on a bdev aliases list, so this one should pass */ + rc = spdk_bdev_alias_del(bdev[1], "proper alias 1"); + CU_ASSERT(rc == 0); + + /* Trying to remove name instead of alias, so this one should fail, name cannot be changed or removed */ + rc = spdk_bdev_alias_del(bdev[0], bdev[0]->name); + CU_ASSERT(rc != 0); + + /* Unregister and free bdevs */ + spdk_bdev_unregister(bdev[0], NULL, NULL); + spdk_bdev_unregister(bdev[1], NULL, NULL); + + free(bdev[0]); + free(bdev[1]); +} + int main(int argc, char **argv) { @@ -379,7 +452,8 @@ main(int argc, char **argv) CU_add_test(suite, "bytes_to_blocks_test", bytes_to_blocks_test) == NULL || CU_add_test(suite, "io_valid", io_valid_test) == NULL || CU_add_test(suite, "open_write", open_write_test) == NULL || - CU_add_test(suite, "part", part_test) == NULL + CU_add_test(suite, "part", part_test) == NULL || + CU_add_test(suite, "alias_add_del", alias_add_del_test) == NULL ) { CU_cleanup_registry(); return CU_get_error();