[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