From be54ccc4a980fa8f2c9e9015f739949e08eee3e3 Mon Sep 17 00:00:00 2001 From: Mike Gerdts Date: Thu, 26 Jan 2023 22:49:19 -0600 Subject: [PATCH] vbdev_lvol: allow creation of esnap clones This adds the ability for create esnap clone lvol bdevs. Signed-off-by: Mike Gerdts Change-Id: Ifeef983430153d84d896d282fe914c6671283762 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16590 Reviewed-by: Ben Walker Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris --- module/bdev/lvol/vbdev_lvol.c | 76 +++++++++++ module/bdev/lvol/vbdev_lvol.h | 5 +- .../lib/bdev/vbdev_lvol.c/vbdev_lvol_ut.c | 123 ++++++++++++++++++ 3 files changed, 203 insertions(+), 1 deletion(-) diff --git a/module/bdev/lvol/vbdev_lvol.c b/module/bdev/lvol/vbdev_lvol.c index c66d2acbe..b285732f0 100644 --- a/module/bdev/lvol/vbdev_lvol.c +++ b/module/bdev/lvol/vbdev_lvol.c @@ -1144,6 +1144,82 @@ vbdev_lvol_create_clone(struct spdk_lvol *lvol, const char *clone_name, spdk_lvol_create_clone(lvol, clone_name, _vbdev_lvol_create_cb, req); } +static void +ignore_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx) +{ +} + +void +vbdev_lvol_create_bdev_clone(const char *esnap_uuid, + struct spdk_lvol_store *lvs, const char *clone_name, + spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_lvol_with_handle_req *req; + struct spdk_bdev_desc *desc; + struct spdk_bdev *bdev; + char bdev_uuid[SPDK_UUID_STRING_LEN]; + struct spdk_uuid uuid; + uint64_t sz; + int rc; + + if (lvs == NULL) { + SPDK_ERRLOG("lvol store not specified\n"); + cb_fn(cb_arg, NULL, -EINVAL); + return; + } + + rc = spdk_uuid_parse(&uuid, esnap_uuid); + if (rc != 0) { + SPDK_ERRLOG("Invalid UUID '%s'\n", esnap_uuid); + cb_fn(cb_arg, NULL, -EINVAL); + return; + } + + rc = spdk_bdev_open_ext(esnap_uuid, false, ignore_bdev_event_cb, NULL, &desc); + if (rc != 0) { + SPDK_ERRLOG("bdev '%s' could not be opened: error %d\n", esnap_uuid, rc); + cb_fn(cb_arg, NULL, rc); + return; + } + bdev = spdk_bdev_desc_get_bdev(desc); + + rc = spdk_uuid_fmt_lower(bdev_uuid, sizeof(bdev_uuid), spdk_bdev_get_uuid(bdev)); + if (rc != 0) { + spdk_bdev_close(desc); + SPDK_ERRLOG("bdev %s: unable to parse UUID\n", esnap_uuid); + assert(false); + cb_fn(cb_arg, NULL, -ENODEV); + return; + } + + /* Verify the bdev name or alias isn't a UUID that is different from the bdev's UUID. */ + if (spdk_uuid_compare(&uuid, spdk_bdev_get_uuid(bdev)) != 0) { + spdk_bdev_close(desc); + SPDK_ERRLOG("bdev with name or alias %s has UUID %s\n", esnap_uuid, bdev_uuid); + cb_fn(cb_arg, NULL, -EINVAL); + return; + } + + req = calloc(1, sizeof(*req)); + if (req == NULL) { + spdk_bdev_close(desc); + cb_fn(cb_arg, NULL, -ENOMEM); + return; + } + + req->cb_fn = cb_fn; + req->cb_arg = cb_arg; + + sz = spdk_bdev_get_num_blocks(bdev) * spdk_bdev_get_block_size(bdev); + rc = spdk_lvol_create_esnap_clone(bdev_uuid, sizeof(bdev_uuid), sz, lvs, clone_name, + _vbdev_lvol_create_cb, req); + spdk_bdev_close(desc); + if (rc != 0) { + cb_fn(cb_arg, NULL, rc); + free(req); + } +} + static void _vbdev_lvol_rename_cb(void *cb_arg, int lvolerrno) { diff --git a/module/bdev/lvol/vbdev_lvol.h b/module/bdev/lvol/vbdev_lvol.h index e9cbe7f5c..18da7ffc6 100644 --- a/module/bdev/lvol/vbdev_lvol.h +++ b/module/bdev/lvol/vbdev_lvol.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright (C) 2017 Intel Corporation. * All rights reserved. - * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ #ifndef SPDK_VBDEV_LVOL_H @@ -42,6 +42,9 @@ void vbdev_lvol_create_snapshot(struct spdk_lvol *lvol, const char *snapshot_nam void vbdev_lvol_create_clone(struct spdk_lvol *lvol, const char *clone_name, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg); +void vbdev_lvol_create_bdev_clone(const char *esnap_uuid, + struct spdk_lvol_store *lvs, const char *clone_name, + spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg); /** * \brief Change size of lvol 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 ef6e35f81..16839baba 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 @@ -304,6 +304,20 @@ spdk_blob_is_thin_provisioned(struct spdk_blob *blob) static struct spdk_lvol *_lvol_create(struct spdk_lvol_store *lvs); +int +spdk_lvol_create_esnap_clone(const void *esnap_id, uint32_t id_len, uint64_t size_bytes, + struct spdk_lvol_store *lvs, const char *clone_name, + spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg) +{ + struct spdk_lvol *lvol; + + lvol = _lvol_create(lvs); + snprintf(lvol->name, sizeof(lvol->name), "%s", clone_name); + + cb_fn(cb_arg, lvol, 0); + return 0; +} + static void lvs_load(struct spdk_bs_dev *dev, const struct spdk_lvs_opts *lvs_opts, spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg) @@ -575,6 +589,44 @@ spdk_bdev_get_by_name(const char *bdev_name) return NULL; } +struct spdk_bdev_desc { + struct spdk_bdev *bdev; +}; + +int +spdk_bdev_open_ext(const char *bdev_name, bool write, spdk_bdev_event_cb_t event_cb, + void *event_ctx, struct spdk_bdev_desc **_desc) +{ + struct spdk_bdev_desc *desc; + struct spdk_bdev *bdev; + + bdev = spdk_bdev_get_by_name(bdev_name); + if (bdev == NULL) { + return -ENODEV; + } + + desc = calloc(1, sizeof(*desc)); + if (desc == NULL) { + return -ENOMEM; + } + + desc->bdev = bdev; + *_desc = desc; + return 0; +} + +void +spdk_bdev_close(struct spdk_bdev_desc *desc) +{ + free(desc); +} + +struct spdk_bdev * +spdk_bdev_desc_get_bdev(struct spdk_bdev_desc *desc) +{ + return desc->bdev; +} + void spdk_lvol_close(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_fn, void *cb_arg) { @@ -739,6 +791,18 @@ spdk_bdev_get_name(const struct spdk_bdev *bdev) return bdev->name; } +uint32_t +spdk_bdev_get_block_size(const struct spdk_bdev *bdev) +{ + return bdev->blocklen; +} + +uint64_t +spdk_bdev_get_num_blocks(const struct spdk_bdev *bdev) +{ + return bdev->blockcnt; +} + int spdk_bdev_register(struct spdk_bdev *vbdev) { @@ -1756,6 +1820,64 @@ ut_esnap_dev_create(void) free(unterminated); } +static void +ut_lvol_esnap_clone_bad_args(void) +{ + struct spdk_bdev bdev = { 0 }; + struct spdk_lvol_store *lvs; + const char *esnap_uuid = "255f4236-9427-42d0-a9d1-aa17f37dd8db"; + const char *name_uuid = "5c164b0a-93af-434f-ac35-51af59791f3b"; + int rc; + + /* Lvol store is successfully created */ + rc = vbdev_lvs_create("bdev", "lvs", 0, LVS_CLEAR_WITH_UNMAP, 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_lvol_store->bs_dev != NULL); + lvs = g_lvol_store; + + rc = spdk_uuid_parse(&bdev.uuid, esnap_uuid); + CU_ASSERT(rc == 0); + bdev.name = strdup(name_uuid); + SPDK_CU_ASSERT_FATAL(bdev.name != NULL); + bdev.blocklen = 512; + bdev.blockcnt = 8192; + + g_base_bdev = &bdev; + + /* Error when lvs is NULL */ + g_lvolerrno = 0xbad; + vbdev_lvol_create_bdev_clone(esnap_uuid, NULL, "clone1", vbdev_lvol_create_complete, NULL); + CU_ASSERT(g_lvolerrno == -EINVAL); + + /* Error when a uuid-like name is provided and that matches the bdev name but not uuid */ + g_lvolerrno = 0xbad; + vbdev_lvol_create_bdev_clone(name_uuid, lvs, "clone1", vbdev_lvol_create_complete, NULL); + CU_ASSERT(g_lvolerrno == -EINVAL); + + /* Error when the bdev does not exist */ + g_base_bdev = NULL; + g_lvolerrno = 0xbad; + vbdev_lvol_create_bdev_clone(esnap_uuid, lvs, "clone1", vbdev_lvol_create_complete, NULL); + CU_ASSERT(g_lvolerrno == -ENODEV); + + /* Success when the stars all align. */ + g_base_bdev = &bdev; + g_lvolerrno = 0xbad; + vbdev_lvol_create_bdev_clone(esnap_uuid, lvs, "clone1", vbdev_lvol_create_complete, NULL); + CU_ASSERT(g_lvolerrno == 0); + + g_lvol_store = lvs; + vbdev_lvs_destruct(g_lvol_store, lvol_store_op_complete, NULL); + CU_ASSERT(g_lvserrno == 0); + CU_ASSERT(g_lvol_store == NULL); + + free(bdev.name); + g_base_bdev = NULL; +} + int main(int argc, char **argv) { @@ -1786,6 +1908,7 @@ main(int argc, char **argv) CU_ADD_TEST(suite, ut_lvs_rename); CU_ADD_TEST(suite, ut_lvol_seek); CU_ADD_TEST(suite, ut_esnap_dev_create); + CU_ADD_TEST(suite, ut_lvol_esnap_clone_bad_args); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests();