Merge remote-tracking branch 'spice/spice.v45' into staging
This commit is contained in:
commit
eca968d0d4
@ -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
|
||||
|
66
hw/qxl.c
66
hw/qxl.c
@ -18,8 +18,6 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#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)
|
||||
|
3
hw/qxl.h
3
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 */
|
||||
|
11
migration.c
11
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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -19,10 +19,10 @@
|
||||
#include <spice-experimental.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#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();
|
||||
|
Loading…
Reference in New Issue
Block a user