diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-03-07 07:32:28 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-03-07 07:32:28 +0000 |
commit | 7dc3bc7a043a0492d5a7ff9a88322ba733830337 (patch) | |
tree | d597190411bf276d0127fdb1c64ba4d4241f87a9 /qga | |
parent | eba44e9339fc13c36e24c8c59e2b73ea231b46a1 (diff) | |
parent | ec72c0e271f2b13953079a4f4dadb49ac5910b54 (diff) |
Merge remote-tracking branch 'remotes/mdroth/tags/qga-pull-2017-03-06-tag' into staging
qemu-ga patch queue for 2.9
* fix fsfreeze for filesystems mounted in multiple locations
* fix test failure when running in a chroot
* support for socket-based activation
# gpg: Signature made Mon 06 Mar 2017 07:54:17 GMT
# gpg: using RSA key 0x3353C9CEF108B584
# gpg: Good signature from "Michael Roth <flukshun@gmail.com>"
# gpg: aka "Michael Roth <mdroth@utexas.edu>"
# gpg: aka "Michael Roth <mdroth@linux.vnet.ibm.com>"
# Primary key fingerprint: CEAC C9E1 5534 EBAB B82D 3FA0 3353 C9CE F108 B584
* remotes/mdroth/tags/qga-pull-2017-03-06-tag:
tests: check path to avoid a failing qga/get-vcpus test
qga: ignore EBUSY when freezing a filesystem
qga: add systemd socket activation support
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'qga')
-rw-r--r-- | qga/channel-posix.c | 68 | ||||
-rw-r--r-- | qga/channel-win32.c | 2 | ||||
-rw-r--r-- | qga/channel.h | 3 | ||||
-rw-r--r-- | qga/commands-posix.c | 5 | ||||
-rw-r--r-- | qga/main.c | 74 |
5 files changed, 114 insertions, 38 deletions
diff --git a/qga/channel-posix.c b/qga/channel-posix.c index 71582e0c38..3f34465159 100644 --- a/qga/channel-posix.c +++ b/qga/channel-posix.c @@ -118,14 +118,16 @@ static int ga_channel_client_add(GAChannel *c, int fd) return 0; } -static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod method) +static gboolean ga_channel_open(GAChannel *c, const gchar *path, + GAChannelMethod method, int fd) { int ret; c->method = method; switch (c->method) { case GA_CHANNEL_VIRTIO_SERIAL: { - int fd = qemu_open(path, O_RDWR | O_NONBLOCK + assert(fd < 0); + fd = qemu_open(path, O_RDWR | O_NONBLOCK #ifndef CONFIG_SOLARIS | O_ASYNC #endif @@ -153,7 +155,9 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod } case GA_CHANNEL_ISA_SERIAL: { struct termios tio; - int fd = qemu_open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); + + assert(fd < 0); + fd = qemu_open(path, O_RDWR | O_NOCTTY | O_NONBLOCK); if (fd == -1) { g_critical("error opening channel: %s", strerror(errno)); return false; @@ -183,37 +187,41 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod break; } case GA_CHANNEL_UNIX_LISTEN: { - Error *local_err = NULL; - int fd = unix_listen(path, NULL, strlen(path), &local_err); - if (local_err != NULL) { - g_critical("%s", error_get_pretty(local_err)); - error_free(local_err); - return false; + if (fd < 0) { + Error *local_err = NULL; + + fd = unix_listen(path, NULL, strlen(path), &local_err); + if (local_err != NULL) { + g_critical("%s", error_get_pretty(local_err)); + error_free(local_err); + return false; + } } ga_channel_listen_add(c, fd, true); break; } case GA_CHANNEL_VSOCK_LISTEN: { - Error *local_err = NULL; - SocketAddress *addr; - char *addr_str; - int fd; - - addr_str = g_strdup_printf("vsock:%s", path); - addr = socket_parse(addr_str, &local_err); - g_free(addr_str); - if (local_err != NULL) { - g_critical("%s", error_get_pretty(local_err)); - error_free(local_err); - return false; - } + if (fd < 0) { + Error *local_err = NULL; + SocketAddress *addr; + char *addr_str; - fd = socket_listen(addr, &local_err); - qapi_free_SocketAddress(addr); - if (local_err != NULL) { - g_critical("%s", error_get_pretty(local_err)); - error_free(local_err); - return false; + addr_str = g_strdup_printf("vsock:%s", path); + addr = socket_parse(addr_str, &local_err); + g_free(addr_str); + if (local_err != NULL) { + g_critical("%s", error_get_pretty(local_err)); + error_free(local_err); + return false; + } + + fd = socket_listen(addr, &local_err); + qapi_free_SocketAddress(addr); + if (local_err != NULL) { + g_critical("%s", error_get_pretty(local_err)); + error_free(local_err); + return false; + } } ga_channel_listen_add(c, fd, true); break; @@ -262,13 +270,13 @@ GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count) } GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, - GAChannelCallback cb, gpointer opaque) + int listen_fd, GAChannelCallback cb, gpointer opaque) { GAChannel *c = g_new0(GAChannel, 1); c->event_cb = cb; c->user_data = opaque; - if (!ga_channel_open(c, path, method)) { + if (!ga_channel_open(c, path, method, listen_fd)) { g_critical("error opening channel"); ga_channel_free(c); return NULL; diff --git a/qga/channel-win32.c b/qga/channel-win32.c index 21f9deedf6..7e6dc4d26f 100644 --- a/qga/channel-win32.c +++ b/qga/channel-win32.c @@ -316,7 +316,7 @@ static gboolean ga_channel_open(GAChannel *c, GAChannelMethod method, } GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, - GAChannelCallback cb, gpointer opaque) + int listen_fd, GAChannelCallback cb, gpointer opaque) { GAChannel *c = g_new0(GAChannel, 1); SECURITY_ATTRIBUTES sec_attrs; diff --git a/qga/channel.h b/qga/channel.h index 8fd0c8f72c..1778416115 100644 --- a/qga/channel.h +++ b/qga/channel.h @@ -25,7 +25,8 @@ typedef enum { typedef gboolean (*GAChannelCallback)(GIOCondition condition, gpointer opaque); GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path, - GAChannelCallback cb, gpointer opaque); + int listen_fd, GAChannelCallback cb, + gpointer opaque); void ga_channel_free(GAChannel *c); GIOStatus ga_channel_read(GAChannel *c, gchar *buf, gsize size, gsize *count); GIOStatus ga_channel_write_all(GAChannel *c, const gchar *buf, gsize size); diff --git a/qga/commands-posix.c b/qga/commands-posix.c index ea37c097cf..73d93eb5ce 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -1243,6 +1243,9 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints, * filesystems may not implement fsfreeze for less obvious reasons. * these will report EOPNOTSUPP. we simply ignore these when tallying * the number of frozen filesystems. + * if a filesystem is mounted more than once (aka bind mount) a + * consecutive attempt to freeze an already frozen filesystem will + * return EBUSY. * * any other error means a failure to freeze a filesystem we * expect to be freezable, so return an error in those cases @@ -1250,7 +1253,7 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints, */ ret = ioctl(fd, FIFREEZE); if (ret == -1) { - if (errno != EOPNOTSUPP) { + if (errno != EOPNOTSUPP && errno != EBUSY) { error_setg_errno(errp, errno, "failed to freeze %s", mount->dirname); close(fd); diff --git a/qga/main.c b/qga/main.c index 9435bc74b8..92658bc0e2 100644 --- a/qga/main.c +++ b/qga/main.c @@ -28,6 +28,7 @@ #include "qga/channel.h" #include "qemu/bswap.h" #include "qemu/help_option.h" +#include "qemu/sockets.h" #ifdef _WIN32 #include "qga/service-win32.h" #include "qga/vss-win32.h" @@ -185,6 +186,37 @@ void reopen_fd_to_null(int fd) } #endif +/** + * get_listen_fd: + * @consume: true to prevent future calls from succeeding + * + * Fetch a listen file descriptor that was passed via systemd socket + * activation. Use @consume to prevent child processes from thinking a file + * descriptor was passed. + * + * Returns: file descriptor or -1 if no fd was passed + */ +static int get_listen_fd(bool consume) +{ +#ifdef _WIN32 + return -1; /* no fd passing expected, unsetenv(3) not available */ +#else + const char *listen_fds = getenv("LISTEN_FDS"); + int fd = STDERR_FILENO + 1; + + if (!listen_fds || strcmp(listen_fds, "1") != 0) { + return -1; + } + + if (consume) { + unsetenv("LISTEN_FDS"); + } + + qemu_set_cloexec(fd); + return fd; +#endif /* !_WIN32 */ +} + static void usage(const char *cmd) { printf( @@ -649,7 +681,8 @@ static gboolean channel_event_cb(GIOCondition condition, gpointer data) return true; } -static gboolean channel_init(GAState *s, const gchar *method, const gchar *path) +static gboolean channel_init(GAState *s, const gchar *method, const gchar *path, + int listen_fd) { GAChannelMethod channel_method; @@ -667,7 +700,8 @@ static gboolean channel_init(GAState *s, const gchar *method, const gchar *path) return false; } - s->channel = ga_channel_new(channel_method, path, channel_event_cb, s); + s->channel = ga_channel_new(channel_method, path, listen_fd, + channel_event_cb, s); if (!s->channel) { g_critical("failed to create guest agent channel"); return false; @@ -1026,7 +1060,9 @@ static void config_dump(GAConfig *config) g_key_file_set_boolean(keyfile, "general", "daemon", config->daemonize); g_key_file_set_string(keyfile, "general", "method", config->method); - g_key_file_set_string(keyfile, "general", "path", config->channel_path); + if (config->channel_path) { + g_key_file_set_string(keyfile, "general", "path", config->channel_path); + } if (config->log_filepath) { g_key_file_set_string(keyfile, "general", "logfile", config->log_filepath); @@ -1295,7 +1331,9 @@ static int run_agent(GAState *s, GAConfig *config) #endif s->main_loop = g_main_loop_new(NULL, false); - if (!channel_init(ga_state, config->method, config->channel_path)) { + + if (!channel_init(ga_state, config->method, config->channel_path, + get_listen_fd(true))) { g_critical("failed to initialize guest agent channel"); return EXIT_FAILURE; } @@ -1319,6 +1357,7 @@ int main(int argc, char **argv) int ret = EXIT_SUCCESS; GAState *s = g_new0(GAState, 1); GAConfig *config = g_new0(GAConfig, 1); + int listen_fd; config->log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL; @@ -1340,7 +1379,32 @@ int main(int argc, char **argv) config->method = g_strdup("virtio-serial"); } - if (config->channel_path == NULL) { + listen_fd = get_listen_fd(false); + if (listen_fd >= 0) { + SocketAddress *addr; + + g_free(config->method); + g_free(config->channel_path); + config->method = NULL; + config->channel_path = NULL; + + addr = socket_local_address(listen_fd, NULL); + if (addr) { + if (addr->type == SOCKET_ADDRESS_KIND_UNIX) { + config->method = g_strdup("unix-listen"); + } else if (addr->type == SOCKET_ADDRESS_KIND_VSOCK) { + config->method = g_strdup("vsock-listen"); + } + + qapi_free_SocketAddress(addr); + } + + if (!config->method) { + g_critical("unsupported listen fd type"); + ret = EXIT_FAILURE; + goto end; + } + } else if (config->channel_path == NULL) { if (strcmp(config->method, "virtio-serial") == 0) { /* try the default path for the virtio-serial port */ config->channel_path = g_strdup(QGA_VIRTIO_PATH_DEFAULT); |