diff options
author | David Teigland <teigland@redhat.com> | 2014-11-18 13:56:40 -0600 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2015-03-05 14:24:52 -0600 |
commit | b3330a15be5447805ab234cac3b860423edbf613 (patch) | |
tree | 525b3c62b1ff35f91e9328c122828f0a0c9588c6 | |
parent | 8062e5af6a8dc3ec903e750861117b1674f4a9ad (diff) | |
download | lvm2-b3330a15be5447805ab234cac3b860423edbf613.tar.gz |
lvmlockd: start and stop VG lockspace
A lock manager requires an application to "start" or "join"
a lockspace before using locks from it. Start is the point
at which the lock manager on a host begins interacting with
other hosts to coordinate access to locks in the lockspace.
Similarly, an application needs to "stop" or "leave" a
lockspace when it's done using locks from the lockspace so
the lock manager can shut down and clean up the lockspace.
lvmlockd uses a lockspace for each sanlock|dlm VG, and the
lockspace for each VG needs to be started before lvm can use
it. These commands tell lvmlockd to start or stop the
lockspace for a VG:
vgchange --lock-start vg_name
vgchange --lock-stop vg_name
To start the lockspace for a VG, lvmlockd needs to know which
lock manager (sanlock or dlm) to use, and this is stored in the
VG metadata as lock_type = "sanlock|dlm", along with data that
is specific to the lock manager for the VG, saved as lock_args.
For sanlock, lock_args is the location of the locks on disk.
For dlm, lock_args is the name of the cluster the dlm should use.
So, the process for starting a VG includes:
- Reading the VG without a lock (no lock can be acquired
because the lockspace is not started).
- Taking the lock_type and lock_args strings from the
VG metadata.
- Asking lvmlockd to start the VG lockspace, providing
the lock_type and lock_args strings which tell lvmlockd
exactly which lock manager is needed.
- lvmlockd will ask the specific lock manager to join the
lockspace.
The VG read in the first step, without a lock, is not used for
for anything except getting the lock information needed to start
the lockspace. Subsequent use of the VG would use the VG lock.
In the case of a sanlock VG, there is an additional step in the
sequence. Between the second and third steps, the vgchange
lock-start command needs to activate the internal LV in the VG
that holds the sanlock locks. This LV must be active before
sanlock can join the lockspace.
Starting and stopping VG's would typically be done automatically
by the system, similar to the way LV's are automatically activated
by the system. But, it is always possible to directly start/stop VG
lockspaces, as it is always possible to directly activate/deactivate
LVs. Automatic VG start/stop will be added by a later patch, using
the basic functionality from this patch.
-rw-r--r-- | lib/config/config_settings.h | 1 | ||||
-rw-r--r-- | lib/locking/lvmlockd.c | 171 | ||||
-rw-r--r-- | lib/locking/lvmlockd.h | 8 | ||||
-rw-r--r-- | tools/args.h | 2 | ||||
-rw-r--r-- | tools/commands.h | 2 | ||||
-rw-r--r-- | tools/vgchange.c | 24 | ||||
-rw-r--r-- | tools/vgcreate.c | 4 |
7 files changed, 206 insertions, 6 deletions
diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h index 3600fcb3c..28a1eb46b 100644 --- a/lib/config/config_settings.h +++ b/lib/config/config_settings.h @@ -288,5 +288,6 @@ cfg(tag_host_list_CFG, "host_list", tag_CFG_SUBSECTION, CFG_ALLOW_EMPTY | CFG_DE cfg(local_system_id_CFG, "system_id", local_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 117), NULL) cfg_array(local_extra_system_ids_CFG, "extra_system_ids", local_CFG_SECTION, CFG_ALLOW_EMPTY | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 117), NULL) +cfg(local_host_id_CFG, "host_id", local_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_INT, 0, vsn(2, 2, 112), NULL) cfg(CFG_COUNT, NULL, root_CFG_SECTION, 0, CFG_TYPE_INT, 0, vsn(0, 0, 0), NULL) diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c index d3349b701..db84a29d1 100644 --- a/lib/locking/lvmlockd.c +++ b/lib/locking/lvmlockd.c @@ -539,11 +539,8 @@ static int _free_vg_dlm(struct cmd_context *cmd, struct volume_group *vg) return 0; } - /* - * Leave the dlm lockspace. - * Joining and leaving the lockspaces to be added by later patch. - * lockd_stop_vg(cmd, vg); - */ + /* Leave the dlm lockspace. */ + lockd_stop_vg(cmd, vg); return 1; } @@ -702,3 +699,167 @@ void lockd_free_vg_final(struct cmd_context *cmd, struct volume_group *vg) } } +/* + * Starting a vg involves: + * 1. reading the vg without a lock + * 2. getting the lock_type/lock_args from the vg metadata + * 3. doing start_vg in lvmlockd for the lock_type; + * this means joining the lockspace + * + * The vg read in step 1 should not be used for anything + * other than getting the lock_type/lock_args/uuid necessary + * for starting the lockspace. To use the vg after starting + * the lockspace, follow the standard method which is: + * lock the vg, read/use/write the vg, unlock the vg. + */ + +int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg) +{ + char uuid[64] __attribute__((aligned(8))); + daemon_reply reply; + const char *lock_type; + int host_id = 0; + int result; + int ret; + + memset(uuid, 0, sizeof(uuid)); + + /* + * We do not skip non-lockd vg's here (see add_local below). + * We use this to ensure lvmlockd has seen the local vg. + * It is an optimization in case lvmlockd has not seen the + * local vg yet. + */ + + if (!_lvmlockd_active) + return 1; + if (!lvmlockd_connected()) + return 0; + + /* Skip starting the vg lockspace when the vg lock is skipped. */ + + /* Added in a later patch. */ + /* + if (cmd_mode && !strcmp(cmd_mode, "na")) + return 1; + */ + + log_debug("lockd_start_vg %s lock_type %s", vg->name, + vg->lock_type ? vg->lock_type : "empty"); + + if (vg->lock_type && !strcmp(vg->lock_type, "sanlock")) { + /* + * This is the big difference between starting + * sanlock vgs vs starting dlm vgs: the internal + * sanlock lv needs to be activated before lvmlockd + * does the start because sanlock needs to use the lv + * to access locks. + */ + if (!_activate_sanlock_lv(cmd, vg)) + return 0; + + host_id = find_config_tree_int(cmd, local_host_id_CFG, NULL); + } + + id_write_format(&vg->id, uuid, sizeof(uuid)); + + if (!is_lockd_type(vg->lock_type)) { + const char *sysid = NULL; + + if (vg->system_id && (strlen(vg->system_id) > 0)) + sysid = vg->system_id; + + reply = _lockd_send("add_local", + "pid = %d", getpid(), + "vg_name = %s", vg->name, + "vg_uuid = %s", uuid[0] ? uuid : "none", + "vg_sysid = %s", sysid ?: "none", + "our_system_id = %s", cmd->system_id ?: "none", + NULL); + + lock_type = "local"; + } else { + reply = _lockd_send("start_vg", + "pid = %d", getpid(), + "vg_name = %s", vg->name, + "vg_lock_type = %s", vg->lock_type, + "vg_lock_args = %s", vg->lock_args, + "vg_uuid = %s", uuid[0] ? uuid : "none", + "version = %d", (int64_t)vg->seqno, + "host_id = %d", host_id, + NULL); + + lock_type = vg->lock_type; + } + + if (!_lockd_result(reply, &result, NULL)) { + result = -1; + ret = 0; + } else { + ret = (result < 0) ? 0 : 1; + } + + if (result == -EEXIST) { + ret = 1; + goto out; + } + + if (!ret) + log_error("Locking start %s VG %s %d", lock_type, vg->name, result); + else + log_debug("lockd_start_vg %s done", vg->name); + +out: + daemon_reply_destroy(reply); + + return ret; +} + +int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg) +{ + daemon_reply reply; + int result; + int ret; + + if (!is_lockd_type(vg->lock_type)) + return 1; + + if (!_lvmlockd_active) + return 1; + if (!lvmlockd_connected()) + return 0; + + log_debug("lockd_stop_vg %s lock_type %s", vg->name, + vg->lock_type ? vg->lock_type : "empty"); + + reply = _lockd_send("stop_vg", + "pid = %d", getpid(), + "vg_name = %s", vg->name, + NULL); + + if (!_lockd_result(reply, &result, NULL)) { + ret = 0; + } else { + ret = (result < 0) ? 0 : 1; + } + + if (result == -EBUSY) { + log_error("Cannot stop locking in busy VG %s", vg->name); + goto out; + } + + if (!ret) { + log_error("Locking stop %s VG %s %d", vg->lock_type, vg->name, result); + goto out; + } + + if (!strcmp(vg->lock_type, "sanlock")) { + log_debug("lockd_stop_vg deactivate sanlock lv"); + _deactivate_sanlock_lv(cmd, vg); + } +out: + daemon_reply_destroy(reply); + + return ret; +} + diff --git a/lib/locking/lvmlockd.h b/lib/locking/lvmlockd.h index c7374d6d0..e35ec0d1e 100644 --- a/lib/locking/lvmlockd.h +++ b/lib/locking/lvmlockd.h @@ -78,6 +78,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); +/* start and stop the lockspace for a vg */ + +int lockd_start_vg(struct cmd_context *cmd, struct volume_group *vg); +int lockd_stop_vg(struct cmd_context *cmd, struct volume_group *vg); + #else /* LVMLOCKD_SUPPORT */ #define lvmlockd_init(cmd) do { } while (0) @@ -91,6 +96,9 @@ void lockd_free_vg_final(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_start_vg(cmd, vg) (1) +#define lockd_stop_vg(cmd, vg) (1) + #endif /* LVMLOCKD_SUPPORT */ #endif diff --git a/tools/args.h b/tools/args.h index 0a6778432..76f54de8e 100644 --- a/tools/args.h +++ b/tools/args.h @@ -48,6 +48,8 @@ arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0) arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", NULL, 0) arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", NULL, 0) arg(labelsector_ARG, '\0', "labelsector", int_arg, 0) +arg(lockstart_ARG, '\0', "lock-start", string_arg, 0) +arg(lockstop_ARG, '\0', "lock-stop", string_arg, 0) arg(locktype_ARG, '\0', "lock-type", string_arg, 0) arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", size_kb_arg, 0) arg(merge_ARG, '\0', "merge", NULL, 0) diff --git a/tools/commands.h b/tools/commands.h index a89a8ab1a..3891fb373 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) + systemid_ARG, test_ARG, uuid_ARG, lockstart_ARG, lockstop_ARG) xx(vgck, "Check the consistency of volume group(s)", diff --git a/tools/vgchange.c b/tools/vgchange.c index 36b44a9ad..0439189c4 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -579,9 +579,23 @@ static int _vgchange_system_id(struct cmd_context *cmd, struct volume_group *vg) if (vg->lvm1_system_id) *vg->lvm1_system_id = '\0'; + /* update system_id in lvmlockd's record for this vg */ + if (!lockd_start_vg(cmd, vg)) + log_debug("Failed to update lvmlockd."); + return 1; } +static int _vgchange_lock_start(struct cmd_context *cmd, struct volume_group *vg) +{ + return lockd_start_vg(cmd, vg); +} + +static int _vgchange_lock_stop(struct cmd_context *cmd, struct volume_group *vg) +{ + return lockd_stop_vg(cmd, vg); +} + static int vgchange_single(struct cmd_context *cmd, const char *vg_name, struct volume_group *vg, struct processing_handle *handle __attribute__((unused))) @@ -696,6 +710,14 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name, if (!_vgchange_background_polling(cmd, vg)) return_ECMD_FAILED; + if (arg_is_set(cmd, lockstart_ARG)) { + if (!_vgchange_lock_start(cmd, vg)) + return_ECMD_FAILED; + } else if (arg_is_set(cmd, lockstop_ARG)) { + if (!_vgchange_lock_stop(cmd, vg)) + return_ECMD_FAILED; + } + return ret; } @@ -703,6 +725,8 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv) { int noupdate = arg_count(cmd, activate_ARG) || + arg_count(cmd, lockstart_ARG) || + arg_count(cmd, lockstop_ARG) || arg_count(cmd, monitor_ARG) || arg_count(cmd, poll_ARG) || arg_count(cmd, refresh_ARG); diff --git a/tools/vgcreate.c b/tools/vgcreate.c index 6d46d727b..52dcfd48a 100644 --- a/tools/vgcreate.c +++ b/tools/vgcreate.c @@ -135,6 +135,10 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv) clustered_message, *clustered_message ? 'v' : 'V', vg->name, vg->system_id ? " with system ID " : "", vg->system_id ? : ""); + /* Start the VG lockspace because it will likely be used right away. */ + if (!lockd_start_vg(cmd, vg)) + log_error("Failed to start locking"); + release_vg(vg); return ECMD_PROCESSED; |