diff --git a/CHANGELOG.md b/CHANGELOG.md index c05404896..bb9e045bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,10 @@ receive and send the I/O management commands. New `spdk_nvmf_transport_create_async` was added, it accepts a callback and callback argument. `spdk_nvmf_transport_create` is marked deprecated. +### part + +New API `spdk_bdev_part_construct_ext` is added and allows the bdev's UUID to be specified. + ### examples `examples/nvme/perf` application now accepts `--use-every-core` parameter that changes diff --git a/include/spdk/bdev_module.h b/include/spdk/bdev_module.h index b1622ec68..3d6038932 100644 --- a/include/spdk/bdev_module.h +++ b/include/spdk/bdev_module.h @@ -1463,6 +1463,24 @@ int spdk_bdev_part_base_construct_ext(const char *bdev_name, spdk_io_channel_destroy_cb ch_destroy_cb, struct spdk_bdev_part_base **base); +/** Options used when constructing a part bdev. */ +struct spdk_bdev_part_construct_opts { + /* Size of this structure in bytes */ + uint64_t opts_size; + /** UUID of the bdev */ + struct spdk_uuid uuid; +}; + +SPDK_STATIC_ASSERT(sizeof(struct spdk_bdev_part_construct_opts) == 24, "Incorrect size"); + +/** + * Initialize options that will be passed to spdk_bdev_part_construct_ext(). + * + * \param opts Options structure to initialize + * \param size Size of opts structure. + */ +void spdk_bdev_part_construct_opts_init(struct spdk_bdev_part_construct_opts *opts, uint64_t size); + /** * Create a logical spdk_bdev_part on top of a base. * @@ -1480,6 +1498,25 @@ int spdk_bdev_part_construct(struct spdk_bdev_part *part, struct spdk_bdev_part_ char *name, uint64_t offset_blocks, uint64_t num_blocks, char *product_name); +/** + * Create a logical spdk_bdev_part on top of a base with a non-NULL bdev UUID + * + * \param part The part object allocated by the user. + * \param base The base from which to create the part. + * \param name The name of the new spdk_bdev_part. + * \param offset_blocks The offset into the base bdev at which this part begins. + * \param num_blocks The number of blocks that this part will span. + * \param product_name Unique name for this type of block device. + * \param opts Additional options. + * + * \return 0 on success. + * \return -1 if the bases underlying bdev cannot be claimed by the current module. + */ +int spdk_bdev_part_construct_ext(struct spdk_bdev_part *part, struct spdk_bdev_part_base *base, + char *name, uint64_t offset_blocks, uint64_t num_blocks, + char *product_name, + const struct spdk_bdev_part_construct_opts *opts); + /** * Forwards I/O from an spdk_bdev_part to the underlying base bdev. * diff --git a/lib/bdev/part.c b/lib/bdev/part.c index c53422cea..53d7bc45c 100644 --- a/lib/bdev/part.c +++ b/lib/bdev/part.c @@ -497,13 +497,68 @@ spdk_bdev_part_base_construct_ext(const char *bdev_name, return 0; } +void +spdk_bdev_part_construct_opts_init(struct spdk_bdev_part_construct_opts *opts, uint64_t size) +{ + if (opts == NULL) { + SPDK_ERRLOG("opts should not be NULL\n"); + assert(opts != NULL); + return; + } + if (size == 0) { + SPDK_ERRLOG("size should not be zero\n"); + assert(size != 0); + return; + } + + memset(opts, 0, size); + opts->opts_size = size; +} + +static void +part_construct_opts_copy(const struct spdk_bdev_part_construct_opts *src, + struct spdk_bdev_part_construct_opts *dst) +{ + if (src->opts_size == 0) { + SPDK_ERRLOG("size should not be zero\n"); + assert(false); + } + + memset(dst, 0, sizeof(*dst)); + dst->opts_size = src->opts_size; + +#define FIELD_OK(field) \ + offsetof(struct spdk_bdev_part_construct_opts, field) + sizeof(src->field) <= src->opts_size + +#define SET_FIELD(field) \ + if (FIELD_OK(field)) { \ + dst->field = src->field; \ + } \ + + SET_FIELD(uuid); + + /* You should not remove this statement, but need to update the assert statement + * if you add a new field, and also add a corresponding SET_FIELD statement */ + SPDK_STATIC_ASSERT(sizeof(struct spdk_bdev_part_construct_opts) == 24, "Incorrect size"); + +#undef FIELD_OK +#undef SET_FIELD +} + int -spdk_bdev_part_construct(struct spdk_bdev_part *part, struct spdk_bdev_part_base *base, - char *name, uint64_t offset_blocks, uint64_t num_blocks, - char *product_name) +spdk_bdev_part_construct_ext(struct spdk_bdev_part *part, struct spdk_bdev_part_base *base, + char *name, uint64_t offset_blocks, uint64_t num_blocks, + char *product_name, const struct spdk_bdev_part_construct_opts *_opts) { int rc; bool first_claimed = false; + struct spdk_bdev_part_construct_opts opts; + + if (_opts == NULL) { + spdk_bdev_part_construct_opts_init(&opts, sizeof(opts)); + } else { + part_construct_opts_copy(_opts, &opts); + } part->internal.bdev.blocklen = base->bdev->blocklen; part->internal.bdev.blockcnt = num_blocks; @@ -535,6 +590,8 @@ spdk_bdev_part_construct(struct spdk_bdev_part *part, struct spdk_bdev_part_base return -1; } + spdk_uuid_copy(&part->internal.bdev.uuid, &opts.uuid); + base->ref++; part->internal.base = base; @@ -575,3 +632,12 @@ spdk_bdev_part_construct(struct spdk_bdev_part *part, struct spdk_bdev_part_base return rc; } + +int +spdk_bdev_part_construct(struct spdk_bdev_part *part, struct spdk_bdev_part_base *base, + char *name, uint64_t offset_blocks, uint64_t num_blocks, + char *product_name) +{ + return spdk_bdev_part_construct_ext(part, base, name, offset_blocks, num_blocks, + product_name, NULL); +} diff --git a/lib/bdev/spdk_bdev.map b/lib/bdev/spdk_bdev.map index c836246a3..15c8f43b2 100644 --- a/lib/bdev/spdk_bdev.map +++ b/lib/bdev/spdk_bdev.map @@ -152,7 +152,9 @@ spdk_bdev_part_free; spdk_bdev_part_base_hotremove; spdk_bdev_part_base_construct_ext; + spdk_bdev_part_construct_opts_init; spdk_bdev_part_construct; + spdk_bdev_part_construct_ext; spdk_bdev_part_submit_request; spdk_bdev_part_submit_request_ext; spdk_bdev_part_get_bdev; diff --git a/test/unit/lib/bdev/part.c/part_ut.c b/test/unit/lib/bdev/part.c/part_ut.c index fdbceb048..f84f5c152 100644 --- a/test/unit/lib/bdev/part.c/part_ut.c +++ b/test/unit/lib/bdev/part.c/part_ut.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright (C) 2018 Intel Corporation. * All rights reserved. + * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ #include "spdk_cunit.h" @@ -393,6 +394,48 @@ part_get_io_channel_test(void) ut_fini_bdev(); } +static void +part_construct_ext(void) +{ + struct spdk_bdev_part_base *base; + struct spdk_bdev_part part1 = {}; + struct spdk_bdev bdev_base = {}; + SPDK_BDEV_PART_TAILQ tailq = TAILQ_HEAD_INITIALIZER(tailq); + const char *uuid = "7ed764b7-a841-41b1-ba93-6548d9335a44"; + struct spdk_bdev_part_construct_opts opts; + int rc; + + bdev_base.name = "base"; + bdev_base.fn_table = &base_fn_table; + bdev_base.module = &bdev_ut_if; + rc = spdk_bdev_register(&bdev_base); + CU_ASSERT(rc == 0); + rc = spdk_bdev_part_base_construct_ext("base", NULL, &vbdev_ut_if, + &part_fn_table, &tailq, NULL, + NULL, 0, NULL, NULL, &base); + + CU_ASSERT(rc == 0); + SPDK_CU_ASSERT_FATAL(base != NULL); + + /* Verify opts.uuid is used as bdev UUID */ + spdk_bdev_part_construct_opts_init(&opts, sizeof(opts)); + spdk_uuid_parse(&opts.uuid, uuid); + rc = spdk_bdev_part_construct_ext(&part1, base, "test1", 0, 100, "test", &opts); + SPDK_CU_ASSERT_FATAL(rc == 0); + SPDK_CU_ASSERT_FATAL(base->ref == 1); + SPDK_CU_ASSERT_FATAL(base->claimed == true); + CU_ASSERT(spdk_bdev_get_by_name(uuid) != NULL); + CU_ASSERT(spdk_bdev_get_by_name("test1") != NULL); + + /* Clean up */ + spdk_bdev_part_base_hotremove(base, &tailq); + spdk_bdev_part_base_free(base); + _part_cleanup(&part1); + spdk_bdev_unregister(&bdev_base, NULL, NULL); + + poll_threads(); +} + int main(int argc, char **argv) { @@ -407,6 +450,7 @@ main(int argc, char **argv) CU_ADD_TEST(suite, part_test); CU_ADD_TEST(suite, part_free_test); CU_ADD_TEST(suite, part_get_io_channel_test); + CU_ADD_TEST(suite, part_construct_ext); allocate_cores(1); allocate_threads(1);