Commit 54b4f4dd authored by Mike Gerdts's avatar Mike Gerdts Committed by Jim Harris
Browse files

vbdev_lvol: allow creation of esnap clones



This adds the ability for create esnap clone lvol bdevs.

Signed-off-by: default avatarMike Gerdts <mgerdts@nvidia.com>
Change-Id: Ifeef983430153d84d896d282fe914c6671283762
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16590


Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent 0c31b86a
Loading
Loading
Loading
Loading
+76 −0
Original line number Diff line number Diff line
@@ -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)
{
+4 −1
Original line number Diff line number Diff line
/*   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
+123 −0
Original line number Diff line number Diff line
@@ -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();