bdev: Added functions allowing logical volume store rename.

Change-Id: Ief1f809308fbde2e696c60d3ce79c0720cb3e2ff
Signed-off-by: Sebastian Basierski <sebastianx.basierski@intel.com>
Reviewed-on: https://review.gerrithub.io/398934
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
This commit is contained in:
Sebastian Basierski 2018-01-10 11:03:39 +01:00 committed by Jim Harris
parent b90462d0eb
commit f5e590c8f2
10 changed files with 424 additions and 7 deletions

View File

@ -113,6 +113,17 @@ typedef void (*spdk_lvol_op_complete)(void *cb_arg, int lvolerrno);
int spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o,
spdk_lvs_op_with_handle_complete cb_fn, void *cb_arg);
/**
* \brief Renames given lvolstore.
*
* \param lvs Pointer to lvolstore
* \param new_name New name of lvs
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
*/
void spdk_lvs_rename(struct spdk_lvol_store *lvs, const char *new_name,
spdk_lvs_op_complete cb_fn, void *cb_arg);
/**
* \brief Unloads lvolstore
*

View File

@ -45,6 +45,8 @@
struct spdk_lvs_req {
spdk_lvs_op_complete cb_fn;
void *cb_arg;
struct spdk_lvol_store *lvol_store;
int lvserrno;
};
struct spdk_lvol_req {
@ -89,6 +91,7 @@ struct spdk_lvol_store {
bool on_list;
TAILQ_ENTRY(spdk_lvol_store) link;
char name[SPDK_LVS_NAME_MAX];
char new_name[SPDK_LVS_NAME_MAX];
};
struct spdk_lvol {

View File

@ -252,6 +252,53 @@ vbdev_lvs_create(struct spdk_bdev *base_bdev, const char *name, uint32_t cluster
return 0;
}
static void
_vbdev_lvs_rename_cb(void *cb_arg, int lvserrno)
{
struct spdk_lvs_req *req = cb_arg;
struct spdk_lvol *tmp;
if (lvserrno != 0) {
SPDK_INFOLOG(SPDK_LOG_VBDEV_LVOL, "Lvol store rename failed\n");
} else {
TAILQ_FOREACH(tmp, &req->lvol_store->lvols, link) {
/* We have to pass current lvol name, since only lvs name changed */
_vbdev_lvol_change_bdev_alias(tmp, tmp->name);
}
}
req->cb_fn(req->cb_arg, lvserrno);
free(req);
}
void
vbdev_lvs_rename(struct spdk_lvol_store *lvs, const char *new_lvs_name,
spdk_lvs_op_complete cb_fn, void *cb_arg)
{
struct lvol_store_bdev *lvs_bdev;
struct spdk_lvs_req *req;
lvs_bdev = vbdev_get_lvs_bdev_by_lvs(lvs);
if (!lvs_bdev) {
SPDK_ERRLOG("No such lvol store found\n");
cb_fn(cb_arg, -ENODEV);
return;
}
req = calloc(1, sizeof(*req));
if (!req) {
SPDK_ERRLOG("Cannot alloc memory for vbdev lvol store request pointer\n");
cb_fn(cb_arg, -ENOMEM);
return;
}
req->cb_fn = cb_fn;
req->cb_arg = cb_arg;
req->lvol_store = lvs;
spdk_lvs_rename(lvs, new_lvs_name, _vbdev_lvs_rename_cb, req);
}
static void
_vbdev_lvs_remove_cb(void *cb_arg, int lvserrno)
{

View File

@ -60,6 +60,17 @@ int vbdev_lvol_resize(char *name, size_t sz, spdk_lvol_op_complete cb_fn, void *
void vbdev_lvol_rename(struct spdk_lvol *lvol, const char *new_lvol_name,
spdk_lvol_op_complete cb_fn, void *cb_arg);
/**
* \brief Renames given lvolstore.
*
* \param lvs Pointer to lvolstore
* \param new_name New name of lvs
* \param cb_fn Completion callback
* \param cb_arg Completion callback custom arguments
*/
void vbdev_lvs_rename(struct spdk_lvol_store *lvs, const char *new_lvs_name,
spdk_lvs_op_complete cb_fn, void *cb_arg);
/**
* \brief Search for handle lvolstore
* \param uuid_str UUID of lvolstore

View File

@ -168,6 +168,82 @@ invalid:
}
SPDK_RPC_REGISTER("construct_lvol_store", spdk_rpc_construct_lvol_store)
struct rpc_rename_lvol_store {
char *old_name;
char *new_name;
};
static void
free_rpc_rename_lvol_store(struct rpc_rename_lvol_store *req)
{
free(req->old_name);
free(req->new_name);
}
static const struct spdk_json_object_decoder rpc_rename_lvol_store_decoders[] = {
{"old_name", offsetof(struct rpc_rename_lvol_store, old_name), spdk_json_decode_string},
{"new_name", offsetof(struct rpc_rename_lvol_store, new_name), spdk_json_decode_string},
};
static void
_spdk_rpc_rename_lvol_store_cb(void *cb_arg, int lvserrno)
{
struct spdk_json_write_ctx *w;
struct spdk_jsonrpc_request *request = cb_arg;
if (lvserrno != 0) {
goto invalid;
}
w = spdk_jsonrpc_begin_result(request);
if (w == NULL) {
return;
}
spdk_json_write_bool(w, true);
spdk_jsonrpc_end_result(request, w);
return;
invalid:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
spdk_strerror(-lvserrno));
}
static void
spdk_rpc_rename_lvol_store(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_rename_lvol_store req = {};
struct spdk_lvol_store *lvs;
int rc;
if (spdk_json_decode_object(params, rpc_rename_lvol_store_decoders,
SPDK_COUNTOF(rpc_rename_lvol_store_decoders),
&req)) {
SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "spdk_json_decode_object failed\n");
rc = -EINVAL;
goto invalid;
}
lvs = vbdev_get_lvol_store_by_name(req.old_name);
if (lvs == NULL) {
SPDK_INFOLOG(SPDK_LOG_LVOL_RPC, "no lvs existing for given name\n");
rc = -ENOENT;
goto invalid;
}
vbdev_lvs_rename(lvs, req.new_name, _spdk_rpc_rename_lvol_store_cb, request);
free_rpc_rename_lvol_store(&req);
return;
invalid:
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
free_rpc_rename_lvol_store(&req);
}
SPDK_RPC_REGISTER("rename_lvol_store", spdk_rpc_rename_lvol_store)
struct rpc_destroy_lvol_store {
char *uuid;
char *lvs_name;

View File

@ -622,6 +622,102 @@ spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o,
return 0;
}
static void
_spdk_lvs_rename_cb(void *cb_arg, int lvolerrno)
{
struct spdk_lvs_req *req = cb_arg;
if (lvolerrno != 0) {
req->lvserrno = lvolerrno;
}
if (req->lvserrno != 0) {
SPDK_ERRLOG("Lvol store rename operation failed\n");
/* Lvs renaming failed, so we should 'clear' new_name.
* Otherwise it could cause a failure on the next attepmt to change the name to 'new_name' */
strncpy(req->lvol_store->new_name, req->lvol_store->name, SPDK_LVS_NAME_MAX);
} else {
/* Update lvs name with new_name */
strncpy(req->lvol_store->name, req->lvol_store->new_name, SPDK_LVS_NAME_MAX);
}
req->cb_fn(req->cb_arg, req->lvserrno);
free(req);
}
static void
_spdk_lvs_rename_sync_cb(void *cb_arg, int lvolerrno)
{
struct spdk_lvs_req *req = cb_arg;
struct spdk_blob *blob = req->lvol_store->super_blob;
if (lvolerrno < 0) {
req->lvserrno = lvolerrno;
}
spdk_blob_close(blob, _spdk_lvs_rename_cb, req);
}
static void
_spdk_lvs_rename_open_cb(void *cb_arg, struct spdk_blob *blob, int lvolerrno)
{
struct spdk_lvs_req *req = cb_arg;
int rc;
if (lvolerrno < 0) {
_spdk_lvs_rename_cb(cb_arg, lvolerrno);
return;
}
rc = spdk_blob_set_xattr(blob, "name", req->lvol_store->new_name,
strlen(req->lvol_store->new_name) + 1);
if (rc < 0) {
req->lvserrno = rc;
_spdk_lvs_rename_sync_cb(req, rc);
return;
}
req->lvol_store->super_blob = blob;
spdk_blob_sync_md(blob, _spdk_lvs_rename_sync_cb, req);
}
void
spdk_lvs_rename(struct spdk_lvol_store *lvs, const char *new_name,
spdk_lvs_op_complete cb_fn, void *cb_arg)
{
struct spdk_lvs_req *req;
struct spdk_lvol_store *tmp;
/* Check if new name is current lvs name.
* If so, return success immediately */
if (strncmp(lvs->name, new_name, SPDK_LVS_NAME_MAX) == 0) {
cb_fn(cb_arg, 0);
return;
}
/* Check if new or new_name is already used in other lvs */
TAILQ_FOREACH(tmp, &g_lvol_stores, link) {
if (!strncmp(new_name, tmp->name, SPDK_LVS_NAME_MAX) ||
!strncmp(new_name, tmp->new_name, SPDK_LVS_NAME_MAX)) {
cb_fn(cb_arg, -EEXIST);
return;
}
}
req = calloc(1, sizeof(*req));
if (!req) {
SPDK_ERRLOG("Cannot alloc memory for lvol request pointer\n");
cb_fn(cb_arg, -ENOMEM);
return;
}
strncpy(lvs->new_name, new_name, SPDK_LVS_NAME_MAX);
req->lvol_store = lvs;
req->cb_fn = cb_fn;
req->cb_arg = cb_arg;
spdk_bs_open_blob(lvs->blobstore, lvs->super_blob_id, _spdk_lvs_rename_open_cb, req);
}
static void
_lvs_unload_cb(void *cb_arg, int lvserrno)
{

View File

@ -275,6 +275,11 @@ if __name__ == "__main__":
p.add_argument('-c', '--cluster-sz', help='size of cluster (in bytes)', type=int, required=False)
p.set_defaults(func=rpc.lvol.construct_lvol_store)
p = subparsers.add_parser('rename_lvol_store', help='Change logical volume store name')
p.add_argument('old_name', help='old name')
p.add_argument('new_name', help='new name')
p.set_defaults(func=rpc.lvol.rename_lvol_store)
p = subparsers.add_parser('construct_lvol_bdev', help='Add a bdev with an logical volume backend')
p.add_argument('-u', '--uuid', help='lvol store UUID', required=False)
p.add_argument('-l', '--lvs_name', help='lvol store name', required=False)

View File

@ -8,6 +8,14 @@ def construct_lvol_store(args):
print_array(args.client.call('construct_lvol_store', params))
def rename_lvol_store(args):
params = {
'old_name': args.old_name,
'new_name': args.new_name
}
args.client.call('rename_lvol_store', params)
def construct_lvol_bdev(args):
num_bytes = (args.size * 1024 * 1024)
params = {'lvol_name': args.lvol_name, 'size': num_bytes}

View File

@ -59,6 +59,7 @@ bool lvol_store_initialize_cb_fail = false;
bool lvol_already_opened = false;
bool g_examine_done = false;
bool g_bdev_alias_already_exists = false;
bool g_lvs_with_name_already_exists = false;
int
spdk_bdev_alias_add(struct spdk_bdev *bdev, const char *alias)
@ -107,6 +108,20 @@ spdk_bdev_unregister_done(struct spdk_bdev *bdev, int bdeverrno)
{
}
void
spdk_lvs_rename(struct spdk_lvol_store *lvs, const char *new_name,
spdk_lvs_op_complete cb_fn, void *cb_arg)
{
if (g_lvs_with_name_already_exists) {
g_lvolerrno = -EEXIST;
} else {
strncpy(lvs->name, new_name, SPDK_LVS_NAME_MAX);
g_lvolerrno = 0;
}
cb_fn(cb_arg, g_lvolerrno);
}
void
spdk_lvol_rename(struct spdk_lvol *lvol, const char *new_name,
spdk_lvol_op_complete cb_fn, void *cb_arg)
@ -248,6 +263,8 @@ spdk_lvs_init(struct spdk_bs_dev *bs_dev, struct spdk_lvs_opts *o,
lvs = calloc(1, sizeof(*lvs));
SPDK_CU_ASSERT_FATAL(lvs != NULL);
TAILQ_INIT(&lvs->lvols);
uuid_generate_time(lvs->uuid);
strncpy(lvs->name, o->name, SPDK_LVS_NAME_MAX);
lvs->bs_dev = bs_dev;
error = 0;
}
@ -1137,6 +1154,63 @@ ut_vbdev_lvol_submit_request(void)
free(g_base_bdev);
}
static void
ut_lvs_rename(void)
{
int rc = 0;
int sz = 10;
struct spdk_lvol_store *lvs;
struct spdk_bs_dev *b_bdev;
/* Lvol store is succesfully created */
rc = vbdev_lvs_create(&g_bdev, "old_lvs_name", 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_bs_dev != NULL);
b_bdev = g_bs_dev;
g_bs_dev = NULL;
lvs = g_lvol_store;
g_lvol_store = NULL;
g_base_bdev = calloc(1, sizeof(*g_base_bdev));
SPDK_CU_ASSERT_FATAL(g_base_bdev != NULL);
/* Successfully create lvol, which should be destroyed with lvs later */
g_lvolerrno = -1;
rc = vbdev_lvol_create(lvs, "lvol", sz, false, vbdev_lvol_create_complete, NULL);
CU_ASSERT(rc == 0);
CU_ASSERT(g_lvolerrno == 0);
SPDK_CU_ASSERT_FATAL(g_lvol != NULL);
/* Trying to rename lvs with lvols created */
vbdev_lvs_rename(lvs, "new_lvs_name", lvol_store_op_complete, NULL);
CU_ASSERT(g_lvserrno == 0);
CU_ASSERT_STRING_EQUAL(lvs->name, "new_lvs_name");
CU_ASSERT_STRING_EQUAL(TAILQ_FIRST(&g_lvol->bdev->aliases)->alias, "new_lvs_name/lvol");
/* Trying to rename lvs with name already used by another lvs */
/* This is a bdev_lvol test, so g_lvs_with_name_already_exists simulates
* existing lvs with name 'another_new_lvs_name' and this name in fact is not compared */
g_lvs_with_name_already_exists = true;
vbdev_lvs_rename(lvs, "another_new_lvs_name", lvol_store_op_complete, NULL);
CU_ASSERT(g_lvserrno == -EEXIST);
CU_ASSERT_STRING_EQUAL(lvs->name, "new_lvs_name");
CU_ASSERT_STRING_EQUAL(TAILQ_FIRST(&g_lvol->bdev->aliases)->alias, "new_lvs_name/lvol");
g_lvs_with_name_already_exists = false;
/* Unload lvol store */
g_lvol_store = lvs;
g_bs_dev = b_bdev;
vbdev_lvs_destruct(g_lvol_store, lvol_store_op_complete, NULL);
CU_ASSERT(g_lvserrno == 0);
CU_ASSERT(g_lvol_store == NULL);
free(g_base_bdev->name);
free(g_base_bdev);
}
int main(int argc, char **argv)
{
CU_pSuite suite = NULL;
@ -1165,7 +1239,8 @@ int main(int argc, char **argv)
CU_add_test(suite, "ut_lvol_read_write", ut_lvol_read_write) == NULL ||
CU_add_test(suite, "ut_vbdev_lvol_submit_request", ut_vbdev_lvol_submit_request) == NULL ||
CU_add_test(suite, "lvol_examine", ut_lvol_examine) == NULL ||
CU_add_test(suite, "ut_lvol_rename", ut_lvol_rename) == NULL
CU_add_test(suite, "ut_lvol_rename", ut_lvol_rename) == NULL ||
CU_add_test(suite, "ut_lvs_rename", ut_lvs_rename) == NULL
) {
CU_cleanup_registry();
return CU_get_error();

View File

@ -72,6 +72,7 @@ int g_lvolerrno;
int g_lvserrno;
int g_close_super_status;
int g_resize_rc;
bool g_lvs_rename_blob_open_error = false;
struct spdk_lvol_store *g_lvol_store;
struct spdk_lvol *g_lvol;
spdk_blob_id g_blobid = 1;
@ -343,11 +344,13 @@ spdk_bs_open_blob(struct spdk_blob_store *bs, spdk_blob_id blobid,
{
struct spdk_blob *blob;
TAILQ_FOREACH(blob, &bs->blobs, link) {
if (blob->id == blobid) {
blob->ref++;
cb_fn(cb_arg, blob, blob->open_status);
return;
if (!g_lvs_rename_blob_open_error) {
TAILQ_FOREACH(blob, &bs->blobs, link) {
if (blob->id == blobid) {
blob->ref++;
cb_fn(cb_arg, blob, blob->open_status);
return;
}
}
}
@ -1433,6 +1436,87 @@ lvol_rename(void)
spdk_free_thread();
}
static void
lvs_rename(void)
{
struct lvol_ut_bs_dev dev;
struct spdk_lvs_opts opts;
struct spdk_lvol_store *lvs, *lvs2;
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", SPDK_LVS_NAME_MAX);
g_lvserrno = -1;
g_lvol_store = NULL;
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);
lvs = g_lvol_store;
spdk_lvs_opts_init(&opts);
strncpy(opts.name, "unimportant_lvs_name", SPDK_LVS_NAME_MAX);
g_lvserrno = -1;
g_lvol_store = NULL;
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);
lvs2 = g_lvol_store;
/* Trying to rename lvs with new name */
spdk_lvs_rename(lvs, "new_lvs_name", lvol_store_op_complete, NULL);
CU_ASSERT(g_lvserrno == 0);
CU_ASSERT_STRING_EQUAL(lvs->name, "new_lvs_name");
/* Trying to rename lvs with name lvs already has */
spdk_lvs_rename(lvs, "new_lvs_name", lvol_store_op_complete, NULL);
CU_ASSERT(g_lvserrno == 0);
CU_ASSERT_STRING_EQUAL(lvs->name, "new_lvs_name");
/* Trying to rename lvs with name already existing */
spdk_lvs_rename(lvs2, "new_lvs_name", lvol_store_op_complete, NULL);
CU_ASSERT(g_lvserrno == -EEXIST);
CU_ASSERT_STRING_EQUAL(lvs2->name, "unimportant_lvs_name");
/* Trying to rename lvs with another rename process started with the same name */
/* Simulate renaming process in progress */
strncpy(lvs2->new_name, "another_new_lvs_name", SPDK_LVS_NAME_MAX);
CU_ASSERT_STRING_EQUAL(lvs2->new_name, "another_new_lvs_name");
/* Start second process */
spdk_lvs_rename(lvs, "another_new_lvs_name", lvol_store_op_complete, NULL);
CU_ASSERT(g_lvserrno == -EEXIST);
CU_ASSERT_STRING_EQUAL(lvs->name, "new_lvs_name");
/* reverting lvs2 new name to proper value */
strncpy(lvs2->new_name, "unimportant_lvs_name", SPDK_LVS_NAME_MAX);
CU_ASSERT_STRING_EQUAL(lvs2->new_name, "unimportant_lvs_name");
/* Simulate error while lvs rename */
g_lvs_rename_blob_open_error = true;
spdk_lvs_rename(lvs, "complete_new_lvs_name", lvol_store_op_complete, NULL);
CU_ASSERT(g_lvserrno != 0);
CU_ASSERT_STRING_EQUAL(lvs->name, "new_lvs_name");
CU_ASSERT_STRING_EQUAL(lvs->new_name, "new_lvs_name");
g_lvs_rename_blob_open_error = false;
g_lvserrno = -1;
rc = spdk_lvs_destroy(lvs, lvol_store_op_complete, NULL);
CU_ASSERT(rc == 0);
CU_ASSERT(g_lvserrno == 0);
g_lvol_store = NULL;
g_lvserrno = -1;
rc = spdk_lvs_destroy(lvs2, lvol_store_op_complete, NULL);
CU_ASSERT(rc == 0);
CU_ASSERT(g_lvserrno == 0);
g_lvol_store = NULL;
spdk_free_thread();
}
static void lvol_refcnt(void)
{
struct lvol_ut_bs_dev dev;
@ -1582,7 +1666,8 @@ int main(int argc, char **argv)
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 ||
CU_add_test(suite, "lvol_rename", lvol_rename) == NULL
CU_add_test(suite, "lvol_rename", lvol_rename) == NULL ||
CU_add_test(suite, "lvs_rename", lvs_rename) == NULL
) {
CU_cleanup_registry();
return CU_get_error();