Commit 24574350 authored by Damiano Cipriani's avatar Damiano Cipriani Committed by Tomasz Zawadzki
Browse files

lvol: add shallow copy over a given device



This is mostly a wrapper around spdk_bs_blob_shallow_copy(), but it also
performs some checks over lvol, bs_dev and their compatibility.

Change-Id: I57ef2d2dd7a298f6ac8749d11ffe4e59612eb22e
Signed-off-by: default avatarDamiano Cipriani <damiano.cipriani@suse.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/19249


Community-CI: Mellanox Build Bot
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent 4c88d56d
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -391,6 +391,25 @@ void spdk_lvol_decouple_parent(struct spdk_lvol *lvol, spdk_lvol_op_complete cb_
 */
bool spdk_lvol_is_degraded(const struct spdk_lvol *lvol);

/**
 * Make a shallow copy of lvol on given bs_dev.
 *
 * Lvol must be read only and lvol size must be less or equal than bs_dev size.
 *
 * \param lvol Handle to lvol
 * \param ext_dev The bs_dev to copy on. This is created on the given bdev by using
 * spdk_bdev_create_bs_dev_ext() beforehand
 * \param status_cb_fn Called repeatedly during operation with status updates
 * \param status_cb_arg Argument passed to function status_cb_fn.
 * \param cb_fn Completion callback
 * \param cb_arg Completion callback custom arguments
 *
 * \return 0 if operation starts correctly, negative errno on failure.
 */
int spdk_lvol_shallow_copy(struct spdk_lvol *lvol, struct spdk_bs_dev *ext_dev,
			   spdk_blob_shallow_copy_status status_cb_fn, void *status_cb_arg,
			   spdk_lvol_op_complete cb_fn, void *cb_arg);

#ifdef __cplusplus
}
#endif
+8 −0
Original line number Diff line number Diff line
@@ -46,6 +46,14 @@ struct spdk_lvol_req {
	char			name[SPDK_LVOL_NAME_MAX];
};

struct spdk_lvol_copy_req {
	spdk_lvol_op_complete	cb_fn;
	void			*cb_arg;
	struct spdk_lvol	*lvol;
	struct spdk_io_channel	*channel;
	struct spdk_bs_dev	*ext_dev;
};

struct spdk_lvs_with_handle_req {
	spdk_lvs_op_with_handle_complete cb_fn;
	void				*cb_arg;
+69 −0
Original line number Diff line number Diff line
@@ -2242,3 +2242,72 @@ spdk_lvol_is_degraded(const struct spdk_lvol *lvol)
	}
	return spdk_blob_is_degraded(blob);
}

static void
lvol_shallow_copy_cb(void *cb_arg, int lvolerrno)
{
	struct spdk_lvol_copy_req *req = cb_arg;
	struct spdk_lvol *lvol = req->lvol;

	spdk_bs_free_io_channel(req->channel);

	if (lvolerrno < 0) {
		SPDK_ERRLOG("Could not make a shallow copy of lvol %s, error %d\n", lvol->unique_id, lvolerrno);
	}

	req->cb_fn(req->cb_arg, lvolerrno);
	free(req);
}

int
spdk_lvol_shallow_copy(struct spdk_lvol *lvol, struct spdk_bs_dev *ext_dev,
		       spdk_blob_shallow_copy_status status_cb_fn, void *status_cb_arg,
		       spdk_lvol_op_complete cb_fn, void *cb_arg)
{
	struct spdk_lvol_copy_req *req;
	spdk_blob_id blob_id;
	int rc;

	assert(cb_fn != NULL);

	if (lvol == NULL) {
		SPDK_ERRLOG("lvol must not be NULL\n");
		return -EINVAL;
	}

	assert(lvol->lvol_store->thread == spdk_get_thread());

	if (ext_dev == NULL) {
		SPDK_ERRLOG("lvol %s shallow copy, ext_dev must not be NULL\n", lvol->unique_id);
		return -EINVAL;
	}

	req = calloc(1, sizeof(*req));
	if (!req) {
		SPDK_ERRLOG("lvol %s shallow copy, cannot alloc memory for lvol request\n", lvol->unique_id);
		return -ENOMEM;
	}

	req->lvol = lvol;
	req->cb_fn = cb_fn;
	req->cb_arg = cb_arg;
	req->channel = spdk_bs_alloc_io_channel(lvol->lvol_store->blobstore);
	if (req->channel == NULL) {
		SPDK_ERRLOG("lvol %s shallow copy, cannot alloc io channel for lvol request\n", lvol->unique_id);
		free(req);
		return -ENOMEM;
	}

	blob_id = spdk_blob_get_id(lvol->blob);

	rc = spdk_bs_blob_shallow_copy(lvol->lvol_store->blobstore, req->channel, blob_id, ext_dev,
				       status_cb_fn, status_cb_arg, lvol_shallow_copy_cb, req);

	if (rc < 0) {
		SPDK_ERRLOG("Could not make a shallow copy of lvol %s\n", lvol->unique_id);
		spdk_bs_free_io_channel(req->channel);
		free(req);
	}

	return rc;
}
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
	spdk_lvol_get_by_uuid;
	spdk_lvol_get_by_names;
	spdk_lvol_is_degraded;
	spdk_lvol_shallow_copy;

	# internal functions
	spdk_lvol_resize;
+79 −1
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@ int g_resize_rc;
int g_inflate_rc;
int g_remove_rc;
bool g_lvs_rename_blob_open_error = false;
bool g_blob_read_only = false;
struct spdk_lvol_store *g_lvol_store;
struct spdk_lvol *g_lvol;
spdk_blob_id g_blobid = 1;
@@ -139,7 +140,7 @@ spdk_bs_iter_first(struct spdk_blob_store *bs,
uint64_t
spdk_blob_get_num_clusters(struct spdk_blob *blob)
{
	return 0;
	return 1;
}

void
@@ -250,6 +251,16 @@ spdk_blob_is_thin_provisioned(struct spdk_blob *blob)
	return blob->thin_provisioned;
}

int
spdk_bs_blob_shallow_copy(struct spdk_blob_store *bs, struct spdk_io_channel *channel,
			  spdk_blob_id blobid, struct spdk_bs_dev *ext_dev,
			  spdk_blob_shallow_copy_status status_cb_fn, void *status_cb_arg,
			  spdk_blob_op_complete cb_fn, void *cb_arg)
{
	cb_fn(cb_arg, 0);
	return 0;
}

DEFINE_STUB(spdk_bs_get_page_size, uint64_t, (struct spdk_blob_store *bs), BS_PAGE_SIZE);

int
@@ -460,6 +471,12 @@ spdk_blob_open_opts_init(struct spdk_blob_open_opts *opts, size_t opts_size)
	opts->clear_method = BLOB_CLEAR_WITH_DEFAULT;
}

bool
spdk_blob_is_read_only(struct spdk_blob *blob)
{
	return g_blob_read_only;
}

void
spdk_bs_create_blob(struct spdk_blob_store *bs,
		    spdk_blob_op_with_id_complete cb_fn, void *cb_arg)
@@ -3298,6 +3315,66 @@ lvol_get_by(void)
	free_dev(&dev2);
}

static void
lvol_shallow_copy(void)
{
	struct lvol_ut_bs_dev bs_dev;
	struct spdk_lvs_opts opts;
	struct spdk_bs_dev ext_dev;
	int rc = 0;

	init_dev(&bs_dev);

	ext_dev.blocklen = DEV_BUFFER_BLOCKLEN;
	ext_dev.blockcnt = BS_CLUSTER_SIZE / DEV_BUFFER_BLOCKLEN;

	spdk_lvs_opts_init(&opts);
	snprintf(opts.name, sizeof(opts.name), "lvs");

	g_lvserrno = -1;
	rc = spdk_lvs_init(&bs_dev.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);

	spdk_lvol_create(g_lvol_store, "lvol", BS_CLUSTER_SIZE, false, LVOL_CLEAR_WITH_DEFAULT,
			 lvol_op_with_handle_complete, NULL);
	CU_ASSERT(g_lvserrno == 0);
	SPDK_CU_ASSERT_FATAL(g_lvol != NULL);

	/* Successful shallow copy */
	g_blob_read_only = true;
	rc = spdk_lvol_shallow_copy(g_lvol, &ext_dev, NULL, NULL, op_complete, NULL);
	CU_ASSERT(rc == 0);
	CU_ASSERT(g_lvserrno == 0);

	/* Shallow copy with null lvol */
	rc = spdk_lvol_shallow_copy(NULL, &ext_dev, NULL, NULL, op_complete, NULL);
	CU_ASSERT(rc == -EINVAL);

	/* Shallow copy with null ext_dev */
	rc = spdk_lvol_shallow_copy(g_lvol, NULL, NULL, NULL, op_complete, NULL);
	CU_ASSERT(rc == -EINVAL);

	spdk_lvol_close(g_lvol, op_complete, NULL);
	CU_ASSERT(g_lvserrno == 0);
	spdk_lvol_destroy(g_lvol, op_complete, NULL);
	CU_ASSERT(g_lvserrno == 0);

	g_lvserrno = -1;
	rc = spdk_lvs_unload(g_lvol_store, op_complete, NULL);
	CU_ASSERT(rc == 0);
	CU_ASSERT(g_lvserrno == 0);
	g_lvol_store = NULL;

	free_dev(&bs_dev);

	/* Make sure that all references to the io_channel was closed after
	 * shallow copy call
	 */
	CU_ASSERT(g_io_channel == NULL);
}

int
main(int argc, char **argv)
{
@@ -3342,6 +3419,7 @@ main(int argc, char **argv)
	CU_ADD_TEST(suite, lvol_esnap_missing);
	CU_ADD_TEST(suite, lvol_esnap_hotplug);
	CU_ADD_TEST(suite, lvol_get_by);
	CU_ADD_TEST(suite, lvol_shallow_copy);

	allocate_threads(1);
	set_thread(0);