lvol: add snapshots and clones

Signed-off-by: Piotr Pelplinski <piotr.pelplinski@intel.com>
Signed-off-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Signed-off-by: Tomasz Kulasek <tomaszx.kulasek@intel.com>
Change-Id: Ibc43e3ee65d85a83d78d6e15457ae57992a1188a
Reviewed-on: https://review.gerrithub.io/395059
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Tomasz Zawadzki 2018-02-22 07:29:49 -05:00 committed by Daniel Verkamp
parent 38d75b56f4
commit 97934c5291
11 changed files with 834 additions and 7 deletions

View File

@ -161,6 +161,26 @@ int spdk_lvs_destroy(struct spdk_lvol_store *lvol_store,
*/
int spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
bool thin_provisioned, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
/**
* \brief Create snapshot of given lvol
* \param lvol Handle to lvol
* \param snapshot_name Name of created snapshot
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
*/
void spdk_lvol_create_snapshot(struct spdk_lvol *lvol, const char *snapshot_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
/**
* \brief Create clone of given snapshot
* \param lvol Handle to lvol snapshot
* \param clone_name Name of created clone
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
*/
void spdk_lvol_create_clone(struct spdk_lvol *lvol, const char *clone_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
/**
* \brief Renames lvol with new_name.

View File

@ -448,7 +448,7 @@ struct spdk_bdev_io {
int spdk_bdev_register(struct spdk_bdev *bdev);
void spdk_bdev_unregister(struct spdk_bdev *bdev, spdk_bdev_unregister_cb cb_fn, void *cb_arg);
void spdk_bdev_unregister_done(struct spdk_bdev *bdev, int bdeverrno);
void spdk_bdev_destruct_done(struct spdk_bdev *bdev, int bdeverrno);
int spdk_vbdev_register(struct spdk_bdev *vbdev, struct spdk_bdev **base_bdevs,
int base_bdev_count);

View File

@ -2648,7 +2648,7 @@ spdk_vbdev_register(struct spdk_bdev *vbdev, struct spdk_bdev **base_bdevs, int
}
void
spdk_bdev_unregister_done(struct spdk_bdev *bdev, int bdeverrno)
spdk_bdev_destruct_done(struct spdk_bdev *bdev, int bdeverrno)
{
if (bdev->unregister_cb != NULL) {
bdev->unregister_cb(bdev->unregister_ctx, bdeverrno);

View File

@ -523,9 +523,13 @@ _vbdev_lvol_destroy_cb(void *cb_arg, int lvserrno)
{
struct spdk_bdev *bdev = cb_arg;
if (lvserrno == -EBUSY) {
/* TODO: Handle reporting error to spdk_bdev_unregister */
}
SPDK_INFOLOG(SPDK_LOG_VBDEV_LVOL, "Lvol destroyed\n");
spdk_bdev_unregister_done(bdev, lvserrno);
spdk_bdev_destruct_done(bdev, lvserrno);
free(bdev->name);
free(bdev);
}
@ -538,7 +542,7 @@ _vbdev_lvol_destroy_after_close_cb(void *cb_arg, int lvserrno)
if (lvserrno != 0) {
SPDK_INFOLOG(SPDK_LOG_VBDEV_LVOL, "Could not close Lvol %s\n", lvol->unique_id);
spdk_bdev_unregister_done(bdev, lvserrno);
spdk_bdev_destruct_done(bdev, lvserrno);
free(bdev->name);
free(bdev);
return;
@ -619,11 +623,13 @@ static bool
vbdev_lvol_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
{
switch (io_type) {
case SPDK_BDEV_IO_TYPE_READ:
case SPDK_BDEV_IO_TYPE_WRITE:
case SPDK_BDEV_IO_TYPE_RESET:
case SPDK_BDEV_IO_TYPE_UNMAP:
case SPDK_BDEV_IO_TYPE_WRITE_ZEROES:
/* TODO: Report false if snapshot */
return true;
case SPDK_BDEV_IO_TYPE_RESET:
case SPDK_BDEV_IO_TYPE_READ:
return true;
default:
return false;
@ -887,6 +893,42 @@ vbdev_lvol_create(struct spdk_lvol_store *lvs, const char *name, size_t sz,
return rc;
}
void
vbdev_lvol_create_snapshot(struct spdk_lvol *lvol, const char *snapshot_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
{
struct spdk_lvol_with_handle_req *req;
req = calloc(1, sizeof(*req));
if (req == NULL) {
cb_fn(cb_arg, NULL, -ENOMEM);
return;
}
req->cb_fn = cb_fn;
req->cb_arg = cb_arg;
spdk_lvol_create_snapshot(lvol, snapshot_name, _vbdev_lvol_create_cb, req);
}
void
vbdev_lvol_create_clone(struct spdk_lvol *lvol, const char *clone_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
{
struct spdk_lvol_with_handle_req *req;
req = calloc(1, sizeof(*req));
if (req == NULL) {
cb_fn(cb_arg, NULL, -ENOMEM);
return;
}
req->cb_fn = cb_fn;
req->cb_arg = cb_arg;
spdk_lvol_create_clone(lvol, clone_name, _vbdev_lvol_create_cb, req);
}
static void
_vbdev_lvol_rename_cb(void *cb_arg, int lvolerrno)
{

View File

@ -55,6 +55,12 @@ void vbdev_lvs_unload(struct spdk_lvol_store *lvs, spdk_lvs_op_complete cb_fn, v
int vbdev_lvol_create(struct spdk_lvol_store *lvs, const char *name, size_t sz,
bool thin_provisioned, spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
void vbdev_lvol_create_snapshot(struct spdk_lvol *lvol, const char *snapshot_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
void vbdev_lvol_create_clone(struct spdk_lvol *lvol, const char *clone_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg);
int vbdev_lvol_resize(char *name, size_t sz, spdk_lvol_op_complete cb_fn, void *cb_arg);
void vbdev_lvol_rename(struct spdk_lvol *lvol, const char *new_lvol_name,

View File

@ -418,6 +418,182 @@ invalid:
SPDK_RPC_REGISTER("construct_lvol_bdev", spdk_rpc_construct_lvol_bdev)
struct rpc_snapshot_lvol_bdev {
char *lvol_name;
char *snapshot_name;
};
static void
free_rpc_snapshot_lvol_bdev(struct rpc_snapshot_lvol_bdev *req)
{
free(req->lvol_name);
free(req->snapshot_name);
}
static const struct spdk_json_object_decoder rpc_snapshot_lvol_bdev_decoders[] = {
{"lvol_name", offsetof(struct rpc_snapshot_lvol_bdev, lvol_name), spdk_json_decode_string, true},
{"snapshot_name", offsetof(struct rpc_snapshot_lvol_bdev, snapshot_name), spdk_json_decode_string, true},
};
static void
_spdk_rpc_snapshot_lvol_bdev_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno)
{
struct spdk_json_write_ctx *w;
struct spdk_jsonrpc_request *request = cb_arg;
if (lvolerrno != 0) {
goto invalid;
}
w = spdk_jsonrpc_begin_result(request);
if (w == NULL) {
return;
}
spdk_json_write_array_begin(w);
spdk_json_write_string(w, lvol->bdev->name);
spdk_json_write_array_end(w);
spdk_jsonrpc_end_result(request, w);
return;
invalid:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
spdk_strerror(-lvolerrno));
}
static void
spdk_rpc_snapshot_lvol_bdev(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_snapshot_lvol_bdev req = {};
struct spdk_bdev *bdev;
struct spdk_lvol *lvol;
int rc;
SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Snapshotting blob\n");
if (spdk_json_decode_object(params, rpc_snapshot_lvol_bdev_decoders,
SPDK_COUNTOF(rpc_snapshot_lvol_bdev_decoders),
&req)) {
SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
rc = -EINVAL;
goto invalid;
}
bdev = spdk_bdev_get_by_name(req.lvol_name);
if (bdev == NULL) {
SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "bdev '%s' does not exist\n", req.lvol_name);
rc = -ENODEV;
goto invalid;
}
lvol = vbdev_lvol_get_from_bdev(bdev);
if (lvol == NULL) {
SPDK_ERRLOG("lvol does not exist\n");
rc = -ENODEV;
goto invalid;
}
vbdev_lvol_create_snapshot(lvol, req.snapshot_name, _spdk_rpc_snapshot_lvol_bdev_cb, request);
free_rpc_snapshot_lvol_bdev(&req);
return;
invalid:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
free_rpc_snapshot_lvol_bdev(&req);
}
SPDK_RPC_REGISTER("snapshot_lvol_bdev", spdk_rpc_snapshot_lvol_bdev)
struct rpc_clone_lvol_bdev {
char *snapshot_name;
char *clone_name;
};
static void
free_rpc_clone_lvol_bdev(struct rpc_clone_lvol_bdev *req)
{
free(req->snapshot_name);
free(req->clone_name);
}
static const struct spdk_json_object_decoder rpc_clone_lvol_bdev_decoders[] = {
{"snapshot_name", offsetof(struct rpc_clone_lvol_bdev, snapshot_name), spdk_json_decode_string},
{"clone_name", offsetof(struct rpc_clone_lvol_bdev, clone_name), spdk_json_decode_string, true},
};
static void
_spdk_rpc_clone_lvol_bdev_cb(void *cb_arg, struct spdk_lvol *lvol, int lvolerrno)
{
struct spdk_json_write_ctx *w;
struct spdk_jsonrpc_request *request = cb_arg;
if (lvolerrno != 0) {
goto invalid;
}
w = spdk_jsonrpc_begin_result(request);
if (w == NULL) {
return;
}
spdk_json_write_array_begin(w);
spdk_json_write_string(w, lvol->bdev->name);
spdk_json_write_array_end(w);
spdk_jsonrpc_end_result(request, w);
return;
invalid:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
spdk_strerror(-lvolerrno));
}
static void
spdk_rpc_clone_lvol_bdev(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_clone_lvol_bdev req = {};
struct spdk_bdev *bdev;
struct spdk_lvol *lvol;
int rc;
SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "Cloning blob\n");
if (spdk_json_decode_object(params, rpc_clone_lvol_bdev_decoders,
SPDK_COUNTOF(rpc_clone_lvol_bdev_decoders),
&req)) {
SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
rc = -EINVAL;
goto invalid;
}
bdev = spdk_bdev_get_by_name(req.snapshot_name);
if (bdev == NULL) {
SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "bdev '%s' does not exist\n", req.snapshot_name);
rc = -ENODEV;
goto invalid;
}
lvol = vbdev_lvol_get_from_bdev(bdev);
if (lvol == NULL) {
SPDK_ERRLOG("lvol does not exist\n");
rc = -ENODEV;
goto invalid;
}
vbdev_lvol_create_clone(lvol, req.clone_name, _spdk_rpc_clone_lvol_bdev_cb, request);
free_rpc_clone_lvol_bdev(&req);
return;
invalid:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
free_rpc_clone_lvol_bdev(&req);
}
SPDK_RPC_REGISTER("clone_lvol_bdev", spdk_rpc_clone_lvol_bdev)
struct rpc_rename_lvol_bdev {
char *old_name;
char *new_name;

View File

@ -1103,6 +1103,117 @@ spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, uint64_t sz,
return 0;
}
void
spdk_lvol_create_snapshot(struct spdk_lvol *origlvol, const char *snapshot_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
{
struct spdk_lvol_store *lvs;
struct spdk_lvol *newlvol;
struct spdk_blob *origblob;
struct spdk_lvol_with_handle_req *req;
struct spdk_blob_xattr_opts snapshot_xattrs;
char *xattr_names = LVOL_NAME;
int rc;
if (origlvol == NULL) {
SPDK_INFOLOG(SPDK_LOG_LVOL, "Lvol not provided.\n");
cb_fn(cb_arg, NULL, -EINVAL);
return;
}
origblob = origlvol->blob;
lvs = origlvol->lvol_store;
rc = _spdk_lvs_verify_lvol_name(lvs, snapshot_name);
if (rc < 0) {
cb_fn(cb_arg, NULL, rc);
return;
}
req = calloc(1, sizeof(*req));
if (!req) {
SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
cb_fn(cb_arg, NULL, -ENOMEM);
return;
}
newlvol = calloc(1, sizeof(*newlvol));
if (!newlvol) {
SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
free(req);
cb_fn(cb_arg, NULL, -ENOMEM);
return;
}
newlvol->lvol_store = origlvol->lvol_store;
strncpy(newlvol->name, snapshot_name, SPDK_LVOL_NAME_MAX);
snapshot_xattrs.count = 1;
snapshot_xattrs.ctx = newlvol;
snapshot_xattrs.names = &xattr_names;
snapshot_xattrs.get_value = spdk_lvol_get_xattr_value;
req->lvol = newlvol;
req->cb_fn = cb_fn;
req->cb_arg = cb_arg;
spdk_bs_create_snapshot(lvs->blobstore, spdk_blob_get_id(origblob), &snapshot_xattrs,
_spdk_lvol_create_cb, req);
}
void
spdk_lvol_create_clone(struct spdk_lvol *origlvol, const char *clone_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
{
struct spdk_lvol *newlvol;
struct spdk_lvol_with_handle_req *req;
struct spdk_lvol_store *lvs;
struct spdk_blob *origblob;
struct spdk_blob_xattr_opts clone_xattrs;
char *xattr_names = LVOL_NAME;
int rc;
if (origlvol == NULL) {
SPDK_INFOLOG(SPDK_LOG_LVOL, "Lvol not provided.\n");
cb_fn(cb_arg, NULL, -EINVAL);
return;
}
origblob = origlvol->blob;
lvs = origlvol->lvol_store;
rc = _spdk_lvs_verify_lvol_name(lvs, clone_name);
if (rc < 0) {
cb_fn(cb_arg, NULL, rc);
return;
}
req = calloc(1, sizeof(*req));
if (!req) {
SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
cb_fn(cb_arg, NULL, -ENOMEM);
return;
}
newlvol = calloc(1, sizeof(*newlvol));
if (!newlvol) {
SPDK_ERRLOG("Cannot alloc memory for lvol base pointer\n");
free(req);
cb_fn(cb_arg, NULL, -ENOMEM);
return;
}
newlvol->lvol_store = lvs;
strncpy(newlvol->name, clone_name, SPDK_LVOL_NAME_MAX);
clone_xattrs.count = 1;
clone_xattrs.ctx = newlvol;
clone_xattrs.names = &xattr_names;
clone_xattrs.get_value = spdk_lvol_get_xattr_value;
req->lvol = newlvol;
req->cb_fn = cb_fn;
req->cb_arg = cb_arg;
spdk_bs_create_clone(lvs->blobstore, spdk_blob_get_id(origblob), &clone_xattrs,
_spdk_lvol_create_cb,
req);
}
static void
_spdk_lvol_resize_done(void *cb_arg, int lvolerrno)
{

View File

@ -509,6 +509,24 @@ if __name__ == "__main__":
p.add_argument('size', help='size in MiB for this bdev', type=int)
p.set_defaults(func=construct_lvol_bdev)
@call_cmd
def snapshot_lvol_bdev(args):
rpc.lvol.snapshot_lvol_bdev(args.client, args)
p = subparsers.add_parser('snapshot_lvol_bdev', help='Create a snapshot of an lvol bdev')
p.add_argument('lvol_name', help='lvol bdev name')
p.add_argument('snapshot_name', help='lvol snapshot name')
p.set_defaults(func=snapshot_lvol_bdev)
@call_cmd
def clone_lvol_bdev(args):
rpc.lvol.clone_lvol_bdev(args.client, args)
p = subparsers.add_parser('clone_lvol_bdev', help='Create a clone of an lvol snapshot')
p.add_argument('snapshot_name', help='lvol snapshot name')
p.add_argument('clone_name', help='lvol clone name')
p.set_defaults(func=clone_lvol_bdev)
@call_cmd
def rename_lvol_bdev(args):
rpc.lvol.rename_lvol_bdev(args.client, args)

View File

@ -28,6 +28,22 @@ def construct_lvol_bdev(client, args):
return client.call('construct_lvol_bdev', params)
def snapshot_lvol_bdev(client, args):
params = {
'lvol_name': args.lvol_name,
'snapshot_name': args.snapshot_name
}
return client.call('snapshot_lvol_bdev', params)
def clone_lvol_bdev(client, args):
params = {
'snapshot_name': args.snapshot_name,
'clone_name': args.clone_name
}
return client.call('clone_lvol_bdev', params)
def rename_lvol_bdev(client, args):
params = {
'old_name': args.old_name,

View File

@ -104,7 +104,7 @@ spdk_bdev_alias_del(struct spdk_bdev *bdev, const char *alias)
}
void
spdk_bdev_unregister_done(struct spdk_bdev *bdev, int bdeverrno)
spdk_bdev_destruct_done(struct spdk_bdev *bdev, int bdeverrno)
{
}
@ -577,6 +577,28 @@ spdk_lvol_create(struct spdk_lvol_store *lvs, const char *name, size_t sz,
return 0;
}
void
spdk_lvol_create_snapshot(struct spdk_lvol *lvol, const char *snapshot_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
{
struct spdk_lvol *snap;
snap = _lvol_create(lvol->lvol_store);
strncpy(snap->name, snapshot_name, SPDK_LVOL_NAME_MAX);
cb_fn(cb_arg, snap, 0);
}
void
spdk_lvol_create_clone(struct spdk_lvol *lvol, const char *clone_name,
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
{
struct spdk_lvol *clone;
clone = _lvol_create(lvol->lvol_store);
strncpy(clone->name, clone_name, SPDK_LVS_NAME_MAX);
cb_fn(cb_arg, clone, 0);
}
static void
lvol_store_op_complete(void *cb_arg, int lvserrno)
{
@ -696,6 +718,139 @@ ut_lvol_init(void)
free(g_base_bdev);
}
static void
ut_lvol_snapshot(void)
{
int sz = 10;
int rc;
struct spdk_lvol *lvol = NULL;
g_lvs = calloc(1, sizeof(*g_lvs));
SPDK_CU_ASSERT_FATAL(g_lvs != NULL);
TAILQ_INIT(&g_lvs->lvols);
g_lvs_bdev = calloc(1, sizeof(*g_lvs_bdev));
SPDK_CU_ASSERT_FATAL(g_lvs_bdev != NULL);
g_base_bdev = calloc(1, sizeof(*g_base_bdev));
SPDK_CU_ASSERT_FATAL(g_base_bdev != NULL);
/* Assign name to lvs */
strncpy(g_lvs->name, "UNIT_TEST_LVS_NAME", SPDK_LVS_NAME_MAX);
SPDK_CU_ASSERT_FATAL(g_lvs->name != NULL);
g_lvs_bdev->lvs = g_lvs;
g_lvs_bdev->bdev = g_base_bdev;
spdk_uuid_generate(&g_lvs->uuid);
TAILQ_INSERT_TAIL(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores);
/* Successful lvol create */
g_lvolerrno = -1;
rc = vbdev_lvol_create(g_lvs, "lvol", sz, false, vbdev_lvol_create_complete, NULL);
SPDK_CU_ASSERT_FATAL(rc == 0);
CU_ASSERT(g_lvol != NULL);
CU_ASSERT(g_lvolerrno == 0);
lvol = g_lvol;
/* Successful snap create */
vbdev_lvol_create_snapshot(lvol, "snap", vbdev_lvol_create_complete, NULL);
SPDK_CU_ASSERT_FATAL(rc == 0);
CU_ASSERT(g_lvol != NULL);
CU_ASSERT(g_lvolerrno == 0);
/* Successful lvol destruct */
vbdev_lvol_destruct(g_lvol);
CU_ASSERT(g_lvol == NULL);
/* Successful snap destruct */
g_lvol = lvol;
vbdev_lvol_destruct(g_lvol);
CU_ASSERT(g_lvol == NULL);
TAILQ_REMOVE(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores);
free(g_lvs);
free(g_lvs_bdev);
free(g_base_bdev);
}
static void
ut_lvol_clone(void)
{
int sz = 10;
int rc;
struct spdk_lvol *lvol = NULL;
struct spdk_lvol *snap = NULL;
struct spdk_lvol *clone = NULL;
g_lvs = calloc(1, sizeof(*g_lvs));
SPDK_CU_ASSERT_FATAL(g_lvs != NULL);
TAILQ_INIT(&g_lvs->lvols);
g_lvs_bdev = calloc(1, sizeof(*g_lvs_bdev));
SPDK_CU_ASSERT_FATAL(g_lvs_bdev != NULL);
g_base_bdev = calloc(1, sizeof(*g_base_bdev));
SPDK_CU_ASSERT_FATAL(g_base_bdev != NULL);
/* Assign name to lvs */
strncpy(g_lvs->name, "UNIT_TEST_LVS_NAME", SPDK_LVS_NAME_MAX);
SPDK_CU_ASSERT_FATAL(g_lvs->name != NULL);
g_lvs_bdev->lvs = g_lvs;
g_lvs_bdev->bdev = g_base_bdev;
spdk_uuid_generate(&g_lvs->uuid);
TAILQ_INSERT_TAIL(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores);
/* Successful lvol create */
g_lvolerrno = -1;
rc = vbdev_lvol_create(g_lvs, "lvol", sz, false, vbdev_lvol_create_complete, NULL);
SPDK_CU_ASSERT_FATAL(rc == 0);
CU_ASSERT(g_lvol != NULL);
CU_ASSERT(g_lvolerrno == 0);
lvol = g_lvol;
/* Successful snap create */
vbdev_lvol_create_snapshot(lvol, "snap", vbdev_lvol_create_complete, NULL);
SPDK_CU_ASSERT_FATAL(rc == 0);
CU_ASSERT(g_lvol != NULL);
CU_ASSERT(g_lvolerrno == 0);
snap = g_lvol;
/* Successful clone create */
vbdev_lvol_create_clone(snap, "clone", vbdev_lvol_create_complete, NULL);
SPDK_CU_ASSERT_FATAL(rc == 0);
CU_ASSERT(g_lvol != NULL);
CU_ASSERT(g_lvolerrno == 0);
clone = g_lvol;
/* Successful lvol destruct */
g_lvol = lvol;
vbdev_lvol_destruct(g_lvol);
CU_ASSERT(g_lvol == NULL);
/* Successful clone destruct */
g_lvol = clone;
vbdev_lvol_destruct(g_lvol);
CU_ASSERT(g_lvol == NULL);
/* Successful snap destruct */
g_lvol = snap;
vbdev_lvol_destruct(g_lvol);
CU_ASSERT(g_lvol == NULL);
TAILQ_REMOVE(&g_spdk_lvol_pairs, g_lvs_bdev, lvol_stores);
free(g_lvs);
free(g_lvs_bdev);
free(g_base_bdev);
}
static void
ut_lvol_hotremove(void)
{
@ -1233,6 +1388,8 @@ int main(int argc, char **argv)
if (
CU_add_test(suite, "ut_lvs_init", ut_lvs_init) == NULL ||
CU_add_test(suite, "ut_lvol_init", ut_lvol_init) == NULL ||
CU_add_test(suite, "ut_lvol_snapshot", ut_lvol_snapshot) == NULL ||
CU_add_test(suite, "ut_lvol_clone", ut_lvol_clone) == NULL ||
CU_add_test(suite, "ut_lvs_destroy", ut_lvs_destroy) == NULL ||
CU_add_test(suite, "ut_lvs_unload", ut_lvs_unload) == NULL ||
CU_add_test(suite, "ut_lvol_resize", ut_lvol_resize) == NULL ||

View File

@ -59,6 +59,7 @@ const char *uuid = "828d9766-ae50-11e7-bd8d-001e67edf350";
struct spdk_blob {
spdk_blob_id id;
uint32_t ref;
struct spdk_blob_store *bs;
int close_status;
int open_status;
int load_status;
@ -399,11 +400,28 @@ spdk_bs_create_blob_ext(struct spdk_blob_store *bs, const struct spdk_blob_opts
if (opts != NULL && opts->thin_provision) {
b->thin_provisioned = true;
}
b->bs = bs;
TAILQ_INSERT_TAIL(&bs->blobs, b, link);
cb_fn(cb_arg, b->id, 0);
}
void
spdk_bs_create_snapshot(struct spdk_blob_store *bs, spdk_blob_id blobid,
const struct spdk_blob_xattr_opts *snapshot_xattrs,
spdk_blob_op_with_id_complete cb_fn, void *cb_arg)
{
spdk_bs_create_blob_ext(bs, NULL, cb_fn, cb_arg);
}
void
spdk_bs_create_clone(struct spdk_blob_store *bs, spdk_blob_id blobid,
const struct spdk_blob_xattr_opts *clone_xattrs,
spdk_blob_op_with_id_complete cb_fn, void *cb_arg)
{
spdk_bs_create_blob_ext(bs, NULL, cb_fn, cb_arg);
}
static void
_lvol_send_msg(spdk_thread_fn fn, void *ctx, void *thread_ctx)
{
@ -1281,6 +1299,265 @@ lvol_open(void)
spdk_free_thread();
}
static void
lvol_snapshot(void)
{
struct lvol_ut_bs_dev dev;
struct spdk_lvol *lvol;
struct spdk_lvs_opts opts;
int rc = 0;
init_dev(&dev);
spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL);
spdk_lvs_opts_init(&opts);
strncpy(opts.name, "lvs", sizeof(opts.name));
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);
spdk_lvol_create(g_lvol_store, "lvol", 10, true, lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno == 0);
SPDK_CU_ASSERT_FATAL(g_lvol != NULL);
lvol = g_lvol;
spdk_lvol_create_snapshot(lvol, "snap", 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, "snap");
/* Lvol has to be closed (or destroyed) before unloading lvol store. */
spdk_lvol_close(g_lvol, close_cb, NULL);
CU_ASSERT(g_lvserrno == 0);
g_lvserrno = -1;
spdk_lvol_close(lvol, close_cb, NULL);
CU_ASSERT(g_lvserrno == 0);
g_lvserrno = -1;
rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL);
CU_ASSERT(rc == 0);
CU_ASSERT(g_lvserrno == 0);
g_lvol_store = NULL;
free_dev(&dev);
spdk_free_thread();
}
static void
lvol_snapshot_fail(void)
{
struct lvol_ut_bs_dev dev;
struct spdk_lvol *lvol, *snap;
struct spdk_lvs_opts opts;
int rc = 0;
init_dev(&dev);
spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL);
spdk_lvs_opts_init(&opts);
strncpy(opts.name, "lvs", sizeof(opts.name));
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);
spdk_lvol_create(g_lvol_store, "lvol", 10, true, lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno == 0);
SPDK_CU_ASSERT_FATAL(g_lvol != NULL);
lvol = g_lvol;
spdk_lvol_create_snapshot(NULL, "snap", lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno < 0);
SPDK_CU_ASSERT_FATAL(g_lvol == NULL);
spdk_lvol_create_snapshot(lvol, "", lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno < 0);
SPDK_CU_ASSERT_FATAL(g_lvol == NULL);
spdk_lvol_create_snapshot(lvol, NULL, lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno < 0);
SPDK_CU_ASSERT_FATAL(g_lvol == NULL);
spdk_lvol_create_snapshot(lvol, "snap", 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, "snap");
snap = g_lvol;
spdk_lvol_create_snapshot(lvol, "snap", lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno < 0);
spdk_lvol_close(lvol, close_cb, NULL);
CU_ASSERT(g_lvserrno == 0);
g_lvserrno = -1;
spdk_lvol_close(snap, close_cb, NULL);
CU_ASSERT(g_lvserrno == 0);
g_lvserrno = -1;
rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL);
CU_ASSERT(rc == 0);
CU_ASSERT(g_lvserrno == 0);
g_lvol_store = NULL;
free_dev(&dev);
spdk_free_thread();
}
static void
lvol_clone(void)
{
struct lvol_ut_bs_dev dev;
struct spdk_lvol *lvol;
struct spdk_lvol *snap;
struct spdk_lvs_opts opts;
int rc = 0;
init_dev(&dev);
spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL);
spdk_lvs_opts_init(&opts);
strncpy(opts.name, "lvs", sizeof(opts.name));
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);
spdk_lvol_create(g_lvol_store, "lvol", 10, true, lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno == 0);
SPDK_CU_ASSERT_FATAL(g_lvol != NULL);
lvol = g_lvol;
spdk_lvol_create_snapshot(lvol, "snap", 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, "snap");
snap = g_lvol;
spdk_lvol_create_clone(snap, "clone", 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, "clone");
/* Lvol has to be closed (or destroyed) before unloading lvol store. */
spdk_lvol_close(g_lvol, close_cb, NULL);
CU_ASSERT(g_lvserrno == 0);
g_lvserrno = -1;
spdk_lvol_close(snap, close_cb, NULL);
CU_ASSERT(g_lvserrno == 0);
g_lvserrno = -1;
spdk_lvol_close(lvol, close_cb, NULL);
CU_ASSERT(g_lvserrno == 0);
g_lvserrno = -1;
rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL);
CU_ASSERT(rc == 0);
CU_ASSERT(g_lvserrno == 0);
g_lvol_store = NULL;
free_dev(&dev);
spdk_free_thread();
}
static void
lvol_clone_fail(void)
{
struct lvol_ut_bs_dev dev;
struct spdk_lvol *lvol;
struct spdk_lvol *snap;
struct spdk_lvol *clone;
struct spdk_lvs_opts opts;
int rc = 0;
init_dev(&dev);
spdk_allocate_thread(_lvol_send_msg, NULL, NULL, NULL, NULL);
spdk_lvs_opts_init(&opts);
strncpy(opts.name, "lvs", sizeof(opts.name));
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);
spdk_lvol_create(g_lvol_store, "lvol", 10, true, lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno == 0);
SPDK_CU_ASSERT_FATAL(g_lvol != NULL);
lvol = g_lvol;
spdk_lvol_create_snapshot(lvol, "snap", 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, "snap");
snap = g_lvol;
spdk_lvol_create_clone(NULL, "clone", lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno < 0);
spdk_lvol_create_clone(snap, "", lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno < 0);
spdk_lvol_create_clone(snap, NULL, lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno < 0);
spdk_lvol_create_clone(snap, "clone", 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, "clone");
clone = g_lvol;
spdk_lvol_create_clone(snap, "clone", lvol_op_with_handle_complete, NULL);
CU_ASSERT(g_lvserrno < 0);
/* Lvol has to be closed (or destroyed) before unloading lvol store. */
spdk_lvol_close(clone, close_cb, NULL);
CU_ASSERT(g_lvserrno == 0);
g_lvserrno = -1;
spdk_lvol_close(snap, close_cb, NULL);
CU_ASSERT(g_lvserrno == 0);
g_lvserrno = -1;
spdk_lvol_close(lvol, close_cb, NULL);
CU_ASSERT(g_lvserrno == 0);
g_lvserrno = -1;
rc = spdk_lvs_unload(g_lvol_store, lvol_store_op_complete, NULL);
CU_ASSERT(rc == 0);
CU_ASSERT(g_lvserrno == 0);
g_lvol_store = NULL;
free_dev(&dev);
spdk_free_thread();
}
static void
lvol_names(void)
{
@ -1659,6 +1936,10 @@ int main(int argc, char **argv)
CU_add_test(suite, "lvol_load", lvs_load) == NULL ||
CU_add_test(suite, "lvs_load", lvols_load) == NULL ||
CU_add_test(suite, "lvol_open", lvol_open) == NULL ||
CU_add_test(suite, "lvol_snapshot", lvol_snapshot) == NULL ||
CU_add_test(suite, "lvol_snapshot_fail", lvol_snapshot_fail) == NULL ||
CU_add_test(suite, "lvol_clone", lvol_clone) == NULL ||
CU_add_test(suite, "lvol_clone_fail", lvol_clone_fail) == NULL ||
CU_add_test(suite, "lvol_refcnt", lvol_refcnt) == NULL ||
CU_add_test(suite, "lvol_names", lvol_names) == NULL ||
CU_add_test(suite, "lvol_create_thin_provisioned", lvol_create_thin_provisioned) == NULL ||