[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PULL v3 21/24] qga: add --retry-path option for re-initial
From: |
Michael Roth |
Subject: |
[Qemu-devel] [PULL v3 21/24] qga: add --retry-path option for re-initializing channel on failure |
Date: |
Wed, 31 Oct 2018 09:19:22 -0500 |
This adds an option to instruct the agent to periodically attempt
re-opening the communication channel after a channel error has
occurred. The main use-case for this is providing an OS-independent
way of allowing the agent to survive situations like hotplug/unplug of
the communication channel, or initial guest set up where the agent may
be installed/started prior to the installation of the channel device's
driver.
There are nicer ways of implementing this functionality via things
like systemd services, but this option is useful for platforms like
*BSD/w32.
Currently a channel error will result in the GSource for that channel
being removed from the GMainLoop, but the main loop continuing to run.
That behavior results in a dead loop when --retry-path isn't set, and
prevents us from knowing when to attempt re-opening the channel when
it is set, so we also force the loop to exit as part of this patch.
Signed-off-by: Michael Roth <address@hidden>
---
qga/main.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 54 insertions(+), 8 deletions(-)
diff --git a/qga/main.c b/qga/main.c
index 761007deb4..506a314140 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -58,6 +58,7 @@
#endif
#define QGA_SENTINEL_BYTE 0xFF
#define QGA_CONF_DEFAULT CONFIG_QEMU_CONFDIR G_DIR_SEPARATOR_S "qemu-ga.conf"
+#define QGA_RETRY_INTERVAL 5
static struct {
const char *state_dir;
@@ -98,6 +99,7 @@ struct GAState {
GAPersistentState pstate;
GAConfig *config;
int socket_activation;
+ bool force_exit;
};
struct GAState *ga_state;
@@ -120,6 +122,7 @@ DWORD WINAPI service_ctrl_handler(DWORD ctrl, DWORD type,
LPVOID data,
VOID WINAPI service_main(DWORD argc, TCHAR *argv[]);
#endif
static int run_agent(GAState *s);
+static void stop_agent(GAState *s, bool requested);
static void
init_dfl_pathnames(void)
@@ -168,9 +171,7 @@ static void quit_handler(int sig)
}
g_debug("received signal num %d, quitting", sig);
- if (g_main_loop_is_running(ga_state->main_loop)) {
- g_main_loop_quit(ga_state->main_loop);
- }
+ stop_agent(ga_state, true);
}
#ifndef _WIN32
@@ -255,6 +256,10 @@ QEMU_COPYRIGHT "\n"
" to list available RPCs)\n"
" -D, --dump-conf dump a qemu-ga config file based on current config\n"
" options / command-line parameters to stdout\n"
+" -r, --retry-path attempt re-opening path if it's unavailable or closed\n"
+" due to an error which may be recoverable in the future\n"
+" (virtio-serial driver re-install, serial device hot\n"
+" plug/unplug, etc.)\n"
" -h, --help display this help and exit\n"
"\n"
QEMU_HELP_BOTTOM "\n"
@@ -614,6 +619,7 @@ static gboolean channel_event_cb(GIOCondition condition,
gpointer data)
switch (status) {
case G_IO_STATUS_ERROR:
g_warning("error reading channel");
+ stop_agent(s, false);
return false;
case G_IO_STATUS_NORMAL:
buf[count] = 0;
@@ -927,6 +933,7 @@ struct GAConfig {
int daemonize;
GLogLevelFlags log_level;
int dumpconf;
+ bool retry_path;
};
static void config_load(GAConfig *config)
@@ -976,6 +983,10 @@ static void config_load(GAConfig *config)
/* enable all log levels */
config->log_level = G_LOG_LEVEL_MASK;
}
+ if (g_key_file_has_key(keyfile, "general", "retry-path", NULL)) {
+ config->retry_path =
+ g_key_file_get_boolean(keyfile, "general", "retry-path", &gerr);
+ }
if (g_key_file_has_key(keyfile, "general", "blacklist", NULL)) {
config->bliststr =
g_key_file_get_string(keyfile, "general", "blacklist", &gerr);
@@ -1037,6 +1048,8 @@ static void config_dump(GAConfig *config)
g_key_file_set_string(keyfile, "general", "statedir", config->state_dir);
g_key_file_set_boolean(keyfile, "general", "verbose",
config->log_level == G_LOG_LEVEL_MASK);
+ g_key_file_set_boolean(keyfile, "general", "retry-path",
+ config->retry_path);
tmp = list_join(config->blacklist, ',');
g_key_file_set_string(keyfile, "general", "blacklist", tmp);
g_free(tmp);
@@ -1055,7 +1068,7 @@ static void config_dump(GAConfig *config)
static void config_parse(GAConfig *config, int argc, char **argv)
{
- const char *sopt = "hVvdm:p:l:f:F::b:s:t:D";
+ const char *sopt = "hVvdm:p:l:f:F::b:s:t:Dr";
int opt_ind = 0, ch;
const struct option lopt[] = {
{ "help", 0, NULL, 'h' },
@@ -1075,6 +1088,7 @@ static void config_parse(GAConfig *config, int argc, char
**argv)
{ "service", 1, NULL, 's' },
#endif
{ "statedir", 1, NULL, 't' },
+ { "retry-path", 0, NULL, 'r' },
{ NULL, 0, NULL, 0 }
};
@@ -1119,6 +1133,9 @@ static void config_parse(GAConfig *config, int argc, char
**argv)
case 'D':
config->dumpconf = 1;
break;
+ case 'r':
+ config->retry_path = true;
+ break;
case 'b': {
if (is_help_option(optarg)) {
qmp_for_each_command(&ga_commands, ga_print_cmd, NULL);
@@ -1322,9 +1339,6 @@ static void cleanup_agent(GAState *s)
ga_command_state_free(s->command_state);
json_message_parser_destroy(&s->parser);
}
- if (s->channel) {
- ga_channel_free(s->channel);
- }
g_free(s->pstate_filepath);
g_free(s->state_filepath_isfrozen);
if (s->main_loop) {
@@ -1334,7 +1348,7 @@ static void cleanup_agent(GAState *s)
ga_state = NULL;
}
-static int run_agent(GAState *s)
+static int run_agent_once(GAState *s)
{
if (!channel_init(s, s->config->method, s->config->channel_path,
s->socket_activation ? FIRST_SOCKET_ACTIVATION_FD : -1))
{
@@ -1344,9 +1358,41 @@ static int run_agent(GAState *s)
g_main_loop_run(ga_state->main_loop);
+ if (s->channel) {
+ ga_channel_free(s->channel);
+ }
+
return EXIT_SUCCESS;
}
+static int run_agent(GAState *s)
+{
+ int ret = EXIT_SUCCESS;
+
+ s->force_exit = false;
+
+ do {
+ ret = run_agent_once(s);
+ if (s->config->retry_path && !s->force_exit) {
+ g_warning("agent stopped unexpectedly, restarting...");
+ sleep(QGA_RETRY_INTERVAL);
+ }
+ } while (s->config->retry_path && !s->force_exit);
+
+ return ret;
+}
+
+static void stop_agent(GAState *s, bool requested)
+{
+ if (!s->force_exit) {
+ s->force_exit = requested;
+ }
+
+ if (g_main_loop_is_running(s->main_loop)) {
+ g_main_loop_quit(s->main_loop);
+ }
+}
+
int main(int argc, char **argv)
{
int ret = EXIT_SUCCESS;
--
2.17.1
- [Qemu-devel] [PULL v3 16/24] qga-win: demystify namespace stripping, (continued)
- [Qemu-devel] [PULL v3 16/24] qga-win: demystify namespace stripping, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 18/24] qga: group agent init/cleanup init separate routines, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 12/24] qga-win: report disk serial number, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 14/24] qga-win: handle multi-disk volumes, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 20/24] qga: move w32 service handling out of run_agent(), Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 09/24] build: rename CONFIG_QGA_NTDDDISK to CONFIG_QGA_NTDDSCSI, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 19/24] qga: hang GAConfig/socket_activation off of GAState global, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 17/24] qga: fix an off-by-one issue, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 10/24] qga-win: add debugging information, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 01/24] qga: Support Unicode paths in guest-file-open on win32, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 21/24] qga: add --retry-path option for re-initializing channel on failure,
Michael Roth <=
- [Qemu-devel] [PULL v3 22/24] qga-win: install service with --retry-path set by default, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 24/24] qga-win: changing --retry-path option behavior, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 23/24] qga-win: report specific error when failing to open channel, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 02/24] qga-win: add support for qmp_guest_fsfreeze_freeze_list, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 03/24] qga: ignore non present cpus when handling qmp_guest_get_vcpus(), Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 08/24] qga-win: fsinfo: pci-info: allow partial info, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 07/24] qga-win: prevent crash when executing fsinfo command, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 04/24] configure: add test for libudev, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 05/24] qga: linux: report disk serial number, Michael Roth, 2018/10/31
- [Qemu-devel] [PULL v3 06/24] qga: linux: return disk device in guest-get-fsinfo, Michael Roth, 2018/10/31