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

lvol: add lvol set external parent



This function is mostly a wrapper around
spdk_bs_blob_set_external_parent to set the parent external snapshot
of a lvol.
It also perform some checks over input parameters and create backing
device of the external snapshot.

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


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 ef5c1379
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -426,6 +426,26 @@ int spdk_lvol_shallow_copy(struct spdk_lvol *lvol, struct spdk_bs_dev *ext_dev,
void spdk_lvol_set_parent(struct spdk_lvol *lvol, struct spdk_lvol *snapshot,
			  spdk_lvol_op_complete cb_fn, void *cb_arg);

/**
 * Set an external snapshot as the parent of a lvol
 *
 * This call set an external snapshot as the parent of a lvol, making the lvol a clone of this
 * external snapshot.
 * The previous parent of the lvol, if any, can be another external snapshot or a snapshot; if
 * the lvol is not a clone, it must be thin-provisioned.
 * The size of the external snapshot device must be an integer multiple of cluster size of
 * lvol's lvolstore.
 *
 * \param lvol Handle to lvol
 * \param esnap_id The identifier of the external snapshot.
 * \param esnap_id_len The length of esnap_id, in bytes.
 * \param cb_fn Completion callback
 * \param cb_arg Completion callback custom arguments
 */
void spdk_lvol_set_external_parent(struct spdk_lvol *lvol, const void *esnap_id,
				   uint32_t esnap_id_len,
				   spdk_lvol_op_complete cb_fn, void *cb_arg);

#ifdef __cplusplus
}
#endif
+7 −0
Original line number Diff line number Diff line
@@ -76,6 +76,13 @@ struct spdk_lvol_with_handle_req {
	struct spdk_lvol		*origlvol;
};

struct spdk_lvol_bs_dev_req {
	struct spdk_lvol	*lvol;
	struct spdk_bs_dev	*bs_dev;
	spdk_lvol_op_complete	cb_fn;
	void			*cb_arg;
};

struct spdk_lvs_degraded_lvol_set;

struct spdk_lvol_store {
+68 −0
Original line number Diff line number Diff line
@@ -2363,3 +2363,71 @@ spdk_lvol_set_parent(struct spdk_lvol *lvol, struct spdk_lvol *snapshot,
	spdk_bs_blob_set_parent(lvol->lvol_store->blobstore, blob_id, snapshot_id,
				lvol_set_parent_cb, req);
}

static void
lvol_set_external_parent_cb(void *cb_arg, int lvolerrno)
{
	struct spdk_lvol_bs_dev_req *req = cb_arg;

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

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

void
spdk_lvol_set_external_parent(struct spdk_lvol *lvol, const void *esnap_id, uint32_t esnap_id_len,
			      spdk_lvol_op_complete cb_fn, void *cb_arg)
{
	struct spdk_lvol_bs_dev_req *req;
	struct spdk_bs_dev *bs_dev;
	spdk_blob_id blob_id;
	int rc;

	assert(cb_fn != NULL);

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

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

	if (esnap_id_len == sizeof(lvol->uuid_str) &&
	    memcmp(esnap_id, lvol->uuid_str, esnap_id_len) == 0) {
		SPDK_ERRLOG("lvol %s and esnap have the same UUID\n", lvol->name);
		cb_fn(cb_arg, -EINVAL);
		return;
	}

	rc = lvs_esnap_bs_dev_create(lvol->lvol_store, lvol, lvol->blob, esnap_id, esnap_id_len, &bs_dev);
	if (rc < 0) {
		cb_fn(cb_arg, rc);
		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->bs_dev = bs_dev;
	req->cb_fn = cb_fn;
	req->cb_arg = cb_arg;

	blob_id = spdk_blob_get_id(lvol->blob);

	spdk_bs_blob_set_external_parent(lvol->lvol_store->blobstore, blob_id, bs_dev, esnap_id,
					 esnap_id_len, lvol_set_external_parent_cb, req);
}
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
	spdk_lvol_is_degraded;
	spdk_lvol_shallow_copy;
	spdk_lvol_set_parent;
	spdk_lvol_set_external_parent;

	# internal functions
	spdk_lvol_resize;
+74 −0
Original line number Diff line number Diff line
@@ -276,6 +276,14 @@ spdk_bs_blob_set_parent(struct spdk_blob_store *bs, spdk_blob_id blob_id,
	cb_fn(cb_arg, 0);
}

void
spdk_bs_blob_set_external_parent(struct spdk_blob_store *bs, spdk_blob_id blob_id,
				 struct spdk_bs_dev *back_bs_dev, const void *esnap_id,
				 uint32_t id_len, 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
@@ -3483,6 +3491,71 @@ lvol_set_parent(void)
	lvol_store1 = NULL;
}

static void
lvol_set_external_parent(void)
{
	struct lvol_ut_bs_dev dev;
	struct spdk_lvol *lvol;
	struct spdk_lvs_opts opts;
	uint64_t cluster_sz;
	int rc;

	g_spdk_blob_get_esnap_id = (void *)uuid;
	g_spdk_blob_get_esnap_id_len = SPDK_UUID_STRING_LEN;
	init_dev(&dev);

	/* Create lvol store */
	spdk_lvs_opts_init(&opts);
	cluster_sz = opts.cluster_sz;
	snprintf(opts.name, sizeof(opts.name), "lvs");

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

	/* Create lvol */
	spdk_lvol_create(g_lvol_store, "lvol", cluster_sz, false, LVOL_CLEAR_WITH_DEFAULT,
			 lvol_op_with_handle_complete, NULL);
	CU_ASSERT(g_lvserrno == 0);
	SPDK_CU_ASSERT_FATAL(g_lvol != NULL);

	lvol = g_lvol;

	/* Set external parent with NULL lvol */
	spdk_lvol_set_external_parent(NULL, uuid, SPDK_UUID_STRING_LEN, op_complete, NULL);
	poll_threads();
	CU_ASSERT(g_lvserrno == -EINVAL);

	/* Set external parent with NULL esnap id */
	spdk_lvol_set_external_parent(lvol, NULL, SPDK_UUID_STRING_LEN, op_complete, NULL);
	poll_threads();
	CU_ASSERT(g_lvserrno == -EINVAL);

	/* Set external parent with equal lvol and esnap */
	spdk_lvol_set_external_parent(lvol, lvol->uuid_str, SPDK_UUID_STRING_LEN, op_complete, NULL);
	poll_threads();
	CU_ASSERT(g_lvserrno == -EINVAL);

	/* Set external parent successful */
	spdk_lvol_set_external_parent(lvol, uuid, SPDK_UUID_STRING_LEN, op_complete, NULL);
	poll_threads();
	CU_ASSERT(g_lvserrno == 0);

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

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

int
main(int argc, char **argv)
{
@@ -3529,6 +3602,7 @@ main(int argc, char **argv)
	CU_ADD_TEST(suite, lvol_get_by);
	CU_ADD_TEST(suite, lvol_shallow_copy);
	CU_ADD_TEST(suite, lvol_set_parent);
	CU_ADD_TEST(suite, lvol_set_external_parent);

	allocate_threads(1);
	set_thread(0);