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/hw/qxl.c b/hw/qxl.c
index 03848edb75..12f71aa56c 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"
@@ -238,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);
}
@@ -330,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);
@@ -402,7 +404,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;
}
@@ -1067,6 +1071,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;
}
@@ -1212,10 +1217,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;
}
@@ -1372,7 +1373,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 +1392,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);
}
@@ -1710,10 +1711,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);
@@ -1787,6 +1790,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)",
@@ -1799,18 +1815,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 = {
@@ -1823,18 +1828,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)
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 */
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);
diff --git a/monitor.c b/monitor.c
index d13bd15209..ee53f7fcaf 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..6d3dab6960 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;
@@ -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);
}
@@ -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();
}
@@ -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)
@@ -413,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;
}
@@ -449,18 +481,39 @@ 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
}
}
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;
+#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;
}
static int add_channel(const char *name, const char *value, void *opaque)
@@ -503,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;
@@ -650,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();