From afe2df69cf9305b195d96afc545d3fefc0fb5f5d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Tue, 25 Oct 2011 13:50:11 +0200 Subject: [PATCH 01/11] migration: add status query functions Add migration_is_active and migration_has_failed functions to query migration state. Signed-off-by: Gerd Hoffmann --- migration.c | 11 +++++++++++ migration.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/migration.c b/migration.c index bdca72e008..d6935678b9 100644 --- a/migration.c +++ b/migration.c @@ -372,11 +372,22 @@ void remove_migration_state_change_notifier(Notifier *notify) notifier_list_remove(&migration_state_notifiers, notify); } +bool migration_is_active(MigrationState *s) +{ + return s->state == MIG_STATE_ACTIVE; +} + bool migration_has_finished(MigrationState *s) { return s->state == MIG_STATE_COMPLETED; } +bool migration_has_failed(MigrationState *s) +{ + return (s->state == MIG_STATE_CANCELLED || + s->state == MIG_STATE_ERROR); +} + void migrate_fd_connect(MigrationState *s) { int ret; diff --git a/migration.h b/migration.h index a1f80d0728..1b8ee58530 100644 --- a/migration.h +++ b/migration.h @@ -76,7 +76,9 @@ void migrate_fd_connect(MigrationState *s); void add_migration_state_change_notifier(Notifier *notify); void remove_migration_state_change_notifier(Notifier *notify); +bool migration_is_active(MigrationState *); bool migration_has_finished(MigrationState *); +bool migration_has_failed(MigrationState *); uint64_t ram_bytes_remaining(void); uint64_t ram_bytes_transferred(void); From edc5cb1a52b2847201acf78b0fba67ab3c2464d5 Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Mon, 17 Oct 2011 10:03:18 +0200 Subject: [PATCH 02/11] spice: turn client_migrate_info to async RHBZ 737921 Spice client is required to connect to the migration target before/as migration starts. Since after migration starts, the target qemu is blocked and cannot accept new spice client we trigger the connection to the target upon client_migrate_info command. client_migrate_info completion cb will be called after spice client has been connected to the target (or a timeout). See following patches and spice patches. Signed-off-by: Yonit Halperin Signed-off-by: Gerd Hoffmann --- hmp-commands.hx | 3 ++- monitor.c | 6 ++++-- qmp-commands.hx | 3 ++- ui/qemu-spice.h | 14 +++++++++++--- ui/spice-core.c | 10 +++++++--- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index ab08d583df..e1812676e3 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -824,7 +824,8 @@ ETEXI .params = "protocol hostname port tls-port cert-subject", .help = "send migration info to spice/vnc client", .user_print = monitor_user_noop, - .mhandler.cmd_new = client_migrate_info, + .mhandler.cmd_async = client_migrate_info, + .flags = MONITOR_CMD_ASYNC, }, STEXI diff --git a/monitor.c b/monitor.c index ffda0feb84..13b0fa5738 100644 --- a/monitor.c +++ b/monitor.c @@ -1153,7 +1153,8 @@ static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_d return -1; } -static int client_migrate_info(Monitor *mon, const QDict *qdict, QObject **ret_data) +static int client_migrate_info(Monitor *mon, const QDict *qdict, + MonitorCompletion cb, void *opaque) { const char *protocol = qdict_get_str(qdict, "protocol"); const char *hostname = qdict_get_str(qdict, "hostname"); @@ -1168,7 +1169,8 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict, QObject **ret_d return -1; } - ret = qemu_spice_migrate_info(hostname, port, tls_port, subject); + ret = qemu_spice_migrate_info(hostname, port, tls_port, subject, + cb, opaque); if (ret != 0) { qerror_report(QERR_UNDEFINED_ERROR); return -1; diff --git a/qmp-commands.hx b/qmp-commands.hx index 4328e8b86c..cb60d0cdf1 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -569,7 +569,8 @@ EQMP .params = "protocol hostname port tls-port cert-subject", .help = "send migration info to spice/vnc client", .user_print = monitor_user_noop, - .mhandler.cmd_new = client_migrate_info, + .mhandler.cmd_async = client_migrate_info, + .flags = MONITOR_CMD_ASYNC, }, SQMP diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index f34be69f52..c35b29c1f6 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -25,6 +25,7 @@ #include "qemu-option.h" #include "qemu-config.h" #include "qemu-char.h" +#include "monitor.h" extern int using_spice; @@ -37,7 +38,8 @@ int qemu_spice_set_passwd(const char *passwd, bool fail_if_connected, bool disconnect_if_connected); int qemu_spice_set_pw_expire(time_t expires); int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, - const char *subject); + const char *subject, + MonitorCompletion cb, void *opaque); void do_info_spice_print(Monitor *mon, const QObject *data); void do_info_spice(Monitor *mon, QObject **ret_data); @@ -45,6 +47,7 @@ void do_info_spice(Monitor *mon, QObject **ret_data); int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr); #else /* CONFIG_SPICE */ +#include "monitor.h" #define using_spice 0 static inline int qemu_spice_set_passwd(const char *passwd, @@ -57,8 +60,13 @@ static inline int qemu_spice_set_pw_expire(time_t expires) { return -1; } -static inline int qemu_spice_migrate_info(const char *h, int p, int t, const char *s) -{ return -1; } +static inline int qemu_spice_migrate_info(const char *h, int p, int t, + const char *s, + MonitorCompletion cb, void *opaque) +{ + cb(opaque, NULL); + return -1; +} #endif /* CONFIG_SPICE */ diff --git a/ui/spice-core.c b/ui/spice-core.c index b33366e5d7..62ffb9b28c 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -457,10 +457,14 @@ static void migration_state_notifier(Notifier *notifier, void *data) } int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, - const char *subject) + const char *subject, + MonitorCompletion *cb, void *opaque) { - return spice_server_migrate_info(spice_server, hostname, - port, tls_port, subject); + int ret; + ret = spice_server_migrate_info(spice_server, hostname, + port, tls_port, subject); + cb(opaque, NULL); + return ret; } static int add_channel(const char *name, const char *value, void *opaque) From 026f773f562d118962fbdf3c28c66571f75f96fe Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Mon, 17 Oct 2011 10:03:19 +0200 Subject: [PATCH 03/11] spice: support the new migration interface (spice 0.8.3) - call spice_server_migrate_(start|end|connect). - register spice_migrate_connect completion callback Signed-off-by: Yonit Halperin Signed-off-by: Gerd Hoffmann --- ui/spice-core.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/ui/spice-core.c b/ui/spice-core.c index 62ffb9b28c..8a86e4530e 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -288,6 +288,38 @@ static SpiceCoreInterface core_interface = { #endif }; +#ifdef SPICE_INTERFACE_MIGRATION +typedef struct SpiceMigration { + SpiceMigrateInstance sin; + struct { + MonitorCompletion *cb; + void *opaque; + } connect_complete; +} SpiceMigration; + +static void migrate_connect_complete_cb(SpiceMigrateInstance *sin); + +static const SpiceMigrateInterface migrate_interface = { + .base.type = SPICE_INTERFACE_MIGRATION, + .base.description = "migration", + .base.major_version = SPICE_INTERFACE_MIGRATION_MAJOR, + .base.minor_version = SPICE_INTERFACE_MIGRATION_MINOR, + .migrate_connect_complete = migrate_connect_complete_cb, + .migrate_end_complete = NULL, +}; + +static SpiceMigration spice_migrate; + +static void migrate_connect_complete_cb(SpiceMigrateInstance *sin) +{ + SpiceMigration *sm = container_of(sin, SpiceMigration, sin); + if (sm->connect_complete.cb) { + sm->connect_complete.cb(sm->connect_complete.opaque, NULL); + } + sm->connect_complete.cb = NULL; +} +#endif + /* config string parsing */ static int name2enum(const char *string, const char *table[], int entries) @@ -449,9 +481,19 @@ static void migration_state_notifier(Notifier *notifier, void *data) { MigrationState *s = data; - if (migration_has_finished(s)) { + if (migration_is_active(s)) { +#ifdef SPICE_INTERFACE_MIGRATION + spice_server_migrate_start(spice_server); +#endif + } else if (migration_has_finished(s)) { #if SPICE_SERVER_VERSION >= 0x000701 /* 0.7.1 */ +#ifndef SPICE_INTERFACE_MIGRATION spice_server_migrate_switch(spice_server); +#else + spice_server_migrate_end(spice_server, true); + } else if (migration_has_failed(s)) { + spice_server_migrate_end(spice_server, false); +#endif #endif } } @@ -461,9 +503,16 @@ int qemu_spice_migrate_info(const char *hostname, int port, int tls_port, MonitorCompletion *cb, void *opaque) { int ret; +#ifdef SPICE_INTERFACE_MIGRATION + spice_migrate.connect_complete.cb = cb; + spice_migrate.connect_complete.opaque = opaque; + ret = spice_server_migrate_connect(spice_server, hostname, + port, tls_port, subject); +#else ret = spice_server_migrate_info(spice_server, hostname, port, tls_port, subject); cb(opaque, NULL); +#endif return ret; } @@ -654,6 +703,11 @@ void qemu_spice_init(void) migration_state.notify = migration_state_notifier; add_migration_state_change_notifier(&migration_state); +#ifdef SPICE_INTERFACE_MIGRATION + spice_migrate.sin.base.sif = &migrate_interface.base; + spice_migrate.connect_complete.cb = NULL; + qemu_spice_add_interface(&spice_migrate.sin.base); +#endif qemu_spice_input_init(); qemu_spice_audio_init(); From f9ab6091b0a741c47546b38301836f2ab6ce978d Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 20 Sep 2011 17:14:33 +0200 Subject: [PATCH 04/11] spice: Convert core to QEMU thread API No need to use pthread directly, we have proper abstractions for identity checking. Signed-off-by: Jan Kiszka Signed-off-by: Gerd Hoffmann --- ui/spice-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/spice-core.c b/ui/spice-core.c index 8a86e4530e..4c06c36c31 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -19,10 +19,10 @@ #include #include -#include #include "qemu-common.h" #include "qemu-spice.h" +#include "qemu-thread.h" #include "qemu-timer.h" #include "qemu-queue.h" #include "qemu-x509.h" @@ -45,7 +45,7 @@ static char *auth_passwd; static time_t auth_expires = TIME_MAX; int using_spice = 0; -static pthread_t me; +static QemuThread me; struct SpiceTimer { QEMUTimer *timer; @@ -229,7 +229,7 @@ static void channel_event(int event, SpiceChannelEventInfo *info) * thread and grab the iothread lock if so before calling qemu * functions. */ - bool need_lock = !pthread_equal(me, pthread_self()); + bool need_lock = !qemu_thread_is_self(&me); if (need_lock) { qemu_mutex_lock_iothread(); } @@ -556,7 +556,7 @@ void qemu_spice_init(void) spice_image_compression_t compression; spice_wan_compression_t wan_compr; - me = pthread_self(); + qemu_thread_get_self(&me); if (!opts) { return; From 691f5c7bde07218127e034cca4e2581f66a6ddcf Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 20 Sep 2011 17:14:40 +0200 Subject: [PATCH 05/11] qxl: Convert to QEMU thread API Use QEMU thread API instead of pthread directly. We still need to get rid of pthread_yield, though, to drop pthread.h inclusion. Signed-off-by: Jan Kiszka Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 4 ++-- hw/qxl.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index 03848edb75..a0b0f36eb5 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1372,7 +1372,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) if ((old_pending & le_events) == le_events) { return; } - if (pthread_self() == d->main) { + if (qemu_thread_is_self(&d->main)) { qxl_update_irq(d); } else { if (write(d->pipe[1], d, 1) != 1) { @@ -1391,7 +1391,7 @@ static void init_pipe_signaling(PCIQXLDevice *d) fcntl(d->pipe[1], F_SETFL, O_NONBLOCK); fcntl(d->pipe[0], F_SETOWN, getpid()); - d->main = pthread_self(); + qemu_thread_get_self(&d->main); qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d); } diff --git a/hw/qxl.h b/hw/qxl.h index 868db813f9..37b2619e55 100644 --- a/hw/qxl.h +++ b/hw/qxl.h @@ -4,6 +4,7 @@ #include "hw.h" #include "pci.h" #include "vga_int.h" +#include "qemu-thread.h" #include "ui/qemu-spice.h" #include "ui/spice-display.h" @@ -63,7 +64,7 @@ typedef struct PCIQXLDevice { QemuMutex track_lock; /* thread signaling */ - pthread_t main; + QemuThread main; int pipe[2]; /* ram pci bar */ From 4ec8d3077b799fcdd9fe0f38e432791c8fceb88e Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Tue, 20 Sep 2011 17:21:07 +0200 Subject: [PATCH 06/11] qxl: Drop phread_yield on OOM This was only a best-effort attempt, by far not guaranteed to have an effect. Drop it so that also no direct pthread usage remain in the device model. Signed-off-by: Jan Kiszka Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index a0b0f36eb5..fb2b22d363 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -18,8 +18,6 @@ * along with this program; if not, see . */ -#include - #include "qemu-common.h" #include "qemu-timer.h" #include "qemu-queue.h" @@ -1212,10 +1210,6 @@ async_common: qxl_update_irq(d); break; case QXL_IO_NOTIFY_OOM: - if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) { - break; - } - pthread_yield(); if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) { break; } From 3bb781f3ed91bd3f085ded4d16f089e7b66f1076 Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Tue, 4 Oct 2011 13:25:53 +0200 Subject: [PATCH 07/11] ui/spice-core: fix segfault in monitor Fix segfault if a qxl device is present but no spice command line argument is given. RHBZ 743251. Signed-off-by: Alon Levy --- ui/spice-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/spice-core.c b/ui/spice-core.c index 4c06c36c31..be52356e63 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -445,7 +445,7 @@ void do_info_spice(Monitor *mon, QObject **ret_data) int port, tls_port; char version_string[20]; /* 12 = |255.255.255\0| is the max */ - if (!spice_server) { + if (!spice_server || !opts) { *ret_data = qobject_from_jsonf("{ 'enabled': false }"); return; } From 78e60ba53d5bf3c8b59aada8c22c1bd3aed3d344 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 17 Oct 2011 14:11:16 +0200 Subject: [PATCH 08/11] qxl: factor out properties Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index fb2b22d363..2ca1b04eb0 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -1781,6 +1781,19 @@ static VMStateDescription qxl_vmstate = { }, }; +static Property qxl_properties[] = { + DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, + 64 * 1024 * 1024), + DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, + 64 * 1024 * 1024), + DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, + QXL_DEFAULT_REVISION), + DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), + DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), + DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static PCIDeviceInfo qxl_info_primary = { .qdev.name = "qxl-vga", .qdev.desc = "Spice QXL GPU (primary, vga compatible)", @@ -1793,18 +1806,7 @@ static PCIDeviceInfo qxl_info_primary = { .vendor_id = REDHAT_PCI_VENDOR_ID, .device_id = QXL_DEVICE_ID_STABLE, .class_id = PCI_CLASS_DISPLAY_VGA, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, - 64 * 1024 * 1024), - DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, - 64 * 1024 * 1024), - DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, - QXL_DEFAULT_REVISION), - DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), - DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), - DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), - DEFINE_PROP_END_OF_LIST(), - } + .qdev.props = qxl_properties, }; static PCIDeviceInfo qxl_info_secondary = { @@ -1817,18 +1819,7 @@ static PCIDeviceInfo qxl_info_secondary = { .vendor_id = REDHAT_PCI_VENDOR_ID, .device_id = QXL_DEVICE_ID_STABLE, .class_id = PCI_CLASS_DISPLAY_OTHER, - .qdev.props = (Property[]) { - DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, - 64 * 1024 * 1024), - DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, - 64 * 1024 * 1024), - DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, - QXL_DEFAULT_REVISION), - DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), - DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), - DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), - DEFINE_PROP_END_OF_LIST(), - } + .qdev.props = qxl_properties, }; static void qxl_register(void) From 30f6da6656c94964ba8677928588592d9667007e Mon Sep 17 00:00:00 2001 From: Yonit Halperin Date: Tue, 18 Oct 2011 18:58:54 +0200 Subject: [PATCH 09/11] qxl: fix guest cursor tracking (1) If the guest cursor command is empty, don't reload it after migration. (2) Cleaning the guest cursor when it is released by the spice server. In addition, explicitly reset the cursor in spice upon destroying the primary surface (was done by spice-server implicitly). This will prevent access to pci memory that was released. RHBZ: 744518 Signed-off-by: Yonit Halperin Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/hw/qxl.c b/hw/qxl.c index 2ca1b04eb0..3a3b3a44ac 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -236,6 +236,9 @@ void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) void qxl_spice_reset_cursor(PCIQXLDevice *qxl) { qxl->ssd.worker->reset_cursor(qxl->ssd.worker); + qemu_mutex_lock(&qxl->track_lock); + qxl->guest_cursor = 0; + qemu_mutex_unlock(&qxl->track_lock); } @@ -400,7 +403,9 @@ static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) { QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); if (cmd->type == QXL_CURSOR_SET) { + qemu_mutex_lock(&qxl->track_lock); qxl->guest_cursor = ext->cmd.data; + qemu_mutex_unlock(&qxl->track_lock); } break; } @@ -1065,6 +1070,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) d->mode = QXL_MODE_UNDEFINED; qemu_spice_destroy_primary_surface(&d->ssd, 0, async); + qxl_spice_reset_cursor(d); return 1; } @@ -1704,10 +1710,12 @@ static int qxl_post_load(void *opaque, int version) cmds[out].group_id = MEMSLOT_GROUP_GUEST; out++; } - cmds[out].cmd.data = d->guest_cursor; - cmds[out].cmd.type = QXL_CMD_CURSOR; - cmds[out].group_id = MEMSLOT_GROUP_GUEST; - out++; + if (d->guest_cursor) { + cmds[out].cmd.data = d->guest_cursor; + cmds[out].cmd.type = QXL_CMD_CURSOR; + cmds[out].group_id = MEMSLOT_GROUP_GUEST; + out++; + } qxl_spice_loadvm_commands(d, cmds, out); g_free(cmds); From 9f0f352d8546f217780013dd35ab157d667195dd Mon Sep 17 00:00:00 2001 From: Alon Levy Date: Sun, 23 Oct 2011 17:03:52 +0200 Subject: [PATCH 10/11] qxl: reset update_surface update init_qxl_ram to reset update_surface to 0. This fixes one case of breakage when installing an old driver in a vm that had a new driver installed. The newer driver would know about surface creation and would change update_surface to !=0, then a reset would happen, all surfaces are destroyed, then the old driver is initialized and issues an UPDATE_AREA, and spice server aborts on invalid surface. RHBZ: 690427 Signed-off-by: Alon Levy Signed-off-by: Gerd Hoffmann --- hw/qxl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/qxl.c b/hw/qxl.c index 3a3b3a44ac..12f71aa56c 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -331,6 +331,7 @@ static void init_qxl_ram(PCIQXLDevice *d) d->ram->magic = cpu_to_le32(QXL_RAM_MAGIC); d->ram->int_pending = cpu_to_le32(0); d->ram->int_mask = cpu_to_le32(0); + d->ram->update_surface = 0; SPICE_RING_INIT(&d->ram->cmd_ring); SPICE_RING_INIT(&d->ram->cursor_ring); SPICE_RING_INIT(&d->ram->release_ring); From 08cc67f32ebe9b7dc3e1410f0678f198c092c0e7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 21 Oct 2011 15:56:21 +0200 Subject: [PATCH 11/11] spice: fix file handle cleanup Setting both read and write handlers to NULL in qemu_set_fd_handler is not enougth to make qemu purge the file handle from the list. We must set opaque to NULL too. Signed-off-by: Gerd Hoffmann --- ui/spice-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/spice-core.c b/ui/spice-core.c index be52356e63..6d3dab6960 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -133,7 +133,7 @@ static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void * static void watch_remove(SpiceWatch *watch) { - watch_update_mask(watch, 0); + qemu_set_fd_handler(watch->fd, NULL, NULL, NULL); QTAILQ_REMOVE(&watches, watch, next); g_free(watch); }