summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--daemons/lvmetad/lvmetad-core.c7
-rw-r--r--lib/cache/lvmetad.c62
-rw-r--r--lib/cache/lvmetad.h2
-rw-r--r--tools/commands.h2
-rw-r--r--tools/lvmcmdline.c24
-rw-r--r--tools/pvscan.c15
-rw-r--r--tools/tools.h2
7 files changed, 103 insertions, 11 deletions
diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
index e14795699..848b10d35 100644
--- a/daemons/lvmetad/lvmetad-core.c
+++ b/daemons/lvmetad/lvmetad-core.c
@@ -2479,9 +2479,10 @@ static response set_global_info(lvmetad_state *s, request r)
static response get_global_info(lvmetad_state *s, request r)
{
- return daemon_reply_simple("OK", "global_invalid = %d",
- (s->flags & GLFL_INVALID) ? 1 : 0,
- NULL);
+ return daemon_reply_simple("OK",
+ "global_invalid = %d", (s->flags & GLFL_INVALID) ? 1 : 0,
+ "token = %s", s->token[0] ? s->token : "none",
+ NULL);
}
static response set_vg_info(lvmetad_state *s, request r)
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
index 090f0d722..090bd7544 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -206,6 +206,54 @@ void lvmetad_set_socket(const char *sock)
_lvmetad_socket = sock;
}
+int lvmetad_token_matches(struct cmd_context *cmd)
+{
+ daemon_reply reply;
+ const char *daemon_token;
+ int ret = 1;
+
+ reply = daemon_send_simple(_lvmetad, "get_global_info",
+ "token = %s", "skip",
+ NULL);
+ if (reply.error) {
+ log_error("lvmetad_token_matches get_global_info error %d", reply.error);
+ ret = 0;
+ goto out;
+ }
+
+ if (strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+ log_error("lvmetad_token_matches get_global_info not ok");
+ ret = 0;
+ goto out;
+ }
+
+ daemon_token = daemon_reply_str(reply, "token", NULL);
+
+ if (!daemon_token) {
+ log_error("lvmetad_token_matches no token returned");
+ ret = 0;
+ goto out;
+ }
+
+ if (!strcmp(daemon_token, "none")) {
+ /* lvmetad is not yet populated */
+ ret = 0;
+ goto out;
+ }
+
+ if (strcmp(daemon_token, _lvmetad_token)) {
+ /*
+ * lvmetad has an unmatching token; it was last populated
+ * using a different global filter.
+ */
+ ret = 0;
+ goto out;
+ }
+out:
+ daemon_reply_destroy(reply);
+ return ret;
+}
+
static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler handler,
int ignore_obsolete);
@@ -246,6 +294,13 @@ retry:
* we re-scan immediately, but if we lose the potential race for
* the update, we back off for a short while (0.05-0.5 seconds) and
* try again.
+ *
+ * FIXME: remove the retry/pvscan and just fail the command.
+ * Running pvscan here is likely to mess up the state of
+ * the original command. This should be very unlikely
+ * since the token is verified to match at the start
+ * of the command now. Also there's no recursion check to
+ * prevent _lvmetad_pvscan_all_devs->lvmetad_send->_lvmetad_pvscan_all_devs...
*/
if (!repl.error && !strcmp(daemon_reply_str(repl, "response", ""), "token_mismatch") &&
num_rescans < MAX_RESCANS && total_usecs_waited < (SCAN_TIMEOUT_SECONDS * 1000000) && !test_mode()) {
@@ -1744,7 +1799,12 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
/*
* Update the local lvmetad cache so it correctly reflects any
- * changes made on remote hosts.
+ * changes made on remote hosts. (It's possible that this command
+ * already refreshed the local lvmetad because of a token change,
+ * but we need to do it again here since we now hold the global
+ * lock. Another host may have changed things between the time
+ * we rescanned for the token, and the time we acquired the global
+ * lock.)
*/
lvmetad_pvscan_all_devs(cmd, NULL);
diff --git a/lib/cache/lvmetad.h b/lib/cache/lvmetad.h
index af0d562fe..1c94308df 100644
--- a/lib/cache/lvmetad.h
+++ b/lib/cache/lvmetad.h
@@ -168,6 +168,7 @@ int lvmetad_pvscan_foreign_vgs(struct cmd_context *cmd, activation_handler handl
int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg);
void lvmetad_validate_global_cache(struct cmd_context *cmd, int force);
+int lvmetad_token_matches(struct cmd_context *cmd);
# else /* LVMETAD_SUPPORT */
@@ -197,6 +198,7 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force);
# define lvmetad_pvscan_foreign_vgs(cmd, handler) (0)
# define lvmetad_vg_clear_outdated_pvs(vg) (1)
# define lvmetad_validate_global_cache(cmd, force) do { } while (0)
+# define lvmetad_token_matches(cmd) (1)
# endif /* LVMETAD_SUPPORT */
diff --git a/tools/commands.h b/tools/commands.h
index 92d13fdf0..fb41d9e4c 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -962,7 +962,7 @@ xx(pvs,
xx(pvscan,
"List all physical volumes",
- PERMITTED_READ_ONLY | LOCKD_VG_SH,
+ PERMITTED_READ_ONLY | LOCKD_VG_SH | SKIP_AUTO_PVSCAN,
"pvscan\n"
"\t[-b|--background]\n"
"\t[--cache [-a|--activate ay] [ DevicePath | -j|--major major --minor minor]...]\n"
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 657797765..858b0360f 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -1640,13 +1640,25 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
}
/*
- * Other hosts might have changed foreign VGs so enforce a rescan
- * before processing any command using them.
+ * The lvmetad cache may need to be repopulated before we use it because:
+ * - We are reading foreign VGs which others hosts may have changed
+ * which our lvmetad would not have seen.
+ * - lvmetad may have just been started and no command has been run
+ * to populate it yet (e.g. no pvscan --cache was run).
+ * - Another local command may have run with a different global filter
+ * which changed the content of lvmetad from what we want (recognized
+ * by differnet token values.)
+ *
+ * The pvscan command does rescanning and lvmetad upates itself,
+ * so it doesn't want this automatic rescanning.
*/
- if (cmd->include_foreign_vgs && lvmetad_used() &&
- !lvmetad_pvscan_foreign_vgs(cmd, NULL)) {
- log_error("Failed to scan devices.");
- return ECMD_FAILED;
+ if (lvmetad_active() && !(cmd->command->flags & SKIP_AUTO_PVSCAN)) {
+ if (!lvmetad_token_matches(cmd) || cmd->include_foreign_vgs) {
+ if (!lvmetad_pvscan_all_devs(cmd, NULL)) {
+ log_error("Failed to scan devices");
+ return ECMD_FAILED;
+ }
+ }
}
/*
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 10bf28e52..7ea83f225 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -387,6 +387,21 @@ int pvscan(struct cmd_context *cmd, int argc, char **argv)
arg_count(cmd, exported_ARG) ?
"of exported volume group(s)" : "in no volume group");
+ /*
+ * All pvscan commands skip the automatic repopulating of
+ * lvmetad when the token doesn't match, because pvscan_lvmetad
+ * above (for pvscan --cache) needs to do that repopulating
+ * itself. So for other pvscan commands (without --cache), we
+ * need to check the lvmetad token and repopulate the cache
+ * if it doesn't match.
+ */
+ if (lvmetad_active() && !lvmetad_token_matches(cmd)) {
+ if (!lvmetad_pvscan_all_devs(cmd, NULL)) {
+ log_error("Failed to scan devices");
+ return ECMD_FAILED;
+ }
+ }
+
if (!lock_vol(cmd, VG_GLOBAL, LCK_VG_WRITE, NULL)) {
log_error("Unable to obtain global lock.");
return ECMD_FAILED;
diff --git a/tools/tools.h b/tools/tools.h
index 4ed893fc4..793a871ac 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -105,6 +105,8 @@ struct arg_value_group_list {
#define LOCKD_VG_SH 0x00000020
/* Command does not process any metadata. */
#define NO_METADATA_PROCESSING 0x00000040
+/* Don't refresh lvmetad cache automatically, let command do it. */
+#define SKIP_AUTO_PVSCAN 0x00000080
/* a register of the lvm commands */
struct command {