diff options
author | David Teigland <teigland@redhat.com> | 2019-03-20 13:20:26 -0500 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2019-03-21 12:38:20 -0500 |
commit | 85e68a8333722b7694d607652dd1f834fadfd8c4 (patch) | |
tree | d40421815e61dd04042f83ca7fc841e83eadb707 /lib/locking | |
parent | d369de8399e14e82fb1ea45e7977d917411fbc21 (diff) | |
download | lvm2-85e68a8333722b7694d607652dd1f834fadfd8c4.tar.gz |
lvextend: refresh shared LV remotely using dlm/corosync
When lvextend extends an LV that is active with a shared
lock, use this as a signal that other hosts may also have
the LV active, with gfs2 mounted, and should have the LV
refreshed to reflect the new size. Use the libdlmcontrol
run api, which uses dlm_controld/corosync to run an
lvchange --refresh command on other cluster nodes.
Diffstat (limited to 'lib/locking')
-rw-r--r-- | lib/locking/lvmlockd.c | 165 | ||||
-rw-r--r-- | lib/locking/lvmlockd.h | 17 |
2 files changed, 167 insertions, 15 deletions
diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c index bc6e66f3b..60e061734 100644 --- a/lib/locking/lvmlockd.c +++ b/lib/locking/lvmlockd.c @@ -17,6 +17,8 @@ #include "lib/cache/lvmcache.h" #include "daemons/lvmlockd/lvmlockd-client.h" +#include <mntent.h> + static daemon_handle _lvmlockd; static const char *_lvmlockd_socket = NULL; static int _use_lvmlockd = 0; /* is 1 if command is configured to use lvmlockd */ @@ -2120,22 +2122,17 @@ int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg, * and using --lockopt skiplv to skip the incompat ex * lock, then check if an existing sh lock exists. */ - - if (!strcmp(cmd->name, "lvextend") || - !strcmp(cmd->name, "lvresize") || - !strcmp(cmd->name, "lvchange") || - !strcmp(cmd->name, "lvconvert")) { + if (!strcmp(cmd->name, "lvextend") || !strcmp(cmd->name, "lvresize") || + !strcmp(cmd->name, "lvchange") || !strcmp(cmd->name, "lvconvert")) { int ex = 0, sh = 0; if (!_query_lock_lv(cmd, vg, lv_name, lv_uuid, lock_args, &ex, &sh)) return 1; - if (sh) { log_warn("WARNING: shared LV may require refresh on other hosts where it is active."); return 1; } } - return 1; } @@ -2209,15 +2206,10 @@ int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg, * sh LV lock. */ - /* - * Special case to allow lvextend under gfs2. - * - * FIXME: verify the LV actually holds gfs2/ocfs2 which we know - * allow this (other users of the LV may not.) - */ if (lockd_flags & LD_RF_SH_EXISTS) { - if (flags & LDLV_EXTEND) { + if (flags & LDLV_SH_EXISTS_OK) { log_warn("WARNING: extending LV with a shared lock, other hosts may require LV refresh."); + cmd->lockd_lv_sh_for_ex = 1; return 1; } } @@ -2399,6 +2391,110 @@ int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv, lv->lock_args, def_mode, flags); } +/* + * Check if the LV being resized is used by gfs2/ocfs2 which we + * know allow resizing under a shared lock. + */ +static int _shared_fs_can_resize(struct logical_volume *lv) +{ + FILE *f = NULL; + struct mntent *m; + int ret = 0; + + if (!(f = setmntent("/etc/mtab", "r"))) + return 0; + + while ((m = getmntent(f))) { + if (!strcmp(m->mnt_type, "gfs2") || !strcmp(m->mnt_type, "ocfs2")) { + /* FIXME: check if this mntent is for lv */ + ret = 1; + break; + } + } + endmntent(f); + return ret; +} + +/* + * A special lockd_lv function is used for lvresize so that details can + * be saved for doing cluster "refresh" at the end of the command. + */ + +int lockd_lv_resize(struct cmd_context *cmd, struct logical_volume *lv, + const char *def_mode, uint32_t flags, + struct lvresize_params *lp) +{ + char lv_uuid[64] __attribute__((aligned(8))); + char path[PATH_MAX]; + int shupdate = (lp->lockopt && strstr(lp->lockopt, "shupdate")); + int norefresh = (lp->lockopt && strstr(lp->lockopt, "norefresh")); + int rv; + + if (!vg_is_shared(lv->vg)) + return 1; + + if (!_use_lvmlockd) { + log_error("LV in VG %s with lock_type %s requires lvmlockd.", + lv->vg->name, lv->vg->lock_type); + return 0; + } + + if (!_lvmlockd_connected) + return 0; + + /* + * A special case for gfs2 where we want to allow lvextend + * of an LV that has an existing shared lock, which is normally + * incompatible with the ex lock required by lvextend. + * + * Check if gfs2 or ocfs2 is mounted on the LV, and enable this + * SH_EXISTS_OK flag if so. Other users of the LV may not want + * to allow this. --lockopt shupdate allows the shared lock in + * place of ex even we don't detect gfs2/ocfs2. + */ + if (lp->resize == LV_EXTEND) { + if (shupdate || _shared_fs_can_resize(lv)) + flags |= LDLV_SH_EXISTS_OK; + } + + rv = lockd_lv(cmd, lv, def_mode, flags); + + if (norefresh) + return rv; + + /* + * If lockd_lv found an existing sh lock in lvmlockd and + * used that in place of the usual ex lock (we allowed this + * with SH_EXISTS_OK), then it sets this flag. + * + * We use this as a signal that we should try to refresh + * the LV on remote nodes through dlm/corosync at the end + * of the command. + * + * If lockd_lv sucessfully acquired the LV lock ex (did not + * need to make use of SH_EXISTS_OK), then we know the LV + * is active here only (or not active anywhere) and we + * don't need to do any remote refresh. + * + * lvresize --lockopt norefresh disables the remote refresh. + */ + if (cmd->lockd_lv_sh_for_ex) { + if (!id_write_format(&lv->lvid.id[1], lv_uuid, sizeof(lv_uuid))) + return 0; + if (dm_snprintf(path, sizeof(path), "%s/%s/%s", + cmd->dev_dir, lv->vg->name, lv->name) < 0) { + log_error("LV path too long for lvmlockd refresh."); + return 0; + } + + /* These will be used at the end of lvresize to do lockd_lv_refresh */ + lp->lockd_lv_refresh_path = dm_pool_strdup(cmd->mem, path); + lp->lockd_lv_refresh_uuid = dm_pool_strdup(cmd->mem, lv_uuid); + } + + return rv; +} + static int _init_lv_sanlock(struct cmd_context *cmd, struct volume_group *vg, const char *lv_name, struct id *lv_id, const char **lock_args_ret) @@ -2915,3 +3011,44 @@ int lockd_lv_uses_lock(struct logical_volume *lv) return 1; } + +/* + * send lvmlockd a request to use libdlmcontrol dlmc_run_start/dlmc_run_check + * to run a command on all nodes running dlm_controld: + * lvm lvchange --refresh --nolocking <path> + */ + +int lockd_lv_refresh(struct cmd_context *cmd, struct lvresize_params *lp) +{ + daemon_reply reply; + char *lv_uuid = lp->lockd_lv_refresh_uuid; + char *path = lp->lockd_lv_refresh_path; + int result; + + if (!lv_uuid || !path) + return 1; + + log_warn("Refreshing LV %s on other hosts...", path); + + reply = _lockd_send("refresh_lv", + "pid = " FMTd64, (int64_t) getpid(), + "opts = %s", "none", + "lv_uuid = %s", lv_uuid, + "path = %s", path, + NULL); + + if (!_lockd_result(reply, &result, NULL)) { + /* No result from lvmlockd, it is probably not running. */ + log_error("LV refresh failed for LV %s", path); + return 0; + } + daemon_reply_destroy(reply); + + if (result < 0) { + log_error("Failed to refresh LV on all hosts."); + log_error("Manual lvchange --refresh required on all hosts for %s.", path); + return 0; + } + return 1; +} + diff --git a/lib/locking/lvmlockd.h b/lib/locking/lvmlockd.h index 53d077e3f..ecd39bbd6 100644 --- a/lib/locking/lvmlockd.h +++ b/lib/locking/lvmlockd.h @@ -22,7 +22,7 @@ /* lockd_lv flags */ #define LDLV_MODE_NO_SH 0x00000001 #define LDLV_PERSISTENT 0x00000002 -#define LDLV_EXTEND 0x00000004 +#define LDLV_SH_EXISTS_OK 0x00000004 /* lvmlockd result flags */ #define LD_RF_NO_LOCKSPACES 0x00000001 @@ -82,6 +82,8 @@ int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg, const char *lock_args, const char *def_mode, uint32_t flags); int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv, const char *def_mode, uint32_t flags); +int lockd_lv_resize(struct cmd_context *cmd, struct logical_volume *lv, + const char *def_mode, uint32_t flags, struct lvresize_params *lp); /* lvcreate/lvremove use init/free */ @@ -98,6 +100,8 @@ int handle_sanlock_lv(struct cmd_context *cmd, struct volume_group *vg); int lockd_lv_uses_lock(struct logical_volume *lv); +int lockd_lv_refresh(struct cmd_context *cmd, struct lvresize_params *lp); + #else /* LVMLOCKD_SUPPORT */ static inline void lvmlockd_set_socket(const char *sock) @@ -208,6 +212,12 @@ static inline int lockd_lv(struct cmd_context *cmd, struct logical_volume *lv, return 1; } +static inline int lockd_lv_resize(struct cmd_context *cmd, struct logical_volume *lv, + const char *def_mode, uint32_t flags, struct lvresize_params *lp) +{ + return 0; +} + static inline int lockd_init_lv(struct cmd_context *cmd, struct volume_group *vg, struct logical_volume *lv, struct lvcreate_params *lp) { @@ -242,6 +252,11 @@ static inline int lockd_lv_uses_lock(struct logical_volume *lv) return 0; } +static inline int lockd_lv_refresh(struct cmd_context *cmd, struct lvresize_params *lp) +{ + return 0; +} + #endif /* LVMLOCKD_SUPPORT */ #endif /* _LVMLOCKD_H */ |