From 09e8fa9266e25ab1797751018fe6b68d98b8de0c Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 9 Dec 2014 15:28:15 -0600 Subject: vgrename: for lockd VGs --- daemons/lvmlockd/lvmlockd-core.c | 59 +++++++++++++ daemons/lvmlockd/lvmlockd-internal.h | 3 + daemons/lvmlockd/lvmlockd-sanlock.c | 155 +++++++++++++++++++++++++++++++++++ lib/locking/lvmlockd.c | 126 ++++++++++++++++++++++++++++ lib/locking/lvmlockd.h | 8 ++ man/lvmlockd.8.in | 2 - tools/vgrename.c | 16 ++-- 7 files changed, 361 insertions(+), 8 deletions(-) diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c index 6a6d64bd9..7b5dd277c 100644 --- a/daemons/lvmlockd/lvmlockd-core.c +++ b/daemons/lvmlockd/lvmlockd-core.c @@ -767,6 +767,10 @@ static const char *op_str(int x) return "start_wait"; case LD_OP_STOP_ALL: return "stop_all"; + case LD_OP_RENAME_BEFORE: + return "rename_before"; + case LD_OP_RENAME_FINAL: + return "rename_final"; default: return "op_unknown"; }; @@ -2145,6 +2149,23 @@ static void *lockspace_thread_main(void *arg_in) break; } + if (act->op == LD_OP_RENAME_BEFORE && act->rt == LD_RT_VG) { + /* vgrename */ + log_debug("S %s checking for lockspace hosts", ls->name); + rv = lm_hosts(ls, 1); + if (rv) { + log_error("S %s lockspace hosts %d", ls->name, rv); + list_del(&act->list); + act->result = -EBUSY; + add_client_result(act); + continue; + } + ls->thread_work = 0; + ls->thread_stop = 1; + /* Do we want to check hosts again below like vgremove? */ + break; + } + list_del(&act->list); /* applies to all resources */ @@ -2248,6 +2269,8 @@ out_act: act->result = 0; else if (act->op == LD_OP_STOP) act->result = 0; + else if (act->op == LD_OP_RENAME_BEFORE) + act->result = 0; else act->result = -ENOLS; list_del(&act->list); @@ -3371,6 +3394,25 @@ static int work_init_vg(struct action *act) return rv; } +static int work_rename_vg(struct action *act) +{ + char ls_name[MAX_NAME+1]; + int rv = 0; + + memset(ls_name, 0, sizeof(ls_name)); + + vg_ls_name(act->vg_name, ls_name); + + if (act->lm_type == LD_LM_SANLOCK) + rv = lm_rename_vg_sanlock(ls_name, act->vg_name, act->flags, act->vg_args); + else if (act->lm_type == LD_LM_DLM) + return 0; + else + rv = -EINVAL; + + return rv; +} + static void work_test_gl(void) { struct lockspace *ls; @@ -3526,6 +3568,11 @@ static void *worker_thread_main(void *arg_in) act->result = work_init_lv(act); add_client_result(act); + } else if ((act->op == LD_OP_RENAME_FINAL) && (act->rt == LD_RT_VG)) { + log_debug("work rename_vg %s", act->vg_name); + act->result = work_rename_vg(act); + add_client_result(act); + } else if (act->op == LD_OP_UPDATE_LOCAL) { if (delayed_update_local) { log_debug("work update_local ignore repeat"); @@ -4124,6 +4171,16 @@ static int str_to_op_rt(const char *req_name, int *op, int *rt) *op = LD_OP_UPDATE_LOCAL; return 0; } + if (!strcmp(req_name, "rename_vg_before")) { + *op = LD_OP_RENAME_BEFORE; + *rt = LD_RT_VG; + return 0; + } + if (!strcmp(req_name, "rename_vg_final")) { + *op = LD_OP_RENAME_FINAL; + *rt = LD_RT_VG; + return 0; + } out: return -1; } @@ -4743,6 +4800,7 @@ static void client_recv_action(struct client *cl) case LD_OP_UPDATE_LOCAL: case LD_OP_START_WAIT: case LD_OP_STOP_ALL: + case LD_OP_RENAME_FINAL: add_work_action(act); rv = 0; break; @@ -4751,6 +4809,7 @@ static void client_recv_action(struct client *cl) case LD_OP_ENABLE: case LD_OP_DISABLE: case LD_OP_FREE: + case LD_OP_RENAME_BEFORE: rv = add_lock_action(act); break; case LD_OP_ADD_LOCAL: diff --git a/daemons/lvmlockd/lvmlockd-internal.h b/daemons/lvmlockd/lvmlockd-internal.h index 0c84a798a..10375874a 100644 --- a/daemons/lvmlockd/lvmlockd-internal.h +++ b/daemons/lvmlockd/lvmlockd-internal.h @@ -50,6 +50,8 @@ enum { LD_OP_STOP_ALL, LD_OP_DUMP_INFO, LD_OP_DUMP_LOG, + LD_OP_RENAME_BEFORE, + LD_OP_RENAME_FINAL, }; /* resource types */ @@ -214,6 +216,7 @@ int lm_rem_resource_dlm(struct lockspace *ls, struct resource *r); int lm_init_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args); int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, char *vg_args, char *lv_args); int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r); +int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args); int lm_add_lockspace_sanlock(struct lockspace *ls); int lm_rem_lockspace_sanlock(struct lockspace *ls, int free_vg); int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode, diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c index 4f2477756..fed917bca 100644 --- a/daemons/lvmlockd/lvmlockd-sanlock.c +++ b/daemons/lvmlockd/lvmlockd-sanlock.c @@ -482,6 +482,161 @@ int lm_init_lv_sanlock(char *ls_name, char *vg_name, char *lv_name, return rv; } +/* + * Read the lockspace and each resource, replace the lockspace name, + * and write it back. + */ + +int lm_rename_vg_sanlock(char *ls_name, char *vg_name, uint32_t flags, char *vg_args) +{ + struct sanlk_lockspace ss; + struct sanlk_resourced rd; + struct sanlk_disk disk; + char lock_lv_name[MAX_ARGS]; + uint64_t offset; + uint32_t io_timeout; + int align_size; + int i, rv; + + memset(&disk, 0, sizeof(disk)); + memset(lock_lv_name, 0, sizeof(lock_lv_name)); + + if (!vg_args || !vg_args[0] || !strcmp(vg_args, "none")) { + log_error("S %s rename_vg_san vg_args missing", ls_name); + return -EINVAL; + } + + rv = lock_lv_name_from_args(vg_args, lock_lv_name); + if (rv < 0) { + log_error("S %s init_lv_san lock_lv_name_from_args error %d %s", + ls_name, rv, vg_args); + return rv; + } + + snprintf(disk.path, SANLK_PATH_LEN, "/dev/mapper/%s-%s", vg_name, lock_lv_name); + + log_debug("S %s rename_vg_san path %s", ls_name, disk.path); + + if (daemon_test) + return 0; + + /* FIXME: remove this, device is not always ready for us here */ + sleep(1); + + align_size = sanlock_align(&disk); + if (align_size <= 0) { + log_error("S %s rename_vg_san bad align size %d %s", + ls_name, align_size, disk.path); + return -EINVAL; + } + + /* + * Lockspace + */ + + memset(&ss, 0, sizeof(ss)); + memcpy(ss.host_id_disk.path, disk.path, SANLK_PATH_LEN); + ss.host_id_disk.offset = LS_BEGIN * align_size; + + rv = sanlock_read_lockspace(&ss, 0, &io_timeout); + if (rv < 0) { + log_error("S %s rename_vg_san read_lockspace error %d %s", + ls_name, rv, ss.host_id_disk.path); + return rv; + } + + strncpy(ss.name, ls_name, SANLK_NAME_LEN); + + rv = sanlock_write_lockspace(&ss, 0, 0, 0); + if (rv < 0) { + log_error("S %s rename_vg_san write_lockspace error %d %s", + ls_name, rv, ss.host_id_disk.path); + return rv; + } + + /* + * GL resource + */ + + memset(&rd, 0, sizeof(rd)); + memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN); + rd.rs.disks[0].offset = align_size * GL_LOCK_BEGIN; + rd.rs.num_disks = 1; + + rv = sanlock_read_resource(&rd.rs, 0); + if (rv < 0) { + log_error("S %s rename_vg_san read_resource gl error %d %s", + ls_name, rv, rd.rs.disks[0].path); + return rv; + } + + strncpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN); + + rv = sanlock_write_resource(&rd.rs, 0, 0, 0); + if (rv < 0) { + log_error("S %s rename_vg_san write_resource gl error %d %s", + ls_name, rv, rd.rs.disks[0].path); + return rv; + } + + /* + * VG resource + */ + + memset(&rd, 0, sizeof(rd)); + memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN); + rd.rs.disks[0].offset = align_size * VG_LOCK_BEGIN; + rd.rs.num_disks = 1; + + rv = sanlock_read_resource(&rd.rs, 0); + if (rv < 0) { + log_error("S %s rename_vg_san write_resource vg error %d %s", + ls_name, rv, rd.rs.disks[0].path); + return rv; + } + + strncpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN); + + rv = sanlock_write_resource(&rd.rs, 0, 0, 0); + if (rv < 0) { + log_error("S %s rename_vg_san write_resource vg error %d %s", + ls_name, rv, rd.rs.disks[0].path); + return rv; + } + + /* + * LV resources + */ + + offset = align_size * LV_LOCK_BEGIN; + + for (i = 0; i < LVMLOCKD_SANLOCK_MAX_LVS_IN_VG; i++) { + memset(&rd, 0, sizeof(rd)); + memcpy(rd.rs.disks[0].path, disk.path, SANLK_PATH_LEN); + rd.rs.disks[0].offset = offset; + rd.rs.num_disks = 1; + + rv = sanlock_read_resource(&rd.rs, 0); + if (rv < 0) { + log_error("S %s rename_vg_san read_resource resource area %llu error %d", + ls_name, (unsigned long long)offset, rv); + break; + } + + strncpy(rd.rs.lockspace_name, ss.name, SANLK_NAME_LEN); + + rv = sanlock_write_resource(&rd.rs, 0, 0, 0); + if (rv) { + log_error("S %s rename_vg_san write_resource resource area %llu error %d", + ls_name, (unsigned long long)offset, rv); + break; + } + offset += align_size; + } + + return 0; +} + /* lvremove */ int lm_free_lv_sanlock(struct lockspace *ls, struct resource *r) { diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c index 521f937c1..ab24dae6a 100644 --- a/lib/locking/lvmlockd.c +++ b/lib/locking/lvmlockd.c @@ -12,6 +12,7 @@ #include "toolcontext.h" #include "metadata.h" #include "segtype.h" +#include "activate.h" #include "lvmetad.h" #include "lvmlockd.h" #include "lvmcache.h" @@ -1947,3 +1948,128 @@ int lockd_update_local(struct cmd_context *cmd) return ret; } + +int lockd_rename_vg_before(struct cmd_context *cmd, struct volume_group *vg) +{ + struct lv_list *lvl; + daemon_reply reply; + int result; + int ret; + + if (!is_lockd_type(vg->lock_type)) + return 1; + + if (lvs_in_vg_activated(vg)) { + log_error("LVs must be inactive before vgrename."); + return 0; + } + + /* Check that no LVs are active on other hosts. */ + + dm_list_iterate_items(lvl, &vg->lvs) { + if (!lockd_lv(cmd, lvl->lv, "ex", 0)) { + log_error("LV %s/%s must be inactive on all hosts before vgrename.", + vg->name, lvl->lv->name); + return 0; + } + + if (!lockd_lv(cmd, lvl->lv, "un", 0)) { + log_error("Failed to unlock LV %s/%s.", vg->name, lvl->lv->name); + return 0; + } + } + + /* + * lvmlockd: + * checks for other hosts in lockspace + * leaves the lockspace + */ + + reply = _lockd_send("rename_vg_before", + "pid = %d", getpid(), + "vg_name = %s", vg->name, + "vg_lock_type = %s", vg->lock_type, + "vg_lock_args = %s", vg->lock_args, + NULL); + + if (!_lockd_result(reply, &result, NULL)) { + ret = 0; + } else { + ret = (result < 0) ? 0 : 1; + } + + daemon_reply_destroy(reply); + + if (!ret) { + log_error("lockd_rename_vg_before lvmlockd result %d", result); + return 0; + } + + if (!strcmp(vg->lock_type, "sanlock")) { + log_debug("lockd_rename_vg_before deactivate sanlock lv"); + _deactivate_sanlock_lv(cmd, vg); + } + + return 1; +} + +int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int success) +{ + daemon_reply reply; + int result; + int ret; + + if (!is_lockd_type(vg->lock_type)) + return 1; + + if (!success) { + /* + * Depending on the problem that caused the rename to + * fail, it may make sense to not restart the VG here. + */ + if (!lockd_start_vg(cmd, vg)) + log_error("Failed to restart VG %s lockspace.", vg->name); + return 1; + } + + if (!strcmp(vg->lock_type, "sanlock")) { + if (!_activate_sanlock_lv(cmd, vg)) + return 0; + + /* + * lvmlockd needs to rewrite the leases on disk + * with the new VG (lockspace) name. + */ + reply = _lockd_send("rename_vg_final", + "pid = %d", getpid(), + "vg_name = %s", vg->name, + "vg_lock_type = %s", vg->lock_type, + "vg_lock_args = %s", vg->lock_args, + NULL); + + if (!_lockd_result(reply, &result, NULL)) { + ret = 0; + } else { + ret = (result < 0) ? 0 : 1; + } + + daemon_reply_destroy(reply); + + if (!ret) { + /* + * The VG has been renamed on disk, but renaming the + * sanlock leases failed. Cleaning this up can + * probably be done by converting the VG to lock_type + * none, then converting back to sanlock. + */ + log_error("lockd_rename_vg_final lvmlockd result %d", result); + return 0; + } + } + + if (!lockd_start_vg(cmd, vg)) + log_error("Failed to start VG %s lockspace.", vg->name); + + return 1; +} + diff --git a/lib/locking/lvmlockd.h b/lib/locking/lvmlockd.h index 19c3d6146..5374204e5 100644 --- a/lib/locking/lvmlockd.h +++ b/lib/locking/lvmlockd.h @@ -99,6 +99,11 @@ int lockd_init_vg(struct cmd_context *cmd, struct volume_group *vg); int lockd_free_vg_before(struct cmd_context *cmd, struct volume_group *vg); void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg); +/* vgrename */ + +int lockd_rename_vg_before(struct cmd_context *cmd, struct volume_group *vg); +int lockd_rename_vg_final(struct cmd_context *cmd, struct volume_group *vg, int success); + /* start and stop the lockspace for a vg */ int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg); @@ -144,6 +149,9 @@ int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg, #define lockd_free_vg_before(cmd, vg) (1) #define lockd_free_vg_final(cmd, vg) do { } while (0) +#define lockd_rename_vg_before(cmd, vg) (1) +#define lockd_rename_vg_final(cmd, vg, success) (1) + #define lockd_start_vg(cmd, vg) (1) #define lockd_stop_vg(cmd, vg) (1) #define lockd_start_wait(cmd) (1) diff --git a/man/lvmlockd.8.in b/man/lvmlockd.8.in index 39deda32f..1dfa1b0a4 100644 --- a/man/lvmlockd.8.in +++ b/man/lvmlockd.8.in @@ -588,8 +588,6 @@ Things that do not yet work in lockd VGs: .br - splitting raid1 mirror LVs .br -- vgrename -.br - vgsplit .br - vgmerge diff --git a/tools/vgrename.c b/tools/vgrename.c index 438cbc63f..c0ed348c2 100644 --- a/tools/vgrename.c +++ b/tools/vgrename.c @@ -29,12 +29,6 @@ static struct volume_group *_get_old_vg_for_rename(struct cmd_context *cmd, return_NULL; } - if (is_lockd_type(vg->lock_type)) { - log_error("vgrename not allowed for lock_type %s", vg->lock_type); - unlock_and_release_vg(cmd, vg, vg_name_old); - return NULL; - } - return vg; } @@ -120,6 +114,9 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path, } else vgid = NULL; + if (!lockd_vg(cmd, vg_name_old, "ex", 0)) + return_0; + if (strcmp(vg_name_new, vg_name_old) < 0) lock_vg_old_first = 0; @@ -150,6 +147,9 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path, if (!drop_cached_metadata(vg)) stack; + if (!lockd_rename_vg_before(cmd, vg)) + return_0; + /* Change the volume group name */ vg_rename(cmd, vg, vg_name_new); @@ -177,6 +177,8 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path, } } + lockd_rename_vg_final(cmd, vg, 1); + if (!backup(vg)) stack; if (!backup_remove(cmd, vg_name_old)) @@ -196,6 +198,8 @@ static int vg_rename_path(struct cmd_context *cmd, const char *old_vg_path, return 1; error: + lockd_rename_vg_final(cmd, vg, 0); + if (lock_vg_old_first) { unlock_vg(cmd, vg_name_new); unlock_and_release_vg(cmd, vg, vg_name_old); -- cgit v1.2.1