diff options
-rw-r--r-- | daemons/lvmetad/lvmetad-core.c | 7 | ||||
-rw-r--r-- | lib/cache/lvmetad.c | 62 | ||||
-rw-r--r-- | lib/cache/lvmetad.h | 2 | ||||
-rw-r--r-- | tools/commands.h | 2 | ||||
-rw-r--r-- | tools/lvmcmdline.c | 24 | ||||
-rw-r--r-- | tools/pvscan.c | 15 | ||||
-rw-r--r-- | tools/tools.h | 2 |
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 { |