Commit 7dc3bc7a authored by Peter Maydell's avatar Peter Maydell
Browse files

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: default avatarPeter Maydell <peter.maydell@linaro.org>
parents eba44e93 ec72c0e2
Loading
Loading
Loading
Loading
+38 −30
Original line number Diff line number Diff line
@@ -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,21 +187,24 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod
        break;
    }
    case GA_CHANNEL_UNIX_LISTEN: {
        if (fd < 0) {
            Error *local_err = NULL;
        int fd = unix_listen(path, NULL, strlen(path), &local_err);

            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: {
        if (fd < 0) {
            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);
@@ -215,6 +222,7 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod
                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;
+1 −1
Original line number Diff line number Diff line
@@ -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;
+2 −1
Original line number Diff line number Diff line
@@ -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);
+4 −1
Original line number Diff line number Diff line
@@ -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);
+69 −5
Original line number Diff line number Diff line
@@ -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);
    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);
Loading