summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2014-12-04 11:01:48 -0600
committerDavid Teigland <teigland@redhat.com>2015-01-21 17:00:50 -0600
commit160745bfafa653845bf326f1709c8db0d95e01b8 (patch)
tree84363b4ed648afdf5d5f5c6421835b6ef23106a3
parenta53acba2ca2e8f9090bd8f173fc1040ba7117af9 (diff)
downloadlvm2-160745bfafa653845bf326f1709c8db0d95e01b8.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.c46
-rw-r--r--lib/locking/lvmlockd.h4
-rw-r--r--tools/commands.h2
-rw-r--r--tools/vgchange.c203
4 files changed, 250 insertions, 5 deletions
diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c
index 0063067fe..a8d41ff85 100644
--- a/lib/locking/lvmlockd.c
+++ b/lib/locking/lvmlockd.c
@@ -1745,6 +1745,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
@@ -1853,10 +1894,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 0972a9c21..8ddab2ee2 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -969,7 +969,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, sysinit_ARG, test_ARG, uuid_ARG,
- systemid_ARG, systemidsource_ARG, lockstart_ARG, lockstop_ARG)
+ systemid_ARG, systemidsource_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 db6938c4c..e92d030f4 100644
--- a/tools/vgchange.c
+++ b/tools/vgchange.c
@@ -301,6 +301,15 @@ static int _vgchange_clustered(struct cmd_context *cmd,
{
struct lv_list *lvl;
int clustered = arg_int_value(cmd, clustered_ARG, 0);
+ const char *lock_type = arg_str_value(cmd, locktype_ARG, NULL);
+
+ if (lock_type && !strcmp(lock_type, "clvm"))
+ clustered = 1;
+
+ if (find_config_tree_bool(cmd, global_use_lvmlockd_CFG, NULL)) {
+ log_error("lvmlockd requires changing lock type.");
+ return 0;
+ }
if (clustered && (vg_is_clustered(vg))) {
log_error("Volume group \"%s\" is already clustered",
@@ -488,6 +497,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
@@ -578,6 +779,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 },
{ systemidsource_ARG, &_vgchange_system_id },
};
@@ -772,6 +974,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) ||
arg_count(cmd, systemidsource_ARG);