diff options
-rw-r--r-- | daemons/lvmlockd/lvmlockd-client.h | 8 | ||||
-rw-r--r-- | lib/config/config_settings.h | 2 | ||||
-rw-r--r-- | lib/locking/lvmlockd.c | 18 | ||||
-rw-r--r-- | lib/locking/lvmlockd.h | 8 | ||||
-rw-r--r-- | tools/Makefile.in | 5 | ||||
-rw-r--r-- | tools/args.h | 1 | ||||
-rw-r--r-- | tools/dlock.c | 363 | ||||
-rw-r--r-- | tools/dlock.h | 17 | ||||
-rw-r--r-- | tools/lvchange.c | 3 | ||||
-rw-r--r-- | tools/lvmcmdline.c | 15 | ||||
-rw-r--r-- | tools/lvscan.c | 3 | ||||
-rw-r--r-- | tools/pvchange.c | 7 | ||||
-rw-r--r-- | tools/pvcreate.c | 3 | ||||
-rw-r--r-- | tools/pvdisplay.c | 3 | ||||
-rw-r--r-- | tools/pvremove.c | 3 | ||||
-rw-r--r-- | tools/pvresize.c | 7 | ||||
-rw-r--r-- | tools/pvscan.c | 3 | ||||
-rw-r--r-- | tools/reporter.c | 3 | ||||
-rw-r--r-- | tools/tools.h | 2 | ||||
-rw-r--r-- | tools/vgchange.c | 33 | ||||
-rw-r--r-- | tools/vgcreate.c | 3 | ||||
-rw-r--r-- | tools/vgextend.c | 3 | ||||
-rw-r--r-- | tools/vgmerge.c | 3 | ||||
-rw-r--r-- | tools/vgreduce.c | 3 | ||||
-rw-r--r-- | tools/vgremove.c | 3 | ||||
-rw-r--r-- | tools/vgrename.c | 3 | ||||
-rw-r--r-- | tools/vgscan.c | 3 | ||||
-rw-r--r-- | tools/vgsplit.c | 3 |
28 files changed, 530 insertions, 1 deletions
diff --git a/daemons/lvmlockd/lvmlockd-client.h b/daemons/lvmlockd/lvmlockd-client.h index bde0191ea..dcae38468 100644 --- a/daemons/lvmlockd/lvmlockd-client.h +++ b/daemons/lvmlockd/lvmlockd-client.h @@ -34,6 +34,14 @@ static inline void lvmlockd_close(daemon_handle h) } /* + * Errors returned as the lvmlockd result value. + */ +#define ENOLS 210 /* lockspace not found */ +#define ELOCALVG 211 /* vg is local */ +#define EOTHERVG 212 /* vg sysid specifies other host */ +#define ESTARTING 213 /* lockspace is starting */ + +/* * Also see lvmlockd-sanlock GL_LOCK_BEGIN, VG_LOCK_BEGIN, LV_LOCK_BEGIN. * gl lock at sanlock lease area 65 * vg lock at sanlock lease area 66 diff --git a/lib/config/config_settings.h b/lib/config/config_settings.h index 39e4b0e5a..7438143ba 100644 --- a/lib/config/config_settings.h +++ b/lib/config/config_settings.h @@ -194,6 +194,8 @@ cfg(global_cache_repair_executable_CFG, "cache_repair_executable", global_CFG_SE cfg_array(global_cache_repair_options_CFG, "cache_repair_options", global_CFG_SECTION, 0, CFG_TYPE_STRING, "#S" DEFAULT_CACHE_REPAIR_OPTIONS, vsn(2, 2, 108), NULL) cfg(global_system_id_source_CFG, "system_id_source", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 112), NULL) cfg(global_system_id_file_CFG, "system_id_file", global_CFG_SECTION, CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(2, 2, 112), NULL) +cfg(global_allow_override_lock_modes_CFG, "allow_override_lock_modes", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 112), NULL) +cfg(global_read_only_lock_modes_CFG, "read_only_lock_modes", global_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2, 2, 112), NULL) cfg(activation_checks_CFG, "checks", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_ACTIVATION_CHECKS, vsn(2, 2, 86), NULL) cfg(activation_udev_sync_CFG, "udev_sync", activation_CFG_SECTION, 0, CFG_TYPE_BOOL, DEFAULT_UDEV_SYNC, vsn(2, 2, 51), NULL) diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c index 29b72390f..ec8f1c40e 100644 --- a/lib/locking/lvmlockd.c +++ b/lib/locking/lvmlockd.c @@ -105,8 +105,26 @@ void lvmlockd_set_socket(const char *sock) _lvmlockd_socket = sock; } +/* Translate the result strings from lvmlockd to bit flags. */ static void _result_str_to_flags(const char *str, uint32_t *flags) { + if (strstr(str, "NO_LOCKSPACES")) + *flags |= LD_RF_NO_LOCKSPACES; + + if (strstr(str, "NO_GL_LS")) + *flags |= LD_RF_NO_GL_LS; + + if (strstr(str, "LOCAL_LS")) + *flags |= LD_RF_LOCAL_LS; + + if (strstr(str, "DUP_GL_LS")) + *flags |= LD_RF_DUP_GL_LS; + + if (strstr(str, "INACTIVE_LS")) + *flags |= LD_RF_INACTIVE_LS; + + if (strstr(str, "ADD_LS_ERROR")) + *flags |= LD_RF_ADD_LS_ERROR; } /* diff --git a/lib/locking/lvmlockd.h b/lib/locking/lvmlockd.h index 2aeaaee7d..87b49ccfe 100644 --- a/lib/locking/lvmlockd.h +++ b/lib/locking/lvmlockd.h @@ -19,6 +19,14 @@ #define LOCK_TYPE_DLM 2 #define LOCK_TYPE_SANLOCK 3 +/* lvmlockd_send result flags */ +#define LD_RF_NO_LOCKSPACES 0x00000001 +#define LD_RF_NO_GL_LS 0x00000002 +#define LD_RF_LOCAL_LS 0x00000004 +#define LD_RF_DUP_GL_LS 0x00000008 +#define LD_RF_INACTIVE_LS 0x00000010 +#define LD_RF_ADD_LS_ERROR 0x00000020 + /* * lock_type lock_type_num * "none" -> LOCK_TYPE_NONE diff --git a/tools/Makefile.in b/tools/Makefile.in index 30f5fba43..d6a4de1eb 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -17,7 +17,6 @@ top_srcdir = @top_srcdir@ top_builddir = @top_builddir@ SOURCES =\ - dlock.c \ dumpconfig.c \ formats.c \ lvchange.c \ @@ -64,6 +63,10 @@ SOURCES =\ vgscan.c \ vgsplit.c +ifeq ("@BUILD_LVMLOCKD@", "yes") + SOURCES += dlock.c +endif + SOURCES2 =\ dmsetup.c \ lvm.c \ diff --git a/tools/args.h b/tools/args.h index afa4ce6f5..72f592dd5 100644 --- a/tools/args.h +++ b/tools/args.h @@ -47,6 +47,7 @@ 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(lockgl_ARG, '\0', "lock-gl", string_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) diff --git a/tools/dlock.c b/tools/dlock.c index a962b4c6a..cefa54d7c 100644 --- a/tools/dlock.c +++ b/tools/dlock.c @@ -15,3 +15,366 @@ #include "lvmcache.h" #include "lvmlockd-client.h" +static int _mode_num(const char *mode) +{ + if (!strcmp(mode, "na")) + return -2; + if (!strcmp(mode, "un")) + return -1; + if (!strcmp(mode, "nl")) + return 0; + if (!strcmp(mode, "sh")) + return 1; + if (!strcmp(mode, "ex")) + return 2; + return -3; +} + +/* same rules as strcmp */ +static int _mode_compare(const char *m1, const char *m2) +{ + int n1 = _mode_num(m1); + int n2 = _mode_num(m2); + + if (n1 < n2) + return -1; + if (n1 == n2) + return 0; + if (n1 > n2) + return 1; + return -2; +} + +/* + * Mode is selected by: + * 1. mode from command line option (only taken if allow_override is set) + * 2. the function arg passed by the calling command (def_mode) + * 3. look up a default mode for the command + * (cases where the caller doesn't know a default) + * + * MODE_NOARG: don't use mode from command line option + */ + +/* + * dlock_gl_create() is used by vgcreate to acquire and/or create the + * global lock. vgcreate will have a lock_type for the new vg which + * dlock_gl_create() can provide in the lock-gl call. + * + * dlock_gl() and dlock_gl_create() differ in the specific cases where + * ENOLS (no lockspace found) is overriden. In the vgcreate case, the + * override cases are related to sanlock bootstrap, and the lock_type of + * the vg being created is needed. + * + * 1. vgcreate of the first dlock-type vg calls dlock_gl_create() + * to acquire the global lock. + * + * 2. vgcreate/dlock_gl_create passes gl lock request to lvmlockd, + * along with lock_type of the new vg. + * + * 3. lvmlockd finds no global lockspace/lock. + * + * 4. dlm: + * If the lock_type from vgcreate is dlm, lvmlockd creates the + * dlm global lockspace, and queues the global lock request + * for vgcreate. dlock_gl_create returns sucess with the gl held. + * + * sanlock: + * If the lock_type from vgcreate is sanlock, lvmlockd returns -ENOLS + * with the NO_GL_LS flag. lvmlockd cannot create or acquire a sanlock + * global lock until the VG exists on disk (the locks live within the VG). + * + * dlock_gl_create sees sanlock/ENOLS/NO_GL_LS (and optionally the + * "enable" lock-gl arg), determines that this is the sanlock + * bootstrap special case, and returns success without the global lock. + * + * vgcreate creates the VG on disk, and calls lvmlockd_init_vg() which + * initializes/enables a global lock on the new VG's internal sanlock lv. + * Future dlock_gl/dlock_gl_create calls will acquire the existing gl. + */ + +int dlock_gl_create(struct cmd_context *cmd, const char *def_mode, uint32_t flags, + const char *vg_lock_type) +{ + const char *mode = NULL; + uint32_t result_flags; + int result; + int ret; + + if (!(flags & DL_GL_MODE_NOARG)) { + mode = arg_str_value(cmd, lockgl_ARG, NULL); + if (mode && def_mode && strcmp(mode, "enable") && + (_mode_compare(mode, def_mode) < 0) && + !find_config_tree_bool(cmd, global_allow_override_lock_modes_CFG, NULL)) { + log_error("Disallowed lock-gl mode \"%s\"", mode); + return 0; + } + } + + if (!mode) + mode = def_mode; + + if (!mode) { + log_error("Unknown lock-gl mode"); + return 0; + } + + if (!strcmp(mode, "ex") && find_config_tree_bool(cmd, global_read_only_lock_modes_CFG, NULL)) { + log_error("Disallow lock-gl ex with read_only_lock_modes"); + return 0; + } + + ret = lvmlockd_send(cmd, command_name(cmd), "lock_gl", + NULL, vg_lock_type, NULL, NULL, NULL, mode, "update_names", + &result, &result_flags); + if (!ret) { + /* no result from lvmlockd */ + log_error("Locking failed for global lock"); + return 0; + } + + /* + * result and result_flags were returned from lvmlockd. + * In lvmlockd, result 0 is success, and error is < 0. + */ + + /* + * No lockspace was found with a global lock. + */ + if (result == -ENOLS) { + /* + * It's not a problem if an unlock happens after the + * lockspace has been removed; ignore it. + */ + if (!strcmp(mode, "un")) + return 1; + + /* + * This is the explicit sanlock bootstrap condition for + * proceding without the global lock: a chicken/egg case + * for the first sanlock VG that is created. + * + * When creating the first sanlock VG, there is no global + * lock to acquire because the gl will exist in the VG + * being created. The "enable" option makes explicit that + * this is expected: + * + * vgcreate --lock-type sanlock --lock-gl enable + * + * There are three indications that this is the unique + * first-sanlock-vg bootstrap case: + * + * - result from lvmlockd is -ENOLS because lvmlockd found + * no lockspace for this VG; expected because it's being + * created here. + * + * - result flag LD_RF_NO_GL_LS from lvmlockd means that + * lvmlockd has seen no other lockspace with a global lock. + * This implies that this is probably the first sanlock vg + * to be created. If other sanlock vgs exist, the global + * lock should be available from one of them. + * + * - command line lock-gl arg is "enable" which means the + * user expects this to be the first sanlock vg, and the + * global lock should be enabled in it. + */ + + if ((result_flags & LD_RF_NO_GL_LS) && + !strcmp(vg_lock_type, "sanlock") && + !strcmp(mode, "enable")) { + log_debug("Enabling sanlock global lock"); + lvmetad_validate_global_cache(cmd, 1); + return 1; + } + + /* + * This is an implicit sanlock bootstrap condition for + * proceeding without the global lock. The command line does + * not indicate explicitly that this is a bootstrap situation + * (via "enable"), but it seems likely to be because lvmlockd + * has seen no dlock-type vgs. It is possible that a global + * lock does exist in a vg that has not yet been seen. If that + * vg appears after this creates a new vg with a new enabled + * gl, then there will be two enabled global locks, and one + * will need to be disabled. (We could instead return an error + * here and insist with an error message that the --lock-gl + * enable option be used to exercise the explicit case above.) + */ + + if ((result_flags & LD_RF_NO_GL_LS) && + (result_flags & LD_RF_NO_LOCKSPACES) && + !strcmp(vg_lock_type, "sanlock")) { + log_print_unless_silent("Enabling sanlock global lock"); + lvmetad_validate_global_cache(cmd, 1); + return 1; + } + + /* + * Allow non-dlock-type vgs to be created even when the global + * lock is not available. Once created, these vgs will only be + * accessible to the local system_id, and not protected by + * locks, so allowing the creation without a lock is a very + * minor exception to normal locking. + */ + + if ((result_flags & LD_RF_NO_GL_LS) && + (!strcmp(vg_lock_type, "none"))) { + lvmetad_validate_global_cache(cmd, 1); + return 1; + } + + log_error("Global lock %s error %d", mode, result); + return 0; + } + + if (result < 0) { + log_error("Global lock %s error %d", mode, result); + return 0; + } + + if (!(flags & DL_GL_SKIP_CACHE_VALIDATE)) + lvmetad_validate_global_cache(cmd, 0); + + return 1; +} + +int dlock_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags) +{ + const char *mode = NULL; + const char *opts = NULL; + uint32_t result_flags; + int result; + int ret; + + if (!(flags & DL_GL_MODE_NOARG)) { + mode = arg_str_value(cmd, lockgl_ARG, NULL); + if (mode && def_mode && + (_mode_compare(mode, def_mode) < 0) && + !find_config_tree_bool(cmd, global_allow_override_lock_modes_CFG, NULL)) { + log_error("Disallowed lock-gl mode \"%s\"", mode); + return 0; + } + } + + if (!mode) + mode = def_mode; + + if (!mode) { + log_error("Unknown lock-gl mode"); + return 0; + } + + if (!strcmp(mode, "ex") && find_config_tree_bool(cmd, global_read_only_lock_modes_CFG, NULL)) { + log_error("Disallow lock-gl ex with read_only_lock_modes"); + return 0; + } + + /* + * The dlock_gl() caller uses this flag when it is going to change the + * VG namesapce. lvmlockd uses this to encode extra information in the + * global lock data (a separate version number in the lvb) about what + * was changed. Other hosts will see this extra information in the gl + * data and know that the VG namespace changed, which determines the + * kind of cache refresh they need to do. + */ + if (flags & DL_GL_UPDATE_NAMES) + opts = "update_names"; + + ret = lvmlockd_send(cmd, command_name(cmd), "lock_gl", + NULL, NULL, NULL, NULL, NULL, mode, opts, + &result, &result_flags); + if (!ret) { + /* No result from lvmlockd, it is probably not running. */ + + /* + * These options historically mean that locking is expected + * to fail and the command should be allowed to proceed anyway. + */ + if (arg_is_set(cmd, sysinit_ARG) || arg_is_set(cmd, ignorelockingfailure_ARG)) { + log_debug("Ignore failed locking for global lock: option %s", + arg_is_set(cmd, sysinit_ARG) ? "sysinit" : "ignorelockingfailure"); + return 1; + } + + /* + * We don't care if an unlock operation fails in this case, and + * we can allow a shared lock request to succeed without any + * serious harm. To disallow basic reading/reporting when + * lvmlockd is stopped is too strict, unnecessary, and + * inconvenient. We force a global cache validation in this + * case. + */ + + if (!strcmp(mode, "un")) + return 1; + + if (!strcmp(mode, "sh")) { + log_warn("Reading without shared global lock."); + lvmetad_validate_global_cache(cmd, 1); + return 1; + } + + log_error("Locking failed for global lock"); + return 0; + } + + /* + * result and result_flags were returned from lvmlockd. + * in lvmlockd, result 0 is success, and error is < 0. + */ + + if (result == -ENOLS || result == -ESTARTING) { + + /* It doesn't matter if an unlock operation fails. */ + if (!strcmp(mode, "un")) + return 1; + + /* + * This is a general condition for allowing the command to + * proceed without a shared global lock when the global lock is + * not found or ready. This should not be a persistent + * condition. The VG containing the global lock should appear + * on the system, or the global lock should be enabled in + * another VG, or the the lockspace with the gl should finish + * starting. + * + * Same reasons as above for allowing the command to proceed + * with the shared gl. We force a global cache validation and + * print a warning. + */ + + if (strcmp(mode, "sh")) { + log_error("Global lock %s error %d", mode, result); + return 0; + } + + if (result == -ESTARTING) { + log_warn("Skipping global lock: lockspace is starting"); + lvmetad_validate_global_cache(cmd, 1); + return 1; + } + + if ((result_flags & LD_RF_NO_GL_LS) || + (result_flags & LD_RF_NO_LOCKSPACES)) { + log_warn("Skipping global lock: not found"); + lvmetad_validate_global_cache(cmd, 1); + return 1; + } + + log_error("Global lock %s error %d", mode, result); + return 0; + } + + if ((result_flags & LD_RF_DUP_GL_LS) && strcmp(mode, "un")) + log_warn("Duplicate sanlock global locks should be corrected"); + + if (result < 0) { + log_error("Global lock %s error %d", mode, result); + return 0; + } + + if (!(flags & DL_GL_SKIP_CACHE_VALIDATE)) + lvmetad_validate_global_cache(cmd, 0); + + return 1; +} + diff --git a/tools/dlock.h b/tools/dlock.h index 3c852a844..255c90080 100644 --- a/tools/dlock.h +++ b/tools/dlock.h @@ -11,4 +11,21 @@ #ifndef _DLOCK_H #define _DLOCK_H +#define DL_GL_MODE_NOARG 0x00000001 +#define DL_GL_SKIP_CACHE_VALIDATE 0x00000002 +#define DL_GL_UPDATE_NAMES 0x00000004 + +#ifdef LVMLOCKD_SUPPORT + +int dlock_gl_create(struct cmd_context *cmd, const char *def_mode, uint32_t flags, + const char *vg_lock_type); +int dlock_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags); + +#else /* LVMLOCKD_SUPPORT */ + +#define dlock_gl_create(cmd, def_mode, flags, vg_lock_type) (1) +#define dlock_gl(cmd, def_mode, flags) (1) + +#endif /* LVMLOCKD_SUPPORT */ + #endif diff --git a/tools/lvchange.c b/tools/lvchange.c index e0bb4b1e1..c2c4256e0 100644 --- a/tools/lvchange.c +++ b/tools/lvchange.c @@ -1138,6 +1138,9 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv) } } + if (arg_tag_count(argc, argv) && !dlock_gl(cmd, "sh", 0)) + return_ECMD_FAILED; + return process_each_lv(cmd, argc, argv, update ? READ_FOR_UPDATE : 0, NULL, &_lvchange_single); diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 9f9891fea..07427f941 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -569,6 +569,20 @@ int string_arg(struct cmd_context *cmd __attribute__((unused)), return 1; } +int arg_tag_count(int argc, char **argv) +{ + const char *name; + int count = 0; + int i; + + for (i = 0; i < argc; i++) { + name = argv[i]; + if (*name == '@') + count++; + } + return count; +} + int tag_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av) { char *pos = av->value; @@ -747,6 +761,7 @@ void lvm_register_commands(void) yes_ARG, \ quiet_ARG, config_ARG, \ commandprofile_ARG, \ + lockgl_ARG, \ profile_ARG, -1); #include "commands.h" #undef xx diff --git a/tools/lvscan.c b/tools/lvscan.c index 2d7be074b..9106ab3dc 100644 --- a/tools/lvscan.c +++ b/tools/lvscan.c @@ -98,6 +98,9 @@ int lvscan(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } + if (!dlock_gl(cmd, "sh", 0)) + return_ECMD_FAILED; + return process_each_lv(cmd, argc, argv, 0, NULL, &lvscan_single); } diff --git a/tools/pvchange.c b/tools/pvchange.c index f616c0925..466ecfe2d 100644 --- a/tools/pvchange.c +++ b/tools/pvchange.c @@ -90,6 +90,10 @@ static int _pvchange_single(struct cmd_context *cmd, struct volume_group *vg, } } + /* Convert sh to ex. gl only needed for orphans. */ + if (is_orphan(pv) && !dlock_gl(cmd, "ex", 0)) + return_ECMD_FAILED; + if (tagargs) { /* tag or deltag */ if (arg_count(cmd, addtag_ARG) && !change_tag(cmd, NULL, NULL, pv, addtag_ARG)) @@ -176,6 +180,9 @@ int pvchange(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } + if (!dlock_gl(cmd, "sh", 0)) + return_ECMD_FAILED; + params.done = 0; params.total = 0; diff --git a/tools/pvcreate.c b/tools/pvcreate.c index 139819883..8aa05c163 100644 --- a/tools/pvcreate.c +++ b/tools/pvcreate.c @@ -96,6 +96,9 @@ int pvcreate(struct cmd_context *cmd, int argc, char **argv) int ret = ECMD_PROCESSED; struct pvcreate_params pp; + if (!dlock_gl(cmd, "ex", 0)) + return_ECMD_FAILED; + pvcreate_params_set_defaults(&pp); if (!pvcreate_restore_params_validate(cmd, argc, argv, &pp)) { diff --git a/tools/pvdisplay.c b/tools/pvdisplay.c index d4cb51680..ad2260c8c 100644 --- a/tools/pvdisplay.c +++ b/tools/pvdisplay.c @@ -106,6 +106,9 @@ int pvdisplay(struct cmd_context *cmd, int argc, char **argv) } } + if (!dlock_gl(cmd, "sh", 0)) + return_ECMD_FAILED; + ret = process_each_pv(cmd, argc, argv, NULL, 0, NULL, _pvdisplay_single); diff --git a/tools/pvremove.c b/tools/pvremove.c index 035d4fd4e..a2b71f302 100644 --- a/tools/pvremove.c +++ b/tools/pvremove.c @@ -30,6 +30,9 @@ int pvremove(struct cmd_context *cmd, int argc, char **argv) force_count = arg_count(cmd, force_ARG); prompt = arg_count(cmd, yes_ARG); + if (!dlock_gl(cmd, "ex", 0)) + return_ECMD_FAILED; + for (i = 0; i < argc; i++) { dm_unescape_colons_and_at_signs(argv[i], NULL, NULL); if (!pvremove_single(cmd, argv[i], NULL, force_count, prompt)) { diff --git a/tools/pvresize.c b/tools/pvresize.c index 70b564dc2..66186f9b5 100644 --- a/tools/pvresize.c +++ b/tools/pvresize.c @@ -32,6 +32,10 @@ static int _pvresize_single(struct cmd_context *cmd, params->total++; + /* Convert sh to ex. gl is only needed for orphans. */ + if (is_orphan(pv) && !dlock_gl(cmd, "ex", 0)) + return_ECMD_FAILED; + if (!pv_resize_single(cmd, vg, pv, params->new_size)) return_ECMD_FAILED; @@ -61,6 +65,9 @@ int pvresize(struct cmd_context *cmd, int argc, char **argv) params.done = 0; params.total = 0; + if (!dlock_gl(cmd, "sh", 0)) + return_ECMD_FAILED; + ret = process_each_pv(cmd, argc, argv, NULL, READ_FOR_UPDATE, ¶ms, _pvresize_single); diff --git a/tools/pvscan.c b/tools/pvscan.c index 3eaf0bbcb..0de8cd3dc 100644 --- a/tools/pvscan.c +++ b/tools/pvscan.c @@ -224,6 +224,9 @@ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } + if (!dlock_gl(cmd, "sh", 0)) + return_ECMD_FAILED; + /* Scan everything? */ if (!argc && !devno_args) { if (!lvmetad_pvscan_all_devs(cmd, handler)) diff --git a/tools/reporter.c b/tools/reporter.c index a3b860676..4ba9ac261 100644 --- a/tools/reporter.c +++ b/tools/reporter.c @@ -269,6 +269,9 @@ static int _report(struct cmd_context *cmd, int argc, char **argv, if (args_are_pvs && argc) cmd->filter->wipe(cmd->filter); + if ((!argc || arg_tag_count(argc, argv)) && !dlock_gl(cmd, "sh", 0)) + return_ECMD_FAILED; + switch (report_type) { case DEVTYPES: keys = find_config_tree_str(cmd, report_devtypes_sort_CFG, NULL); diff --git a/tools/tools.h b/tools/tools.h index 11a88afe0..0f0495e0c 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -174,6 +174,8 @@ unsigned grouped_arg_is_set(const struct arg_values *av, int a); const char *grouped_arg_str_value(const struct arg_values *av, int a, const char *def); int32_t grouped_arg_int_value(const struct arg_values *av, int a, const int32_t def); +int arg_tag_count(int argc, char **argv); + const char *command_name(struct cmd_context *cmd); int pvmove_poll(struct cmd_context *cmd, const char *pv, unsigned background); diff --git a/tools/vgchange.c b/tools/vgchange.c index f3e7aaa5a..80d91c647 100644 --- a/tools/vgchange.c +++ b/tools/vgchange.c @@ -665,6 +665,36 @@ static int vgchange_single(struct cmd_context *cmd, const char *vg_name, return ret; } +static int dlock_vgchange(struct cmd_context *cmd, int argc, char **argv) +{ + if (!argc || arg_tag_count(argc, argv) || arg_is_set(cmd, lockstart_ARG)) { + /* + * The first two standard conditions want the current + * list of all vg names. The lockstart condition takes + * the gl to serialize with any other host that tries to + * remove the VG while this tries to start it. + */ + if (!dlock_gl(cmd, "sh", 0)) + return_ECMD_FAILED; + + } else if (arg_is_set(cmd, systemid_ARG) || + arg_is_set(cmd, uuid_ARG) || + arg_is_set(cmd, locktype_ARG)) { + /* + * VG names, uuids and system_ids are the three things that + * other hosts cache related to local vg's, so we use the + * name-change counter in the global lock to indicate that + * one of these global VG identifiers has changed so other + * hosts will update these cached values in VG's that they + * otherwise ignore (because they have foreign system_ids). + */ + if (!dlock_gl(cmd, "ex", DL_GL_UPDATE_NAMES)) + return_ECMD_FAILED; + } + + return 1; +} + int vgchange(struct cmd_context *cmd, int argc, char **argv) { int noupdate = @@ -787,6 +817,9 @@ int vgchange(struct cmd_context *cmd, int argc, char **argv) if (!update || !update_partial_unsafe) cmd->handles_missing_pvs = 1; + if (!dlock_vgchange(cmd, argc, argv)) + return_ECMD_FAILED; + return process_each_vg(cmd, argc, argv, update ? READ_FOR_UPDATE : 0, NULL, &vgchange_single); } diff --git a/tools/vgcreate.c b/tools/vgcreate.c index 5afffd857..1e9bf9629 100644 --- a/tools/vgcreate.c +++ b/tools/vgcreate.c @@ -50,6 +50,9 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv) if (!vgcreate_params_validate(cmd, &vp_new)) return EINVALID_CMD_LINE; + if (!dlock_gl_create(cmd, "ex", 0, vp_new.lock_type)) + return ECMD_FAILED; + lvmcache_seed_infos_from_lvmetad(cmd); /* Create the new VG */ diff --git a/tools/vgextend.c b/tools/vgextend.c index 716a2ceb6..4031ea026 100644 --- a/tools/vgextend.c +++ b/tools/vgextend.c @@ -156,6 +156,9 @@ int vgextend(struct cmd_context *cmd, int argc, char **argv) */ cmd->handles_missing_pvs = 1; + if (!dlock_gl(cmd, "ex", 0)) + return_ECMD_FAILED; + return process_each_vg(cmd, argc, argv, READ_FOR_UPDATE | ONLY_FIRST_NAME, &vp, restore ? &vgextend_restore : &vgextend_single); diff --git a/tools/vgmerge.c b/tools/vgmerge.c index a17a636c5..41658af9a 100644 --- a/tools/vgmerge.c +++ b/tools/vgmerge.c @@ -194,6 +194,9 @@ int vgmerge(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } + if (!dlock_gl(cmd, "ex", DL_GL_UPDATE_NAMES)) + return ECMD_FAILED; + vg_name_to = skip_dev_dir(cmd, argv[0], NULL); argc--; argv++; diff --git a/tools/vgreduce.c b/tools/vgreduce.c index 7af5a7683..95d0cca50 100644 --- a/tools/vgreduce.c +++ b/tools/vgreduce.c @@ -195,6 +195,9 @@ int vgreduce(struct cmd_context *cmd, int argc, char **argv) init_ignore_suspended_devices(1); cmd->handles_missing_pvs = 1; + if (!dlock_gl(cmd, "ex", 0)) + return_ECMD_FAILED; + vg = vg_read_for_update(cmd, vg_name, NULL, READ_ALLOW_EXPORTED); if (vg_read_error(vg) == FAILED_ALLOCATION || vg_read_error(vg) == FAILED_NOTFOUND) diff --git a/tools/vgremove.c b/tools/vgremove.c index 98336362d..6c31c9a3e 100644 --- a/tools/vgremove.c +++ b/tools/vgremove.c @@ -79,6 +79,9 @@ int vgremove(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } + if (!dlock_gl(cmd, "ex", DL_GL_UPDATE_NAMES)) + return ECMD_FAILED; + cmd->handles_missing_pvs = 1; ret = process_each_vg(cmd, argc, argv, READ_FOR_UPDATE, diff --git a/tools/vgrename.c b/tools/vgrename.c index 860ccf196..8dc413920 100644 --- a/tools/vgrename.c +++ b/tools/vgrename.c @@ -207,6 +207,9 @@ int vgrename(struct cmd_context *cmd, int argc, char **argv) return EINVALID_CMD_LINE; } + if (!dlock_gl(cmd, "ex", DL_GL_UPDATE_NAMES)) + return_ECMD_FAILED; + if (!vg_rename_path(cmd, argv[0], argv[1])) return_ECMD_FAILED; diff --git a/tools/vgscan.c b/tools/vgscan.c index bca98cc6e..f30850dc1 100644 --- a/tools/vgscan.c +++ b/tools/vgscan.c @@ -42,6 +42,9 @@ int vgscan(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } + if (!dlock_gl(cmd, "sh", 0)) + return_ECMD_FAILED; + if (cmd->filter->wipe) cmd->filter->wipe(cmd->filter); lvmcache_destroy(cmd, 1, 0); diff --git a/tools/vgsplit.c b/tools/vgsplit.c index 362f85410..339bb52aa 100644 --- a/tools/vgsplit.c +++ b/tools/vgsplit.c @@ -492,6 +492,9 @@ int vgsplit(struct cmd_context *cmd, int argc, char **argv) return ECMD_FAILED; } + if (!dlock_gl(cmd, "ex", DL_GL_UPDATE_NAMES)) + return_ECMD_FAILED; + if (arg_count(cmd, name_ARG)) lv_name = arg_value(cmd, name_ARG); else |