summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2015-10-15 17:13:28 -0500
committerDavid Teigland <teigland@redhat.com>2015-10-20 17:02:11 -0500
commit3822887780cbc5374387da05abb569d2cc4265e1 (patch)
tree8ec8ab4bb46a48c8631fa92fa180d256b299d4a6
parent937a3b1387ee365d589b973f481f8ba8de72084a (diff)
downloadlvm2-dev-dct-lvmetad5.tar.gz
lvmetad: refresh content at command startdev-dct-lvmetad5
At the start of the command, check if the lvmetad content needs updating (token not matching), and if so do the scan and update it. This gets the updating done right at the beginning, before command processing is started. The early scan already exists for the foreign VGs case, so this is added to it. Previously, the command would be part way through its own processing before discovering via lvmetad_send that lvmetad needed updating. It's not good to interrupt a command, insert a 'pvscan --cache', then continue on with the original command. The pvscan is likely to interfere with the original command.
-rw-r--r--daemons/lvmetad/lvmetad-core.c7
-rw-r--r--lib/cache/lvmetad.c89
-rw-r--r--lib/cache/lvmetad.h2
-rw-r--r--tools/commands.h2
-rw-r--r--tools/lvmcmdline.c24
-rw-r--r--tools/pvscan.c22
-rw-r--r--tools/tools.h2
7 files changed, 134 insertions, 14 deletions
diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
index 23a0c5a6b..84b0c6ca0 100644
--- a/daemons/lvmetad/lvmetad-core.c
+++ b/daemons/lvmetad/lvmetad-core.c
@@ -2506,9 +2506,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..4bb3df4fc 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -206,6 +206,56 @@ 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;
+
+ log_debug_lvmetad("lvmetad send get_global_info");
+
+ 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);
@@ -219,6 +269,8 @@ static daemon_reply _lvmetad_send(const char *id, ...)
unsigned max_remaining_sleep_times = 1;
unsigned wait_usecs;
+ log_debug_lvmetad("lvmetad_send %s", id);
+
retry:
req = daemon_request_make(id);
@@ -246,26 +298,44 @@ 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 rescanning 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()) {
- if (!strcmp(daemon_reply_str(repl, "expected", ""), "update in progress") ||
- max_remaining_sleep_times) {
+
+ /*
+ * The other command should finish updating lvmetad soon.
+ * Sleep to give it a chance to finish, then retry.
+ */
+ if (!strcmp(daemon_reply_str(repl, "expected", ""), "update in progress") || max_remaining_sleep_times) {
+ log_debug_lvmetad("lvmetad is not ready, retrying...");
wait_usecs = 50000 + lvm_even_rand(&_lvmetad_cmd->rand_seed, 450000); /* between 0.05s and 0.5s */
(void) usleep(wait_usecs);
total_usecs_waited += wait_usecs;
if (max_remaining_sleep_times)
max_remaining_sleep_times--; /* Sleep once before rescanning the first time, then 5 times each time after that. */
} else {
+ log_error("lvmetad cache is not usable, update lvmetad and retry command.");
+ goto out;
+ }
+#if 0
+ else {
/* If the re-scan fails here, we try again later. */
(void) _lvmetad_pvscan_all_devs(_lvmetad_cmd, NULL, 0);
num_rescans++;
max_remaining_sleep_times = 5;
}
+#endif
daemon_reply_destroy(repl);
goto retry;
}
-
+out:
return repl;
}
@@ -1396,6 +1466,8 @@ static int _lvmetad_pvscan_all_devs(struct cmd_context *cmd, activation_handler
return 0;
}
+ log_debug_lvmetad("Scanning all devices to update lvmetad.");
+
if (!(iter = dev_iter_create(cmd->lvmetad_filter, 1))) {
log_error("dev_iter creation failed");
return 0;
@@ -1712,6 +1784,8 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
if (force)
goto do_scan;
+ log_debug_lvmetad("lvmetad validate send get_global_info");
+
reply = daemon_send_simple(_lvmetad, "get_global_info",
"token = %s", "skip",
NULL);
@@ -1744,7 +1818,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);
@@ -1754,6 +1833,8 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
* from lvmetad will not see global_invalid until
* another host makes another global change.
*/
+ log_debug_lvmetad("lvmetad validate send set_global_info");
+
reply = daemon_send_simple(_lvmetad, "set_global_info",
"token = %s", "skip",
"global_invalid = %d", 0,
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..fbdfd71b8 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -264,6 +264,13 @@ static int _pvscan_lvmetad(struct cmd_context *cmd, int argc, char **argv)
goto out;
}
+ /*
+ * FIXME: when specific devs are named, we generally don't
+ * want to scan any other devs. But, should we check if
+ * lvmetad token is blank or unmatching and in that case
+ * scan all devs even when devs are named?
+ */
+
log_verbose("Using physical volume(s) on command line");
/* Process any command line PVs first. */
@@ -387,6 +394,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 {