Commit ef5c1379 authored by Damiano Cipriani's avatar Damiano Cipriani Committed by Jim Harris
Browse files

lvol: add lvol set parent



This function is mostly a wrapper around spdk_bs_blob_set_parent
to set the parent snapshot of a lvol.
It also perform some checks over input parameters.

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


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarJim Harris <jim.harris@samsung.com>
parent 77c07d07
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -410,6 +410,22 @@ 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);

/**
 * Set a snapshot as the parent of a lvol
 *
 * This call set a snapshot as the parent of a lvol, making the lvol a clone of this snapshot.
 * The previous parent of the lvol, if any, can be another snapshot or an external snapshot; if
 * the lvol is not a clone, it must be thin-provisioned.
 * Lvol and parent snapshot must have the same size and must belong to the same lvol store.
 *
 * \param lvol Handle to lvol
 * \param snapshot Handle to the parent snapshot
 * \param cb_fn Completion callback
 * \param cb_arg Completion callback custom arguments
 */
void spdk_lvol_set_parent(struct spdk_lvol *lvol, struct spdk_lvol *snapshot,
			  spdk_lvol_op_complete cb_fn, void *cb_arg);

#ifdef __cplusplus
}
#endif
+52 −0
Original line number Diff line number Diff line
@@ -2311,3 +2311,55 @@ spdk_lvol_shallow_copy(struct spdk_lvol *lvol, struct spdk_bs_dev *ext_dev,

	return rc;
}

static void
lvol_set_parent_cb(void *cb_arg, int lvolerrno)
{
	struct spdk_lvol_req *req = cb_arg;

	if (lvolerrno < 0) {
		SPDK_ERRLOG("could not set parent of lvol %s, error %d\n", req->lvol->name, lvolerrno);
	}

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

void
spdk_lvol_set_parent(struct spdk_lvol *lvol, struct spdk_lvol *snapshot,
		     spdk_lvol_op_complete cb_fn, void *cb_arg)
{
	struct spdk_lvol_req *req;
	spdk_blob_id blob_id, snapshot_id;

	assert(cb_fn != NULL);

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

	if (snapshot == NULL) {
		SPDK_ERRLOG("snapshot must not be NULL\n");
		cb_fn(cb_arg, -EINVAL);
		return;
	}

	req = calloc(1, sizeof(*req));
	if (!req) {
		SPDK_ERRLOG("cannot alloc memory for lvol request pointer\n");
		cb_fn(cb_arg, -ENOMEM);
		return;
	}

	req->lvol = lvol;
	req->cb_fn = cb_fn;
	req->cb_arg = cb_arg;

	blob_id = spdk_blob_get_id(lvol->blob);
	snapshot_id = spdk_blob_get_id(snapshot->blob);

	spdk_bs_blob_set_parent(lvol->lvol_store->blobstore, blob_id, snapshot_id,
				lvol_set_parent_cb, req);
}
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
	spdk_lvol_get_by_names;
	spdk_lvol_is_degraded;
	spdk_lvol_shallow_copy;
	spdk_lvol_set_parent;

	# internal functions
	spdk_lvol_resize;
+110 −1
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ struct spdk_blob {
	char			name[SPDK_LVS_NAME_MAX];
	bool			thin_provisioned;
	struct spdk_bs_dev	*back_bs_dev;
	uint64_t		num_clusters;
};

int g_lvserrno;
@@ -63,6 +64,7 @@ int g_inflate_rc;
int g_remove_rc;
bool g_lvs_rename_blob_open_error = false;
bool g_blob_read_only = false;
bool g_blob_is_snapshot = false;
struct spdk_lvol_store *g_lvol_store;
struct spdk_lvol *g_lvol;
spdk_blob_id g_blobid = 1;
@@ -140,7 +142,7 @@ spdk_bs_iter_first(struct spdk_blob_store *bs,
uint64_t
spdk_blob_get_num_clusters(struct spdk_blob *blob)
{
	return 1;
	return blob->num_clusters;
}

void
@@ -261,6 +263,19 @@ spdk_bs_blob_shallow_copy(struct spdk_blob_store *bs, struct spdk_io_channel *ch
	return 0;
}

bool
spdk_blob_is_snapshot(struct spdk_blob *blob)
{
	return g_blob_is_snapshot;
}

void
spdk_bs_blob_set_parent(struct spdk_blob_store *bs, spdk_blob_id blob_id,
			spdk_blob_id snapshot_id, spdk_blob_op_complete cb_fn, void *cb_arg)
{
	cb_fn(cb_arg, 0);
}

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

int
@@ -504,6 +519,12 @@ spdk_bs_create_blob_ext(struct spdk_blob_store *bs, const struct spdk_blob_opts
	}
	b->bs = bs;

	if (opts != NULL) {
		b->num_clusters = opts->num_clusters;
	} else {
		b->num_clusters = 1;
	}

	TAILQ_INSERT_TAIL(&bs->blobs, b, link);
	cb_fn(cb_arg, b->id, 0);
}
@@ -3375,6 +3396,93 @@ lvol_shallow_copy(void)
	CU_ASSERT(g_io_channel == NULL);
}

static void
lvol_set_parent(void)
{
	struct lvol_ut_bs_dev bs1_dev;
	struct spdk_lvol_store *lvol_store1;
	struct spdk_lvol *lvol1, *lvol2, *snapshot1;
	struct spdk_lvs_opts opts;
	uint64_t cluster_sz = BS_CLUSTER_SIZE;
	int rc = 0;

	init_dev(&bs1_dev);

	/* Create lvol store 1 */
	spdk_lvs_opts_init(&opts);
	snprintf(opts.name, sizeof(opts.name), "lvs1");

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

	lvol_store1 = g_lvol_store;

	/* Create lvol1 */
	spdk_lvol_create(lvol_store1, "lvol1", cluster_sz, true, LVOL_CLEAR_WITH_DEFAULT,
			 lvol_op_with_handle_complete, NULL);
	CU_ASSERT(g_lvserrno == 0);
	SPDK_CU_ASSERT_FATAL(g_lvol != NULL);

	lvol1 = g_lvol;

	/* Create lvol2 with same size of lvol1 */
	spdk_lvol_create(lvol_store1, "lvol2", cluster_sz, true, LVOL_CLEAR_WITH_DEFAULT,
			 lvol_op_with_handle_complete, NULL);
	CU_ASSERT(g_lvserrno == 0);
	SPDK_CU_ASSERT_FATAL(g_lvol != NULL);

	lvol2 = g_lvol;

	/* Create a snapshot of lvol2 */
	spdk_lvol_create_snapshot(lvol2, "snap1", lvol_op_with_handle_complete, NULL);
	CU_ASSERT(g_lvserrno == 0);
	SPDK_CU_ASSERT_FATAL(g_lvol != NULL);
	CU_ASSERT_STRING_EQUAL(g_lvol->name, "snap1");

	snapshot1 = g_lvol;

	/* Set parent with a NULL lvol */
	g_lvserrno = 0;
	spdk_lvol_set_parent(NULL, snapshot1, op_complete, NULL);
	CU_ASSERT(g_lvserrno == -EINVAL);

	/* Set parent with a NULL parent snapshot */
	g_lvserrno = 0;
	spdk_lvol_set_parent(lvol1, NULL, op_complete, NULL);
	CU_ASSERT(g_lvserrno == -EINVAL);

	/* Set parent successful */
	g_blob_is_snapshot = true;
	g_lvserrno = -1;
	spdk_lvol_set_parent(lvol1, snapshot1, op_complete, NULL);
	CU_ASSERT(g_lvserrno == 0);

	/* Clean up */
	spdk_lvol_close(lvol1, op_complete, NULL);
	CU_ASSERT(g_lvserrno == 0);
	spdk_lvol_destroy(lvol1, op_complete, NULL);
	CU_ASSERT(g_lvserrno == 0);

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

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

	g_lvserrno = -1;
	rc = spdk_lvs_destroy(lvol_store1, op_complete, NULL);
	CU_ASSERT(rc == 0);
	CU_ASSERT(g_lvserrno == 0);
	lvol_store1 = NULL;
}

int
main(int argc, char **argv)
{
@@ -3420,6 +3528,7 @@ main(int argc, char **argv)
	CU_ADD_TEST(suite, lvol_esnap_hotplug);
	CU_ADD_TEST(suite, lvol_get_by);
	CU_ADD_TEST(suite, lvol_shallow_copy);
	CU_ADD_TEST(suite, lvol_set_parent);

	allocate_threads(1);
	set_thread(0);