Commit 38ab3596 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/mdroth/tags/qga-pull-2016-10-31-tag' into staging



qemu-ga patch queue for 2.8

* add guest-fstrim support for w32
* add support for using virtio-vsock as the communication channel

# gpg: Signature made Tue 01 Nov 2016 00:55:40 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-2016-10-31-tag:
  qga: add vsock-listen method
  sockets: add AF_VSOCK support
  qga: drop unnecessary GA_CHANNEL_UNIX_LISTEN checks
  qga: drop unused sockaddr in accept(2) call
  qga: minimal support for fstrim for Windows guests

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents bf99fd39 586ef5de
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -4674,6 +4674,33 @@ if compile_prog "" "" ; then
    have_rtnetlink=yes
fi

##########################################
# check for usable AF_VSOCK environment
have_af_vsock=no
cat > $TMPC << EOF
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#if !defined(AF_VSOCK)
# error missing AF_VSOCK flag
#endif
#include <linux/vm_sockets.h>
int main(void) {
    int sock, ret;
    struct sockaddr_vm svm;
    socklen_t len = sizeof(svm);
    sock = socket(AF_VSOCK, SOCK_STREAM, 0);
    ret = getpeername(sock, (struct sockaddr *)&svm, &len);
    if ((ret == -1) && (errno == ENOTCONN)) {
        return 0;
    }
    return -1;
}
EOF
if compile_prog "" "" ; then
    have_af_vsock=yes
fi

#################################################
# Sparc implicitly links with --relax, which is
# incompatible with -r, so --no-relax should be
@@ -5662,6 +5689,10 @@ if test "$replication" = "yes" ; then
  echo "CONFIG_REPLICATION=y" >> $config_host_mak
fi

if test "$have_af_vsock" = "yes" ; then
  echo "CONFIG_AF_VSOCK=y" >> $config_host_mak
fi

# Hold two types of flag:
#   CONFIG_THREAD_SETNAME_BYTHREAD  - we've got a way of setting the name on
#                                     a thread we have a handle to
+22 −1
Original line number Diff line number Diff line
@@ -1063,12 +1063,14 @@
#
# @unix: unix socket
#
# @vsock: vsock family (since 2.8)
#
# @unknown: otherwise
#
# Since: 2.1
##
{ 'enum': 'NetworkAddressFamily',
  'data': [ 'ipv4', 'ipv6', 'unix', 'unknown' ] }
  'data': [ 'ipv4', 'ipv6', 'unix', 'vsock', 'unknown' ] }

##
# @VncBasicInfo
@@ -3094,6 +3096,24 @@
  'data': {
    'path': 'str' } }

##
# @VsockSocketAddress
#
# Captures a socket address in the vsock namespace.
#
# @cid: unique host identifier
# @port: port
#
# Note that string types are used to allow for possible future hostname or
# service resolution support.
#
# Since 2.8
##
{ 'struct': 'VsockSocketAddress',
  'data': {
    'cid': 'str',
    'port': 'str' } }

##
# @SocketAddress
#
@@ -3105,6 +3125,7 @@
  'data': {
    'inet': 'InetSocketAddress',
    'unix': 'UnixSocketAddress',
    'vsock': 'VsockSocketAddress',
    'fd': 'String' } }

##
+28 −8
Original line number Diff line number Diff line
@@ -26,13 +26,10 @@ static gboolean ga_channel_listen_accept(GIOChannel *channel,
    GAChannel *c = data;
    int ret, client_fd;
    bool accepted = false;
    struct sockaddr_un addr;
    socklen_t addrlen = sizeof(addr);

    g_assert(channel != NULL);

    client_fd = qemu_accept(g_io_channel_unix_get_fd(channel),
                            (struct sockaddr *)&addr, &addrlen);
    client_fd = qemu_accept(g_io_channel_unix_get_fd(channel), NULL, NULL);
    if (client_fd == -1) {
        g_warning("error converting fd to gsocket: %s", strerror(errno));
        goto out;
@@ -64,7 +61,6 @@ static void ga_channel_listen_add(GAChannel *c, int listen_fd, bool create)

static void ga_channel_listen_close(GAChannel *c)
{
    g_assert(c->method == GA_CHANNEL_UNIX_LISTEN);
    g_assert(c->listen_channel);
    g_io_channel_shutdown(c->listen_channel, true, NULL);
    g_io_channel_unref(c->listen_channel);
@@ -80,7 +76,7 @@ static void ga_channel_client_close(GAChannel *c)
    g_io_channel_shutdown(c->client_channel, true, NULL);
    g_io_channel_unref(c->client_channel);
    c->client_channel = NULL;
    if (c->method == GA_CHANNEL_UNIX_LISTEN && c->listen_channel) {
    if (c->listen_channel) {
        ga_channel_listen_add(c, 0, false);
    }
}
@@ -197,6 +193,31 @@ static gboolean ga_channel_open(GAChannel *c, const gchar *path, GAChannelMethod
        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;
        }

        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;
    }
    default:
        g_critical("error binding/listening to specified socket");
        return false;
@@ -258,8 +279,7 @@ GAChannel *ga_channel_new(GAChannelMethod method, const gchar *path,

void ga_channel_free(GAChannel *c)
{
    if (c->method == GA_CHANNEL_UNIX_LISTEN
        && c->listen_channel) {
    if (c->listen_channel) {
        ga_channel_listen_close(c);
    }
    if (c->client_channel) {
+1 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ typedef enum {
    GA_CHANNEL_VIRTIO_SERIAL,
    GA_CHANNEL_ISA_SERIAL,
    GA_CHANNEL_UNIX_LISTEN,
    GA_CHANNEL_VSOCK_LISTEN,
} GAChannelMethod;

typedef gboolean (*GAChannelCallback)(GIOCondition condition, gpointer opaque);
+94 −3
Original line number Diff line number Diff line
@@ -840,10 +840,101 @@ static void guest_fsfreeze_cleanup(void)
GuestFilesystemTrimResponse *
qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
{
    error_setg(errp, QERR_UNSUPPORTED);
    GuestFilesystemTrimResponse *resp;
    HANDLE handle;
    WCHAR guid[MAX_PATH] = L"";

    handle = FindFirstVolumeW(guid, ARRAYSIZE(guid));
    if (handle == INVALID_HANDLE_VALUE) {
        error_setg_win32(errp, GetLastError(), "failed to find any volume");
        return NULL;
    }

    resp = g_new0(GuestFilesystemTrimResponse, 1);

    do {
        GuestFilesystemTrimResult *res;
        GuestFilesystemTrimResultList *list;
        PWCHAR uc_path;
        DWORD char_count = 0;
        char *path, *out;
        GError *gerr = NULL;
        gchar * argv[4];

        GetVolumePathNamesForVolumeNameW(guid, NULL, 0, &char_count);

        if (GetLastError() != ERROR_MORE_DATA) {
            continue;
        }
        if (GetDriveTypeW(guid) != DRIVE_FIXED) {
            continue;
        }

        uc_path = g_malloc(sizeof(WCHAR) * char_count);
        if (!GetVolumePathNamesForVolumeNameW(guid, uc_path, char_count,
                                              &char_count) || !*uc_path) {
            /* strange, but this condition could be faced even with size == 2 */
            g_free(uc_path);
            continue;
        }

        res = g_new0(GuestFilesystemTrimResult, 1);

        path = g_utf16_to_utf8(uc_path, char_count, NULL, NULL, &gerr);

        g_free(uc_path);

        if (!path) {
            res->has_error = true;
            res->error = g_strdup(gerr->message);
            g_error_free(gerr);
            break;
        }

        res->path = path;

        list = g_new0(GuestFilesystemTrimResultList, 1);
        list->value = res;
        list->next = resp->paths;

        resp->paths = list;

        memset(argv, 0, sizeof(argv));
        argv[0] = (gchar *)"defrag.exe";
        argv[1] = (gchar *)"/L";
        argv[2] = path;

        if (!g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
                          &out /* stdout */, NULL /* stdin */,
                          NULL, &gerr)) {
            res->has_error = true;
            res->error = g_strdup(gerr->message);
            g_error_free(gerr);
        } else {
            /* defrag.exe is UGLY. Exit code is ALWAYS zero.
               Error is reported in the output with something like
               (x89000020) etc code in the stdout */

            int i;
            gchar **lines = g_strsplit(out, "\r\n", 0);
            g_free(out);

            for (i = 0; lines[i] != NULL; i++) {
                if (g_strstr_len(lines[i], -1, "(0x") == NULL) {
                    continue;
                }
                res->has_error = true;
                res->error = g_strdup(lines[i]);
                break;
            }
            g_strfreev(lines);
        }
    } while (FindNextVolumeW(handle, guid, ARRAYSIZE(guid)));

    FindVolumeClose(handle);
    return resp;
}

typedef enum {
    GUEST_SUSPEND_MODE_DISK,
    GUEST_SUSPEND_MODE_RAM
@@ -1416,7 +1507,7 @@ GList *ga_command_blacklist_init(GList *blacklist)
        "guest-get-memory-blocks", "guest-set-memory-blocks",
        "guest-get-memory-block-size",
        "guest-fsfreeze-freeze-list",
        "guest-fstrim", NULL};
        NULL};
    char **p = (char **)list_unsupported;

    while (*p) {
Loading