diff options
author | David Teigland <teigland@redhat.com> | 2014-12-04 11:01:48 -0600 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2015-02-27 13:44:55 -0600 |
commit | 0234ee54fc2bc659770eb6a0297c8f8018d85023 (patch) | |
tree | 65b9e73fdb9703789a2de481e1c6374af009724f | |
parent | 75cbb4071b61adf09bc76fe6d1cb9b67da6bc3dc (diff) | |
download | lvm2-0234ee54fc2bc659770eb6a0297c8f8018d85023.tar.gz |
vgchange: allow lock_type to be changed
When lvm is using clvm, the following are possible:
- change lock type from none to clvm
- change lock type from clvm to none
When lvm is using lvmlockd, the following are possible:
- change lock type from none to clvm (with warning)
- change lock type from clvm to none
- change lock type from none to a lockd type (sanlock|dlm)
- change lock type from clvm to a lockd type (sanlock|dlm)
- change lock type from lockd type to none (TODO)
- change lock type from lockd type to clvm (TODO)
The TODO variations are still missing the steps to
undo/reverse the existing lockd type, so are currently
disabled.
A special 'vgchange --lock-type none --force' can be used
to forcibly clear all locking settings from the VG metadata,
skipping any steps that would normally be done to cleanly
undo/reverse the existing lock type.
-rw-r--r-- | lib/locking/lvmlockd.c | 46 | ||||
-rw-r--r-- | lib/locking/lvmlockd.h | 4 | ||||
-rw-r--r-- | tools/commands.h | 2 | ||||
-rw-r--r-- | tools/vgchange.c | 203 |
4 files changed, 250 insertions, 5 deletions
diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c index c6698fb57..faebdcea7 100644 --- a/lib/locking/lvmlockd.c +++ b/lib/locking/lvmlockd.c @@ -1747,6 +1747,47 @@ static int _free_lv_sanlock(struct cmd_context *cmd, struct volume_group *vg, } /* + * The lock managers have max name lengths lower than lvm; + * 64 for dlm and 48 for sanlock. Check for name collisions + * within this limit. (It's much easier to check for this here + * where the vg metadata is available than in lvmlockd.) + */ + +#define MAX_LVNAME_SANLOCK 48 +#define MAX_LVNAME_DLM 64 + +int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg, + const char *lv_name, const char *lock_type, const char **lock_args) +{ + struct lv_list *lvl; + int maxname; + + switch (lock_type_to_num(vg->lock_type)) { + case LOCK_TYPE_SANLOCK: + maxname = MAX_LVNAME_SANLOCK; + break; + case LOCK_TYPE_DLM: + maxname = MAX_LVNAME_DLM; + break; + default: + return 1; + } + + dm_list_iterate_items(lvl, &vg->lvs) { + if (!strncmp(lvl->lv->name, lv_name, maxname)) { + log_error("LV name %s matches existing LV %s within %s character limit %d", + lv_name, lvl->lv->name, vg->lock_type, maxname); + return 0; + } + } + + /* sanlock is the only lock type that sets per-LV lock_args. */ + if (!strcmp(lock_type, "sanlock")) + return _init_lv_sanlock(cmd, vg, lv_name, lock_args); + return 1; +} + +/* * lvcreate * * lvcreate sets lp lock_type to the vg lock_type, so any lv @@ -1858,10 +1899,7 @@ int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, lv_name = lp->lv_name; } - if (lock_type_num == LOCK_TYPE_SANLOCK) - return _init_lv_sanlock(cmd, vg, lv_name, &lp->lock_args); - - return 1; + return lockd_init_lv_args(cmd, vg, lv_name, lp->lock_type, &lp->lock_args); } /* lvremove */ diff --git a/lib/locking/lvmlockd.h b/lib/locking/lvmlockd.h index b368aa6e0..63ecae566 100644 --- a/lib/locking/lvmlockd.h +++ b/lib/locking/lvmlockd.h @@ -126,6 +126,9 @@ int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg, const char *lv_name, const char *lock_args); +int lockd_init_lv_args(struct cmd_context *cmd, struct volume_group *vg, + const char *lv_name, const char *lock_type, const char **lock_args); + #else /* LVMLOCKD_SUPPORT */ #define lvmlockd_init(cmd) do { } while (0) @@ -153,6 +156,7 @@ int lockd_free_lv(struct cmd_context *cmd, struct volume_group *vg, #define lockd_init_lv(cmd, vg, lp) (1) #define lockd_free_lv(cmd, vg, lv_name, lock_args) (1) +#define lockd_init_lv_args(cmd, vg, lv_name, lock_type, lock_args) (1) #endif /* LVMLOCKD_SUPPORT */ diff --git a/tools/commands.h b/tools/commands.h index a5133e26b..273930e8e 100644 --- a/tools/commands.h +++ b/tools/commands.h @@ -988,7 +988,7 @@ xx(vgchange, metadataprofile_ARG, monitor_ARG, noudevsync_ARG, metadatacopies_ARG, vgmetadatacopies_ARG, partial_ARG, physicalextentsize_ARG, poll_ARG, refresh_ARG, resizeable_ARG, resizable_ARG, select_ARG, sysinit_ARG, - systemid_ARG, test_ARG, uuid_ARG, lockstart_ARG, lockstop_ARG) + systemid_ARG, test_ARG, uuid_ARG, lockstart_ARG, lockstop_ARG, locktype_ARG) xx(vgck, "Check the consistency of volume group(s)", diff --git a/tools/vgchange.c b/tools/vgchange.c index 656149a53..b248e7ec2 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -300,9 +300,18 @@ static int _vgchange_clustered(struct cmd_context *cmd, struct volume_group *vg) { int clustered = arg_int_value(cmd, clustered_ARG, 0); + const char *lock_type = arg_str_value(cmd, locktype_ARG, NULL); struct lv_list *lvl; struct lv_segment *mirror_seg; + if (find_config_tree_bool(cmd, global_use_lvmlockd_CFG, NULL)) { + log_error("lvmlockd requires using the vgchange --lock-type option."); + return 0; + } + + if (lock_type && !strcmp(lock_type, "clvm")) + clustered = 1; + if (clustered && vg_is_clustered(vg)) { if (vg->system_id && *vg->system_id) log_warn("WARNING: Clearing invalid system ID %s from volume group %s.", @@ -498,6 +507,198 @@ static int _vgchange_profile(struct cmd_context *cmd, return 1; } +static int _vgchange_locktype(struct cmd_context *cmd, + struct volume_group *vg) +{ + const char *lock_type = arg_str_value(cmd, locktype_ARG, NULL); + const char *lock_args = NULL; + struct lv_list *lvl; + struct logical_volume *lv; + + /* + * This is a special/forced exception to change the lock type to none. + * It's needed for recovery cases and skips the normal steps of undoing + * the current lock type. It's a way to forcibly get access to a VG + * when the normal locking mechanisms are not working. + * + * It ignores: the current lvm locking config, lvmlockd, the state of + * the vg on other hosts, etc. It is meant to just remove any locking + * related metadata from the VG (cluster/lock_type flags, lock_type, + * lock_args). + * + * This can be necessary when manually recovering from certain failures. + * e.g. when a pv is lost containing the lvmlock lv (holding sanlock + * leases), the vg lock_type needs to be changed to none, and then + * back to sanlock, which recreates the lvmlock lv and leases. + */ + if (!strcmp(lock_type, "none") && arg_is_set(cmd, force_ARG)) { + if (yes_no_prompt("Forcibly change VG %s lock type to none? [y/n]: ", vg->name) == 'n') { + log_error("VG lock type not changed."); + return 0; + } + + vg->status &= ~CLUSTERED; + vg->status &= ~LOCK_TYPE; + vg->lock_type = "none"; + vg->lock_args = NULL; + + dm_list_iterate_items(lvl, &vg->lvs) { + lvl->lv->lock_type = "none"; + lvl->lv->lock_args = NULL; + } + + return 1; + } + + if (!strcmp(vg->lock_type, lock_type)) { + log_warn("New lock_type %s matches the current lock_type %s.", + lock_type, vg->lock_type); + return 1; + } + + /* + * When lvm is currently using clvm, this function is just an alternative + * to vgchange -c{y,n}, and can: + * - change none to clvm + * - change clvm to none + * - it CANNOT change to or from a lockd type + */ + if (locking_is_clustered()) { + if (is_lockd_type(lock_type)) { + log_error("Changing to lock type %s requires lvmlockd.", lock_type); + return 0; + } + + return _vgchange_clustered(cmd, vg); + } + + /* + * When lvm is currently using lvmlockd, this function can: + * - change none to lockd type + * - change none to clvm (with warning about not being able to use it) + * - change lockd type to none + * - change lockd type to clvm (with warning about not being able to use it) + * - change clvm to none + * - change clvm to lockd type + */ + + if (lvs_in_vg_activated(vg)) { + log_error("Changing VG %s lock type not allowed with active LVs", + vg->name); + return 0; + } + + /* + * Check if there are any LV types in the VG that cannot be handled + * with the new lock type. Remove this once all LV types can be + * handled. + */ + if (is_lockd_type(lock_type)) { + dm_list_iterate_items(lvl, &vg->lvs) { + lv = lvl->lv; + + if ((lv->status & SNAPSHOT) || lv_is_cow(lv)) { + log_error("Changing to lock type %s is not allowed with cow snapshot LV %s/%s", + lock_type, vg->name, lv->name); + return 0; + } + } + } + + /* none to clvm */ + if (!strcmp(vg->lock_type, "none") && !strcmp(lock_type, "clvm")) { + log_warn("New clvm lock type will not be usable with lvmlockd."); + vg->status |= CLUSTERED; + vg->lock_type = "clvm"; /* this is optional */ + return 1; + } + + /* clvm to none */ + if (!strcmp(vg->lock_type, "clvm") && !strcmp(lock_type, "none")) { + vg->status &= ~CLUSTERED; + vg->lock_type = "none"; + return 1; + } + + /* clvm to ..., first undo clvm */ + if (!strcmp(vg->lock_type, "clvm")) { + vg->status &= ~CLUSTERED; + } + + /* + * lockd type to ..., first undo lockd type + * + * To allow this, we need to do: + * lockd_stop_vg(); + * lockd_free_vg_before(); + * lockd_free_vg_after(); + */ + if (is_lockd_type(vg->lock_type)) { + /* TODO */ + log_error("Changing VG %s from lock type %s not yet allowed.", + vg->name, vg->lock_type); + return 0; + } + + /* ... to clvm */ + if (!strcmp(lock_type, "clvm")) { + log_warn("New clvm lock type will not be usable with lvmlockd."); + vg->status |= CLUSTERED; + vg->lock_type = "clvm"; /* this is optional */ + vg->system_id = NULL; + return 1; + } + + /* + * ... to lockd type. These are the same steps vgcreate uses. + */ + if (is_lockd_type(lock_type)) { + if (!vg_set_lock_type(vg, lock_type)) + return 0; + + if (!lockd_init_vg(cmd, vg)) { + log_error("Failed to initialize lock args for lock type %s", lock_type); + return 0; + } + + vg->system_id = NULL; + + /* These are the same steps lvcreate uses within a lockd type VG. */ + + dm_list_iterate_items(lvl, &vg->lvs) { + lv = lvl->lv; + + /* Some LV types have no lock. */ + if (!lv_is_visible(lv) || + lv_is_thin_volume(lv) || + lv_is_thin_pool_data(lv) || + lv_is_thin_pool_metadata(lv) || + lv_is_pool_metadata_spare(lv) || + lv_is_cache_pool(lv) || + lv_is_cache_pool_data(lv) || + lv_is_cache_pool_metadata(lv)) + continue; + + if (!lockd_init_lv_args(cmd, vg, lv->name, lock_type, &lock_args)) { + log_error("Failed to init %s lock args LV %s/%s", + lock_type, vg->name, lv->name); + return 0; + } + + lv->lock_type = dm_pool_strdup(cmd->mem, lock_type); + lv->lock_args = lock_args; + } + + if (!lockd_start_vg(cmd, vg)) + log_error("Failed to start locking for VG %s", vg->name); + + return 1; + } + + log_error("Unknown lock type"); + return 0; +} + /* * This function will not be called unless the local host is allowed to use the * VG. Either the VG has no system_id, or the VG and host have matching @@ -600,6 +801,7 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name, { metadataprofile_ARG, &_vgchange_profile }, { profile_ARG, &_vgchange_profile }, { detachprofile_ARG, &_vgchange_profile }, + { locktype_ARG, &_vgchange_locktype }, { systemid_ARG, &_vgchange_system_id }, }; @@ -793,6 +995,7 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv) arg_count(cmd, clustered_ARG) || arg_count(cmd, alloc_ARG) || arg_count(cmd, vgmetadatacopies_ARG) || + arg_count(cmd, locktype_ARG) || arg_count(cmd, systemid_ARG); int update = update_partial_safe || update_partial_unsafe; |