[qemu] fix vhost migration issues, and qxl locking for spice

Justin M. Forbes jforbes at fedoraproject.org
Wed Mar 16 20:33:58 UTC 2011


commit da929861c3e42e889f6635f4a459dd402d4d17fd
Author: Justin M. Forbes <jforbes at redhat.com>
Date:   Wed Mar 16 15:31:55 2011 -0500

    fix vhost migration issues, and qxl locking for spice

 ...-add-pflib-PixelFormat-conversion-library.patch |  259 ---
 0001-qxl-spice-display-move-pipe-to-ssd.patch      |  143 ++
 0002-configure-add-logging.patch                   |   39 -
 ...ent-get_command-in-vga-mode-without-locks.patch |  312 +++
 0003-add-spice-into-the-configure-file.patch       |   94 -
 ...emove-qemu_mutex_-un-lock_iothread-around.patch |  148 ++
 ...ender-drop-cursor-locks-replace-with-pipe.patch |  249 +++
 0004-spice-core-bits.patch                         |  333 ----
 0005-spice-add-keyboard.patch                      |  118 --
 0006-spice-add-mouse.patch                         |   62 -
 0007-spice-simple-display.patch                    |  532 -----
 0008-spice-add-tablet-support.patch                |  160 --
 0009-vgabios-update-to-0.6c-pcibios-patches.patch  |   28 -
 0010-switch-stdvga-to-pci-vgabios.patch            |   31 -
 0011-switch-vmware_vga-to-pci-vgabios.patch        |   50 -
 0012-all-vga-refuse-hotplugging.patch              |   61 -
 0013-spice-tls-support.patch                       |  168 --
 0014-spice-add-qxl-device.patch                    | 2085 --------------------
 0015-spice-add-audio.patch                         |  405 ----
 ...-add-virtio-serial-based-vdi-port-backend.patch |  238 ---
 0017-spice-add-pci-vdi-port-backend-obsolete.patch |  592 ------
 0018-use-memalign-instead-of-posix_memalign.patch  |   29 -
 0019-spice-live-migration-wip.patch                |  179 --
 0020-spice-display-draw.h-is-internal-now.patch    |   23 -
 0021-spice-display-disable-debug.patch             |   25 -
 0022-spice-display-pci-rev-fixups.patch            |   27 -
 0023-qxl-pci-rev-fixups.patch                      |   52 -
 0024-qxl-support-QXL_IO_DESTROY_ALL_SURFACES.patch |   26 -
 0025-spice-vmc-two-bugfixes-in-vmc_read.patch      |   57 -
 ...ing-disabling-jpeg-and-zlib-over-glz-via-.patch |   84 -
 0027-ifdef-new-config-options.patch                |   57 -
 ...spice-vmc-add-counter-to-debug-statements.patch |   27 -
 ...plit-vmc_write-to-max-sized-virtio_serial.patch |   53 -
 ...0x480-resolution-to-qxl_modes-n900-native.patch |   24 -
 0031-qxl-savevm-fixes.patch                        |  259 ---
 ...e-vmc-split-vmc_write-to-max-sized-virtio.patch |   53 -
 ...spice-vmc-add-counter-to-debug-statements.patch |   28 -
 ...Revert-spice-vmc-two-bugfixes-in-vmc_read.patch |   55 -
 0035-Revert-spice-live-migration-wip.patch         |  181 --
 ...t-spice-add-pci-vdi-port-backend-obsolete.patch |  590 ------
 ...e-add-virtio-serial-based-vdi-port-backen.patch |  236 ---
 ...irtio-serial-based-spice-vmchannel-backen.patch |  297 ---
 0039-qxl-fix-release-ring-overrun.patch            |   30 -
 0040-qxl-flip-default-to-stable-pci-revision.patch |   25 -
 0041-vmmouse-adapt-to-mouse-handler-changes.patch  |  116 --
 ...vhost-net-patches-for-qemu-0.13.0-tarball.patch |  316 ---
 avoid-llseek.patch                                 |   34 -
 ...vvfat.c-fix-warnings-with-_FORTIFY_SOURCE.patch |   63 -
 qemu-vhost-fix-dirty-page-handling.patch           |   31 +
 qemu.spec                                          |   15 +-
 50 files changed, 897 insertions(+), 8202 deletions(-)
---
diff --git a/0001-qxl-spice-display-move-pipe-to-ssd.patch b/0001-qxl-spice-display-move-pipe-to-ssd.patch
new file mode 100644
index 0000000..b542f54
--- /dev/null
+++ b/0001-qxl-spice-display-move-pipe-to-ssd.patch
@@ -0,0 +1,143 @@
+>From fd04276a00b172e6fbba3e3c72b1d13a0f179414 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Wed, 16 Mar 2011 15:21:03 +0100
+Subject: [PATCH 1/4] qxl/spice-display: move pipe to ssd
+
+This moves the int pipe[2] and pthread_t main data from the
+PCIQXLDevice struct to the SimpleSpiceDisplay. This will let us
+reuse it in the next patch for both -spice with no -qxl usage and
+for vga mode from qxl.
+
+Also move the pipe creation function (which is effectively completely rewritten
+by this patch anyways) from hw/qxl.c to ui/spice-display.c, since
+spice-display will depend on it after the next patch and qemu can be build
+with ui/spice-display.c in combination with no hw/qxl.c.
+---
+ hw/qxl.c           |   22 +++++-----------------
+ hw/qxl.h           |    4 ----
+ ui/spice-display.c |   21 +++++++++++++++++++++
+ ui/spice-display.h |    8 ++++++++
+ 4 files changed, 34 insertions(+), 21 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index fe4212b..201698f 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -1062,7 +1062,7 @@ static void pipe_read(void *opaque)
+     int len;
+ 
+     do {
+-        len = read(d->pipe[0], &dummy, sizeof(dummy));
++        len = read(d->ssd.pipe[0], &dummy, sizeof(dummy));
+     } while (len == sizeof(dummy));
+     qxl_set_irq(d);
+ }
+@@ -1078,10 +1078,11 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
+     if ((old_pending & le_events) == le_events) {
+         return;
+     }
+-    if (pthread_self() == d->main) {
++    if (pthread_self() == d->ssd.main) {
++        /* running in io_thread thread */
+         qxl_set_irq(d);
+     } else {
+-        if (write(d->pipe[1], d, 1) != 1) {
++        if (write(d->ssd.pipe[1], d, 1) != 1) {
+             dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
+         }
+     }
+@@ -1089,20 +1090,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
+ 
+ static void init_pipe_signaling(PCIQXLDevice *d)
+ {
+-   if (pipe(d->pipe) < 0) {
+-       dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__);
+-       return;
+-   }
+-#ifdef CONFIG_IOTHREAD
+-   fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
+-#else
+-   fcntl(d->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
+-#endif
+-   fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
+-   fcntl(d->pipe[0], F_SETOWN, getpid());
+-
+-   d->main = pthread_self();
+-   qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
++   qxl_create_server_to_iothread_pipe(&d->ssd, pipe_read);
+ }
+ 
+ /* graphics console */
+diff --git a/hw/qxl.h b/hw/qxl.h
+index f6c450d..701245f 100644
+--- a/hw/qxl.h
++++ b/hw/qxl.h
+@@ -55,10 +55,6 @@ typedef struct PCIQXLDevice {
+     } guest_surfaces;
+     QXLPHYSICAL        guest_cursor;
+ 
+-    /* thread signaling */
+-    pthread_t          main;
+-    int                pipe[2];
+-
+     /* ram pci bar */
+     QXLRam             *ram;
+     VGACommonState     vga;
+diff --git a/ui/spice-display.c b/ui/spice-display.c
+index 020b423..ec6e0cb 100644
+--- a/ui/spice-display.c
++++ b/ui/spice-display.c
+@@ -394,6 +394,27 @@ static DisplayChangeListener display_listener = {
+     .dpy_refresh = display_refresh,
+ };
+ 
++void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
++    IOHandler *pipe_read)
++{
++    if (pipe(ssd->pipe) < 0) {
++        fprintf(stderr, "%s: pipe creation failed\n", __FUNCTION__);
++        return;
++    }
++
++#ifdef CONFIG_IOTHREAD
++    fcntl(ssd->pipe[0], F_SETFL, O_NONBLOCK);
++#else
++    fcntl(ssd->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
++#endif
++    fcntl(ssd->pipe[1], F_SETFL, O_NONBLOCK);
++
++    fcntl(ssd->pipe[0], F_SETOWN, getpid());
++
++    qemu_set_fd_handler(ssd->pipe[0], pipe_read, NULL, ssd);
++    ssd->main = pthread_self();
++}
++
+ void qemu_spice_display_init(DisplayState *ds)
+ {
+     assert(sdpy.ds == NULL);
+diff --git a/ui/spice-display.h b/ui/spice-display.h
+index aef0464..3e6cf7c 100644
+--- a/ui/spice-display.h
++++ b/ui/spice-display.h
+@@ -43,6 +43,11 @@ typedef struct SimpleSpiceDisplay {
+     QXLRect dirty;
+     int notify;
+     int running;
++
++    /* thread signaling - used both in qxl (in vga mode
++     * and in native mode) and without qxl */
++    pthread_t          main;
++    int                pipe[2];     /* to iothread */
+ } SimpleSpiceDisplay;
+ 
+ typedef struct SimpleSpiceUpdate {
+@@ -66,3 +71,6 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+                                int x, int y, int w, int h);
+ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
+ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
++/* used by both qxl and spice-display */
++void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
++    IOHandler *pipe_read);
+-- 
+1.7.3.2
+
diff --git a/0002-qxl-implement-get_command-in-vga-mode-without-locks.patch b/0002-qxl-implement-get_command-in-vga-mode-without-locks.patch
new file mode 100644
index 0000000..d221d5f
--- /dev/null
+++ b/0002-qxl-implement-get_command-in-vga-mode-without-locks.patch
@@ -0,0 +1,312 @@
+>From 97e291086fef45762e0278e85ab1d231a9902bbb Mon Sep 17 00:00:00 2001
+From: Uri Lublin <uril at redhat.com>
+Date: Wed, 16 Mar 2011 15:43:45 +0100
+Subject: [PATCH 2/4] qxl: implement get_command in vga mode without locks
+
+This patch and the next drop the requirement to lose the global qemu
+mutex during dispatcher calls. This patch enables it, the next drops
+the unlock/lock pairs around dispatcher calls.
+
+The current solution of dropping the locks is buggy:
+ * it allows multiple dispatcher calls from two vcpu threads, the
+ dispatcher doesn't handle that by design (single fd, not locked, can't
+ handle writes from two threads)
+ * it requires us to keep track of cpu_single_env, which is magic.
+
+The solution implemented in this patch and the next (the next just
+drops the locks, this patch allows that to work):
+ * the only operation that needed locking was qemu_create_simple_update,
+ * it required locking because it was called from the spice-server thread.
+ * do it in the iothread by reusing the existing pipe used for set_irq.
+
+The current flow implemented is now:
+spice-server thread:
+ qxl.c:interface_get_command (called either by polling or from wakeup)
+  if update!=NULL:
+   waiting_for_update=0
+   update=NULL
+   return update
+  else:
+   if not waiting_for_update:
+    waiting_for_update=1
+    write to pipe, which is read by iothread (main thread)
+
+iothread:
+ wakeup from select,
+ qxl.c:pipe_read
+  update=qemu_create_simple_update()
+  wakeup spice-server thread by calling d.worker->wakeup(d.worker)
+---
+ hw/qxl.c           |   81 +++++++++++++++++++++++++++++++++++++++------------
+ ui/spice-display.c |   75 +++++++++++++++++++++++++++++++++++++++++++----
+ ui/spice-display.h |   16 ++++++++++
+ 3 files changed, 146 insertions(+), 26 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 201698f..64580f1 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -340,7 +340,6 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+ {
+     PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+-    SimpleSpiceUpdate *update;
+     QXLCommandRing *ring;
+     QXLCommand *cmd;
+     int notify;
+@@ -348,16 +347,25 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+     switch (qxl->mode) {
+     case QXL_MODE_VGA:
+         dprint(qxl, 2, "%s: vga\n", __FUNCTION__);
+-        update = qemu_spice_create_update(&qxl->ssd);
+-        if (update == NULL) {
+-            return false;
++        if (qxl_vga_mode_get_command(&qxl->ssd, ext)) {
++            qxl_log_command(qxl, "vga", ext);
++            return true;
+         }
+-        *ext = update->ext;
+-        qxl_log_command(qxl, "vga", ext);
+-        return true;
++        return false;
+     case QXL_MODE_COMPAT:
+     case QXL_MODE_NATIVE:
+     case QXL_MODE_UNDEFINED:
++        /* flush any existing updates that we didn't send to the guest.
++         * since update != NULL it means the server didn't get it, and
++         * because we changed mode to != QXL_MODE_VGA, it won't. */
++        if (qxl->ssd.update != NULL) {
++            if (qxl->ssd.update != QXL_EMPTY_UPDATE) {
++                qemu_spice_destroy_update(&qxl->ssd, qxl->ssd.update);
++            }
++            qxl->ssd.update = NULL;
++            qxl->ssd.waiting_for_update = 0;
++        }
++        /* */
+         dprint(qxl, 2, "%s: %s\n", __FUNCTION__,
+                qxl->cmdflags ? "compat" : "native");
+         ring = &qxl->ram->cmd_ring;
+@@ -1057,17 +1065,50 @@ static void qxl_map(PCIDevice *pci, int region_num,
+ 
+ static void pipe_read(void *opaque)
+ {
+-    PCIQXLDevice *d = opaque;
+-    char dummy;
+-    int len;
+-
+-    do {
+-        len = read(d->ssd.pipe[0], &dummy, sizeof(dummy));
+-    } while (len == sizeof(dummy));
+-    qxl_set_irq(d);
++    SimpleSpiceDisplay *ssd = opaque;
++    unsigned char cmd;
++    int len, set_irq = 0;
++    int create_update = 0;
++
++    while (1) {
++        cmd = 0;
++        len = read(ssd->pipe[0], &cmd, sizeof(cmd));
++        if (len < 0) {
++            if (errno == EINTR) {
++                continue;
++            }
++            if (errno == EAGAIN) {
++                break;
++            }
++            perror("qxl: pipe_read: read failed");
++            break;
++        }
++        switch (cmd) {
++        case QXL_SERVER_SET_IRQ:
++            set_irq = 1;
++            break;
++        case QXL_SERVER_CREATE_UPDATE:
++            create_update = 1;
++            break;
++        default:
++            fprintf(stderr, "%s: unknown cmd %u\n", __FUNCTION__, cmd);
++            abort();
++        }
++    }
++    /* no need to do either operation more than once */
++    if (create_update) {
++        assert(ssd->update == NULL);
++        ssd->update = qemu_spice_create_update(ssd);
++        if (ssd->update == NULL) {
++            ssd->update = QXL_EMPTY_UPDATE;
++        }
++        ssd->worker->wakeup(ssd->worker);
++    }
++    if (set_irq) {
++        qxl_set_irq(container_of(ssd, PCIQXLDevice, ssd));
++    }
+ }
+ 
+-/* called from spice server thread context only */
+ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
+ {
+     uint32_t old_pending;
+@@ -1082,9 +1123,11 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
+         /* running in io_thread thread */
+         qxl_set_irq(d);
+     } else {
+-        if (write(d->ssd.pipe[1], d, 1) != 1) {
+-            dprint(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
+-        }
++        /* called from spice-server thread */
++        int ret;
++        unsigned char ack = QXL_SERVER_SET_IRQ;
++        ret = write(d->ssd.pipe[1], &ack, 1);
++        assert(ret == 1);
+     }
+ }
+ 
+diff --git a/ui/spice-display.c b/ui/spice-display.c
+index ec6e0cb..bdd14b8 100644
+--- a/ui/spice-display.c
++++ b/ui/spice-display.c
+@@ -294,18 +294,39 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+     info->n_surfaces = NUM_SURFACES;
+ }
+ 
++/* Called from spice server thread context (via interface_get_command) */
++int qxl_vga_mode_get_command(
++    SimpleSpiceDisplay *ssd, struct QXLCommandExt *ext)
++{
++    SimpleSpiceUpdate *update;
++    unsigned char req;
++    int r;
++
++    update = ssd->update;
++    if (update != NULL) {
++        ssd->waiting_for_update = 0;
++        ssd->update = NULL;
++        if (update != QXL_EMPTY_UPDATE) {
++            *ext = update->ext;
++            return true;
++        }
++    } else {
++        if (!ssd->waiting_for_update) {
++            ssd->waiting_for_update = 1;
++            req = QXL_SERVER_CREATE_UPDATE;
++            r = write(ssd->pipe[1], &req , 1);
++            assert(r == 1);
++        }
++    }
++    return false;
++}
++
+ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+ {
+     SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl);
+-    SimpleSpiceUpdate *update;
+ 
+     dprint(3, "%s:\n", __FUNCTION__);
+-    update = qemu_spice_create_update(ssd);
+-    if (update == NULL) {
+-        return false;
+-    }
+-    *ext = update->ext;
+-    return true;
++    return qxl_vga_mode_get_command(ssd, ext);
+ }
+ 
+ static int interface_req_cmd_notification(QXLInstance *sin)
+@@ -394,6 +415,45 @@ static DisplayChangeListener display_listener = {
+     .dpy_refresh = display_refresh,
+ };
+ 
++static void pipe_read(void *opaque)
++{
++    SimpleSpiceDisplay *ssd = opaque;
++    unsigned char cmd;
++    int len, create_update = 0;
++
++    while (1) {
++        cmd = 0;
++        len = read(ssd->pipe[0], &cmd, sizeof(cmd));
++        if (len < 0) {
++            if (errno == EINTR) {
++                continue;
++            }
++            if (errno == EAGAIN) {
++                break;
++            }
++            perror("qxl: pipe_read: read failed");
++            break;
++        }
++        switch (cmd) {
++        case QXL_SERVER_CREATE_UPDATE:
++            create_update = 1;
++            break;
++        default:
++            fprintf(stderr, "%s: unknown cmd %u\n", __FUNCTION__, cmd);
++            abort();
++        }
++    }
++    /* no need to do this more than once */
++    if (create_update) {
++        assert(ssd->update == NULL);
++        ssd->update = qemu_spice_create_update(ssd);
++        if (ssd->update == NULL) {
++            ssd->update = QXL_EMPTY_UPDATE;
++        }
++        ssd->worker->wakeup(ssd->worker);
++    }
++}
++
+ void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
+     IOHandler *pipe_read)
+ {
+@@ -427,6 +487,7 @@ void qemu_spice_display_init(DisplayState *ds)
+     qemu_spice_add_interface(&sdpy.qxl.base);
+     assert(sdpy.worker);
+ 
++    qxl_create_server_to_iothread_pipe(&sdpy, pipe_read);
+     qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy);
+     qemu_spice_create_host_memslot(&sdpy);
+     qemu_spice_create_host_primary(&sdpy);
+diff --git a/ui/spice-display.h b/ui/spice-display.h
+index 3e6cf7c..2be6a34 100644
+--- a/ui/spice-display.h
++++ b/ui/spice-display.h
+@@ -31,6 +31,15 @@
+ 
+ #define NUM_SURFACES 1024
+ 
++/* For commands/requests from server thread to iothread */
++#define QXL_EMPTY_UPDATE ((void *)-1)
++enum {
++    QXL_SERVER_SET_IRQ = 1,
++    QXL_SERVER_CREATE_UPDATE,
++};
++
++struct SimpleSpiceUpdate;
++
+ typedef struct SimpleSpiceDisplay {
+     DisplayState *ds;
+     void *buf;
+@@ -48,6 +57,10 @@ typedef struct SimpleSpiceDisplay {
+      * and in native mode) and without qxl */
+     pthread_t          main;
+     int                pipe[2];     /* to iothread */
++
++    /* ssd updates (one request/command at a time) */
++    struct SimpleSpiceUpdate *update;
++    int waiting_for_update;
+ } SimpleSpiceDisplay;
+ 
+ typedef struct SimpleSpiceUpdate {
+@@ -71,6 +84,9 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+                                int x, int y, int w, int h);
+ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd);
+ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd);
++/* shared with qxl.c in vga mode and ui/spice-display (no qxl mode) */
++int qxl_vga_mode_get_command(
++    SimpleSpiceDisplay *ssd, struct QXLCommandExt *ext);
+ /* used by both qxl and spice-display */
+ void qxl_create_server_to_iothread_pipe(SimpleSpiceDisplay *ssd,
+     IOHandler *pipe_read);
+-- 
+1.7.3.2
+
diff --git a/0003-qxl-spice-remove-qemu_mutex_-un-lock_iothread-around.patch b/0003-qxl-spice-remove-qemu_mutex_-un-lock_iothread-around.patch
new file mode 100644
index 0000000..92a148e
--- /dev/null
+++ b/0003-qxl-spice-remove-qemu_mutex_-un-lock_iothread-around.patch
@@ -0,0 +1,148 @@
+>From d413b3c36cbd9820c5b9492b52caa421abccf745 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Wed, 16 Mar 2011 15:46:22 +0100
+Subject: [PATCH 3/4] qxl/spice: remove qemu_mutex_{un,}lock_iothread around dispatcher
+
+with the previous patch making sure get_command no longer needs to lock,
+there is no reason to drop the qemu iothread mutex in qxl.c and in
+ui/spice-display.c
+
+The only location where the lock remains are the cursor related callbacks,
+that path is currently broken. It is only triggered if running spice and sdl,
+which is broken already before that.
+---
+ hw/qxl.c           |    8 --------
+ ui/spice-display.c |   19 +++----------------
+ 2 files changed, 3 insertions(+), 24 deletions(-)
+
+diff --git a/hw/qxl.c b/hw/qxl.c
+index 64580f1..cf3c938 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -670,10 +670,8 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
+     dprint(d, 1, "%s: start%s\n", __FUNCTION__,
+            loadvm ? " (loadvm)" : "");
+ 
+-    qemu_mutex_unlock_iothread();
+     d->ssd.worker->reset_cursor(d->ssd.worker);
+     d->ssd.worker->reset_image_cache(d->ssd.worker);
+-    qemu_mutex_lock_iothread();
+     qxl_reset_surfaces(d);
+     qxl_reset_memslots(d);
+ 
+@@ -803,9 +801,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d)
+ {
+     dprint(d, 1, "%s:\n", __FUNCTION__);
+     d->mode = QXL_MODE_UNDEFINED;
+-    qemu_mutex_unlock_iothread();
+     d->ssd.worker->destroy_surfaces(d->ssd.worker);
+-    qemu_mutex_lock_iothread();
+     memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
+ }
+ 
+@@ -874,9 +870,7 @@ static void qxl_destroy_primary(PCIQXLDevice *d)
+     dprint(d, 1, "%s\n", __FUNCTION__);
+ 
+     d->mode = QXL_MODE_UNDEFINED;
+-    qemu_mutex_unlock_iothread();
+     d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
+-    qemu_mutex_lock_iothread();
+ }
+ 
+ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm)
+@@ -946,10 +940,8 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
+     case QXL_IO_UPDATE_AREA:
+     {
+         QXLRect update = d->ram->update_area;
+-        qemu_mutex_unlock_iothread();
+         d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
+                                    &update, NULL, 0, 0);
+-        qemu_mutex_lock_iothread();
+         break;
+     }
+     case QXL_IO_NOTIFY_CMD:
+diff --git a/ui/spice-display.c b/ui/spice-display.c
+index bdd14b8..ecb22cc 100644
+--- a/ui/spice-display.c
++++ b/ui/spice-display.c
+@@ -62,13 +62,7 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r)
+     dest->right = MAX(dest->right, r->right);
+ }
+ 
+-/*
+- * Called from spice server thread context (via interface_get_command).
+- *
+- * We must aquire the global qemu mutex here to make sure the
+- * DisplayState (+DisplaySurface) we are accessing doesn't change
+- * underneath us.
+- */
++/* Called from io-thread context (via pipe_read) */
+ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+ {
+     SimpleSpiceUpdate *update;
+@@ -78,9 +72,7 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+     uint8_t *src, *dst;
+     int by, bw, bh;
+ 
+-    qemu_mutex_lock_iothread();
+     if (qemu_spice_rect_is_empty(&ssd->dirty)) {
+-        qemu_mutex_unlock_iothread();
+         return NULL;
+     };
+ 
+@@ -141,7 +133,6 @@ SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd)
+     cmd->data = (intptr_t)drawable;
+ 
+     memset(&ssd->dirty, 0, sizeof(ssd->dirty));
+-    qemu_mutex_unlock_iothread();
+     return update;
+ }
+ 
+@@ -169,6 +160,7 @@ void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd)
+     ssd->worker->add_memslot(ssd->worker, &memslot);
+ }
+ 
++/* called from iothread (main) or a vcpu-thread */
+ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+ {
+     QXLDevSurfaceCreate surface;
+@@ -186,18 +178,14 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd)
+     surface.mem        = (intptr_t)ssd->buf;
+     surface.group_id   = MEMSLOT_GROUP_HOST;
+ 
+-    qemu_mutex_unlock_iothread();
+     ssd->worker->create_primary_surface(ssd->worker, 0, &surface);
+-    qemu_mutex_lock_iothread();
+ }
+ 
+ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd)
+ {
+     dprint(1, "%s:\n", __FUNCTION__);
+ 
+-    qemu_mutex_unlock_iothread();
+     ssd->worker->destroy_primary_surface(ssd->worker, 0);
+-    qemu_mutex_lock_iothread();
+ }
+ 
+ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+@@ -207,9 +195,7 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason)
+     if (running) {
+         ssd->worker->start(ssd->worker);
+     } else {
+-        qemu_mutex_unlock_iothread();
+         ssd->worker->stop(ssd->worker);
+-        qemu_mutex_lock_iothread();
+     }
+     ssd->running = running;
+ }
+@@ -233,6 +219,7 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd,
+     qemu_spice_rect_union(&ssd->dirty, &update_area);
+ }
+ 
++/* called only from iothread (main) */
+ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
+ {
+     dprint(1, "%s:\n", __FUNCTION__);
+-- 
+1.7.3.2
+
diff --git a/0004-hw-qxl-render-drop-cursor-locks-replace-with-pipe.patch b/0004-hw-qxl-render-drop-cursor-locks-replace-with-pipe.patch
new file mode 100644
index 0000000..03daba4
--- /dev/null
+++ b/0004-hw-qxl-render-drop-cursor-locks-replace-with-pipe.patch
@@ -0,0 +1,249 @@
+>From 1a33e5f2fa6de800047517a6f3251dc7191c97b5 Mon Sep 17 00:00:00 2001
+From: Alon Levy <alevy at redhat.com>
+Date: Wed, 16 Mar 2011 16:02:16 +0100
+Subject: [PATCH 4/4] hw/qxl-render: drop cursor locks, replace with pipe
+
+Switching locking protection of ds->cursor_set/cursor_move to moving
+every call to these functions into the iothread and using the ssd->pipe
+to transfer that, adding QXL_SERVER_CURSOR_SET, QXL_SERVER_CURSOR_MOVE.
+
+This is tested with both -vnc :0 -spice and -sdl -spice.
+---
+ hw/qxl-render.c    |   25 +++++++++-----
+ hw/qxl.c           |   90 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ hw/qxl.h           |    4 ++
+ ui/spice-display.h |   13 +++++++-
+ 4 files changed, 122 insertions(+), 10 deletions(-)
+
+diff --git a/hw/qxl-render.c b/hw/qxl-render.c
+index 58965e0..6759edb 100644
+--- a/hw/qxl-render.c
++++ b/hw/qxl-render.c
+@@ -178,7 +178,6 @@ fail:
+     return NULL;
+ }
+ 
+-
+ /* called from spice server thread context only */
+ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
+ {
+@@ -209,18 +208,26 @@ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
+         if (c == NULL) {
+             c = cursor_builtin_left_ptr();
+         }
+-        qemu_mutex_lock_iothread();
+-        qxl->ssd.ds->cursor_define(c);
+-        qxl->ssd.ds->mouse_set(x, y, 1);
+-        qemu_mutex_unlock_iothread();
+-        cursor_put(c);
++        qxl_server_request_cursor_set(qxl, c, x, y);
+         break;
+     case QXL_CURSOR_MOVE:
+         x = cmd->u.position.x;
+         y = cmd->u.position.y;
+-        qemu_mutex_lock_iothread();
+-        qxl->ssd.ds->mouse_set(x, y, 1);
+-        qemu_mutex_unlock_iothread();
++        qxl_server_request_cursor_move(qxl, x, y);
+         break;
+     }
+ }
++
++/* called from iothread only (via qxl.c:pipe_read) */
++void qxl_render_cursor_set(SimpleSpiceDisplay *ssd, QEMUCursor *c, int x, int y)
++{
++    ssd->ds->cursor_define(c);
++    ssd->ds->mouse_set(x, y, 1);
++    cursor_put(c);
++}
++
++/* called from iothread only (via qxl.c:pipe_read) */
++void qxl_render_cursor_move(SimpleSpiceDisplay *ssd, int x, int y)
++{
++    ssd->ds->mouse_set(x, y, 1);
++}
+diff --git a/hw/qxl.c b/hw/qxl.c
+index cf3c938..4c27deb 100644
+--- a/hw/qxl.c
++++ b/hw/qxl.c
+@@ -117,6 +117,27 @@ static QXLMode qxl_modes[] = {
+ #endif
+ };
+ 
++typedef struct __attribute__ ((__packed__)) {
++    QEMUCursor *c;
++    int x;
++    int y;
++} QXLServerCursorSet;
++
++typedef struct __attribute__ ((__packed__)) {
++    int x;
++    int y;
++} QXLServerCursorMove;
++
++typedef struct __attribute__ ((__packed__)) {
++    unsigned char req;
++    QXLServerCursorMove data;
++} QXLServerCursorMoveRequest;
++
++typedef struct __attribute__ ((__packed__)) {
++    unsigned char req;
++    QXLServerCursorSet data;
++} QXLServerCursorSetRequest;
++
+ static PCIQXLDevice *qxl0;
+ 
+ static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
+@@ -337,6 +358,33 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
+ }
+ 
+ /* called from spice server thread context only */
++void qxl_server_request_cursor_set(PCIQXLDevice *qxl, QEMUCursor *c, int x, int y)
++{
++    QXLServerCursorSetRequest req;
++    int r;
++
++    req.req = QXL_SERVER_CURSOR_SET;
++    req.data.c = c;
++    req.data.x = x;
++    req.data.y = y;
++    r = write(qxl->ssd.pipe[1], &req, sizeof(req));
++    assert(r == sizeof(req));
++}
++
++/* called from spice server thread context only */
++void qxl_server_request_cursor_move(PCIQXLDevice *qxl, int x, int y)
++{
++    QXLServerCursorMoveRequest req;
++    int r;
++
++    req.req = QXL_SERVER_CURSOR_MOVE;
++    req.data.x = x;
++    req.data.y = y;
++    r = write(qxl->ssd.pipe[1], &req, sizeof(req));
++    assert(r == sizeof(req));
++}
++
++/* called from spice server thread context only */
+ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
+ {
+     PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
+@@ -1055,12 +1103,37 @@ static void qxl_map(PCIDevice *pci, int region_num,
+     }
+ }
+ 
++static void read_bytes(int fd, void *buf, int len_requested)
++{
++    int len;
++    int total_len = 0;
++
++    do {
++        len = read(fd, buf, len_requested - total_len);
++        if (len < 0) {
++            if (errno == EINTR || errno == EAGAIN) {
++                continue;
++            }
++            perror("qxl: pipe_read: read failed");
++            /* will abort once it's out of the while loop */
++            break;
++        }
++        total_len += len;
++        buf = (uint8_t *)buf + len;
++    } while (total_len < len_requested);
++    assert(total_len == len_requested);
++}
++
+ static void pipe_read(void *opaque)
+ {
+     SimpleSpiceDisplay *ssd = opaque;
+     unsigned char cmd;
+     int len, set_irq = 0;
+     int create_update = 0;
++    int cursor_set = 0;
++    int cursor_move = 0;
++    QXLServerCursorSet cursor_set_data;
++    QXLServerCursorMove cursor_move_data;
+ 
+     while (1) {
+         cmd = 0;
+@@ -1082,6 +1155,17 @@ static void pipe_read(void *opaque)
+         case QXL_SERVER_CREATE_UPDATE:
+             create_update = 1;
+             break;
++        case QXL_SERVER_CURSOR_SET:
++            if (cursor_set == 1) {
++                cursor_put(cursor_set_data.c);
++            }
++            cursor_set = 1;
++            read_bytes(ssd->pipe[0], &cursor_set_data, sizeof(cursor_set_data));
++            break;
++        case QXL_SERVER_CURSOR_MOVE:
++            cursor_move = 1;
++            read_bytes(ssd->pipe[0], &cursor_move_data, sizeof(cursor_move_data));
++            break;
+         default:
+             fprintf(stderr, "%s: unknown cmd %u\n", __FUNCTION__, cmd);
+             abort();
+@@ -1099,6 +1183,12 @@ static void pipe_read(void *opaque)
+     if (set_irq) {
+         qxl_set_irq(container_of(ssd, PCIQXLDevice, ssd));
+     }
++    if (cursor_move) {
++        qxl_render_cursor_move(ssd, cursor_move_data.x, cursor_move_data.y);
++    }
++    if (cursor_set) {
++        qxl_render_cursor_set(ssd, cursor_set_data.c, cursor_set_data.x, cursor_set_data.y);
++    }
+ }
+ 
+ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
+diff --git a/hw/qxl.h b/hw/qxl.h
+index 701245f..f4f99ec 100644
+--- a/hw/qxl.h
++++ b/hw/qxl.h
+@@ -93,6 +93,8 @@ typedef struct PCIQXLDevice {
+ 
+ /* qxl.c */
+ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
++void qxl_server_request_cursor_set(PCIQXLDevice *qxl, QEMUCursor *c, int x, int y);
++void qxl_server_request_cursor_move(PCIQXLDevice *qxl, int x, int y);
+ 
+ /* qxl-logger.c */
+ void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
+@@ -102,3 +104,5 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
+ void qxl_render_resize(PCIQXLDevice *qxl);
+ void qxl_render_update(PCIQXLDevice *qxl);
+ void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
++void qxl_render_cursor_set(SimpleSpiceDisplay *ssd, QEMUCursor *c, int x, int y);
++void qxl_render_cursor_move(SimpleSpiceDisplay *ssd, int x, int y);
+diff --git a/ui/spice-display.h b/ui/spice-display.h
+index 2be6a34..bbfd689 100644
+--- a/ui/spice-display.h
++++ b/ui/spice-display.h
+@@ -31,11 +31,22 @@
+ 
+ #define NUM_SURFACES 1024
+ 
+-/* For commands/requests from server thread to iothread */
++/*
++ * Commands/requests from server thread to iothread.
++ * Note that CREATE_UPDATE is used both with qxl and without it (spice-display)
++ * the others are only used with the qxl device.
++ *
++ * SET_IRQ - just the request is sent (1 byte)
++ * CREATE_UPDATE - jus the request is sent (1 byte)
++ * CURSOR_SET - send QXLServerRequestCursorSet
++ * CURSOR_MOVE - send QXLServerRequestCursorMove
++ */
+ #define QXL_EMPTY_UPDATE ((void *)-1)
+ enum {
+     QXL_SERVER_SET_IRQ = 1,
+     QXL_SERVER_CREATE_UPDATE,
++    QXL_SERVER_CURSOR_SET,
++    QXL_SERVER_CURSOR_MOVE
+ };
+ 
+ struct SimpleSpiceUpdate;
+-- 
+1.7.3.2
+
diff --git a/qemu-vhost-fix-dirty-page-handling.patch b/qemu-vhost-fix-dirty-page-handling.patch
new file mode 100644
index 0000000..e3fabb7
--- /dev/null
+++ b/qemu-vhost-fix-dirty-page-handling.patch
@@ -0,0 +1,31 @@
+vhost was passing a physical address to cpu_physical_memory_set_dirty,
+which is wrong: we need to translate to ram address first.
+
+Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
+
+Note: this lead to crashes during migration, so the patch
+is needed on the stable branch too.
+
+---
+ hw/vhost.c |    4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/hw/vhost.c b/hw/vhost.c
+index aaa34e4..97a1299 100644
+--- a/hw/vhost.c
++++ b/hw/vhost.c
+@@ -49,8 +49,10 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
+         log = __sync_fetch_and_and(from, 0);
+         while ((bit = sizeof(log) > sizeof(int) ?
+                 ffsll(log) : ffs(log))) {
++            ram_addr_t ram_addr;
+             bit -= 1;
+-            cpu_physical_memory_set_dirty(addr + bit * VHOST_LOG_PAGE);
++            ram_addr = cpu_get_physical_page_desc(addr + bit * VHOST_LOG_PAGE);
++            cpu_physical_memory_set_dirty(ram_addr);
+             log &= ~(0x1ull << bit);
+         }
+         addr += VHOST_LOG_CHUNK;
+-- 
+1.7.3.2.91.g446ac
+
diff --git a/qemu.spec b/qemu.spec
index 98c115b..630116b 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -1,7 +1,7 @@
 Summary: QEMU is a FAST! processor emulator
 Name: qemu
 Version: 0.14.0
-Release: 2%{?dist}
+Release: 3%{?dist}
 # Epoch because we pushed a qemu-1.0 package
 Epoch: 2
 License: GPLv2+ and LGPLv2+ and BSD
@@ -37,7 +37,16 @@ Source8: ksmtuned.conf
 # with F-13/
 Patch00: pc-add-a-Fedora-13-machine-type-for-backward-compat.patch
 
+# Patches from upstream:
 Patch01: qemu-fix-non-PCI-target-build.patch
+Patch02: qemu-vhost-fix-dirty-page-handling.patch
+
+# Spice fixes
+Patch20: 0001-qxl-spice-display-move-pipe-to-ssd.patch
+Patch21: 0002-qxl-implement-get_command-in-vga-mode-without-locks.patch
+Patch22: 0003-qxl-spice-remove-qemu_mutex_-un-lock_iothread-around.patch
+Patch23: 0004-hw-qxl-render-drop-cursor-locks-replace-with-pipe.patch
+
 
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel
@@ -570,6 +579,10 @@ fi
 %{_mandir}/man1/qemu-img.1*
 
 %changelog
+* Wed Mar 16 2011 Justin M. Forbes <jforbes at redhat.com> - 2:0.14.0-3
+- Fix migration issue with vhost
+- Fix qxl locking issues for spice
+
 * Wed Mar 02 2011 Justin M. Forbes <jforbes at redhat.com> - 2:0.14.0-2
 - Re-enable sparc and cris builds
 


More information about the scm-commits mailing list