mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-09-09 17:24:53 +00:00
qemu: Do not poll for spice migration status
QEMU_CAPS_SEAMLESS_MIGRATION capability says QEMU supports SPICE_MIGRATE_COMPLETED event. Thus we can just drop all code which polls query-spice and replace it with waiting for the event. Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
This commit is contained in:
parent
bfbbb78ca3
commit
2ad46e5b0e
@ -170,6 +170,7 @@ qemuDomainObjResetAsyncJob(qemuDomainObjPrivatePtr priv)
|
|||||||
job->mask = QEMU_JOB_DEFAULT_MASK;
|
job->mask = QEMU_JOB_DEFAULT_MASK;
|
||||||
job->dump_memory_only = false;
|
job->dump_memory_only = false;
|
||||||
job->abortJob = false;
|
job->abortJob = false;
|
||||||
|
job->spiceMigrated = false;
|
||||||
VIR_FREE(job->current);
|
VIR_FREE(job->current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +136,7 @@ struct qemuDomainJobObj {
|
|||||||
qemuDomainJobInfoPtr current; /* async job progress data */
|
qemuDomainJobInfoPtr current; /* async job progress data */
|
||||||
qemuDomainJobInfoPtr completed; /* statistics data of a recently completed job */
|
qemuDomainJobInfoPtr completed; /* statistics data of a recently completed job */
|
||||||
bool abortJob; /* abort of the job requested */
|
bool abortJob; /* abort of the job requested */
|
||||||
|
bool spiceMigrated; /* spice migration completed */
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*qemuDomainCleanupCallback)(virQEMUDriverPtr driver,
|
typedef void (*qemuDomainCleanupCallback)(virQEMUDriverPtr driver,
|
||||||
|
@ -2416,45 +2416,29 @@ qemuMigrationSetPinAll(virQEMUDriverPtr driver,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qemuMigrationWaitForSpice(virQEMUDriverPtr driver,
|
qemuMigrationWaitForSpice(virDomainObjPtr vm)
|
||||||
virDomainObjPtr vm)
|
|
||||||
{
|
{
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
bool wait_for_spice = false;
|
bool wait_for_spice = false;
|
||||||
bool spice_migrated = false;
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
int rc;
|
|
||||||
|
|
||||||
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_SEAMLESS_MIGRATION)) {
|
if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_SEAMLESS_MIGRATION))
|
||||||
for (i = 0; i < vm->def->ngraphics; i++) {
|
return 0;
|
||||||
if (vm->def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
|
|
||||||
wait_for_spice = true;
|
for (i = 0; i < vm->def->ngraphics; i++) {
|
||||||
break;
|
if (vm->def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
|
||||||
}
|
wait_for_spice = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wait_for_spice)
|
if (!wait_for_spice)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while (!spice_migrated) {
|
while (!priv->job.spiceMigrated && !priv->job.abortJob) {
|
||||||
/* Poll every 50ms for progress & to allow cancellation */
|
if (virDomainObjWait(vm) < 0)
|
||||||
struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };
|
|
||||||
|
|
||||||
if (qemuDomainObjEnterMonitorAsync(driver, vm,
|
|
||||||
QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
rc = qemuMonitorGetSpiceMigrationStatus(priv->mon, &spice_migrated);
|
|
||||||
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
|
||||||
return -1;
|
|
||||||
if (rc < 0)
|
|
||||||
return -1;
|
|
||||||
virObjectUnlock(vm);
|
|
||||||
nanosleep(&ts, NULL);
|
|
||||||
virObjectLock(vm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3680,7 +3664,7 @@ qemuMigrationConfirmPhase(virQEMUDriverPtr driver,
|
|||||||
if (retcode == 0) {
|
if (retcode == 0) {
|
||||||
/* If guest uses SPICE and supports seamless migration we have to hold
|
/* If guest uses SPICE and supports seamless migration we have to hold
|
||||||
* up domain shutdown until SPICE server transfers its data */
|
* up domain shutdown until SPICE server transfers its data */
|
||||||
qemuMigrationWaitForSpice(driver, vm);
|
qemuMigrationWaitForSpice(vm);
|
||||||
|
|
||||||
qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED,
|
qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED,
|
||||||
VIR_QEMU_PROCESS_STOP_MIGRATED);
|
VIR_QEMU_PROCESS_STOP_MIGRATED);
|
||||||
|
@ -2123,16 +2123,6 @@ qemuMonitorGetMigrationStatus(qemuMonitorPtr mon,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
qemuMonitorGetSpiceMigrationStatus(qemuMonitorPtr mon,
|
|
||||||
bool *spice_migrated)
|
|
||||||
{
|
|
||||||
QEMU_CHECK_MONITOR_JSON(mon);
|
|
||||||
|
|
||||||
return qemuMonitorJSONGetSpiceMigrationStatus(mon, spice_migrated);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
qemuMonitorMigrateToFd(qemuMonitorPtr mon,
|
qemuMonitorMigrateToFd(qemuMonitorPtr mon,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
|
@ -498,8 +498,6 @@ struct _qemuMonitorMigrationStatus {
|
|||||||
|
|
||||||
int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon,
|
int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon,
|
||||||
qemuMonitorMigrationStatusPtr status);
|
qemuMonitorMigrationStatusPtr status);
|
||||||
int qemuMonitorGetSpiceMigrationStatus(qemuMonitorPtr mon,
|
|
||||||
bool *spice_migrated);
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
QEMU_MONITOR_MIGRATION_CAPS_XBZRLE,
|
QEMU_MONITOR_MIGRATION_CAPS_XBZRLE,
|
||||||
|
@ -2684,55 +2684,6 @@ int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
qemuMonitorJSONSpiceGetMigrationStatusReply(virJSONValuePtr reply,
|
|
||||||
bool *spice_migrated)
|
|
||||||
{
|
|
||||||
virJSONValuePtr ret;
|
|
||||||
|
|
||||||
if (!(ret = virJSONValueObjectGet(reply, "return"))) {
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
||||||
_("query-spice reply was missing return data"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (virJSONValueObjectGetBoolean(ret, "migrated", spice_migrated) < 0) {
|
|
||||||
/* Deliberately don't report error here as we are
|
|
||||||
* probably dealing with older qemu which doesn't
|
|
||||||
* report this yet. Pretend spice is migrated. */
|
|
||||||
*spice_migrated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int qemuMonitorJSONGetSpiceMigrationStatus(qemuMonitorPtr mon,
|
|
||||||
bool *spice_migrated)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
virJSONValuePtr cmd = qemuMonitorJSONMakeCommand("query-spice",
|
|
||||||
NULL);
|
|
||||||
virJSONValuePtr reply = NULL;
|
|
||||||
|
|
||||||
if (!cmd)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
ret = qemuMonitorJSONCommand(mon, cmd, &reply);
|
|
||||||
|
|
||||||
if (ret == 0)
|
|
||||||
ret = qemuMonitorJSONCheckError(cmd, reply);
|
|
||||||
|
|
||||||
if (ret == 0)
|
|
||||||
ret = qemuMonitorJSONSpiceGetMigrationStatusReply(reply,
|
|
||||||
spice_migrated);
|
|
||||||
|
|
||||||
virJSONValueFree(cmd);
|
|
||||||
virJSONValueFree(reply);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
|
int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
const char *uri)
|
const char *uri)
|
||||||
|
@ -1481,6 +1481,33 @@ qemuProcessHandleSerialChanged(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
qemuProcessHandleSpiceMigrated(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
void *opaque ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
qemuDomainObjPrivatePtr priv;
|
||||||
|
|
||||||
|
virObjectLock(vm);
|
||||||
|
|
||||||
|
VIR_DEBUG("Spice migration completed for domain %p %s",
|
||||||
|
vm, vm->def->name);
|
||||||
|
|
||||||
|
priv = vm->privateData;
|
||||||
|
if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
|
||||||
|
VIR_DEBUG("got SPICE_MIGRATE_COMPLETED event without a migration job");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->job.spiceMigrated = true;
|
||||||
|
virDomainObjSignal(vm);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virObjectUnlock(vm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static qemuMonitorCallbacks monitorCallbacks = {
|
static qemuMonitorCallbacks monitorCallbacks = {
|
||||||
.eofNotify = qemuProcessHandleMonitorEOF,
|
.eofNotify = qemuProcessHandleMonitorEOF,
|
||||||
.errorNotify = qemuProcessHandleMonitorError,
|
.errorNotify = qemuProcessHandleMonitorError,
|
||||||
@ -1504,6 +1531,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
|
|||||||
.domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
|
.domainDeviceDeleted = qemuProcessHandleDeviceDeleted,
|
||||||
.domainNicRxFilterChanged = qemuProcessHandleNicRxFilterChanged,
|
.domainNicRxFilterChanged = qemuProcessHandleNicRxFilterChanged,
|
||||||
.domainSerialChange = qemuProcessHandleSerialChanged,
|
.domainSerialChange = qemuProcessHandleSerialChanged,
|
||||||
|
.domainSpiceMigrated = qemuProcessHandleSpiceMigrated,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1705,45 +1705,6 @@ testQemuMonitorJSONqemuMonitorJSONGetMigrationStatus(const void *data)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
testQemuMonitorJSONqemuMonitorJSONGetSpiceMigrationStatus(const void *data)
|
|
||||||
{
|
|
||||||
virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
|
|
||||||
qemuMonitorTestPtr test = qemuMonitorTestNewSimple(true, xmlopt);
|
|
||||||
int ret = -1;
|
|
||||||
bool spiceMigrated;
|
|
||||||
|
|
||||||
if (!test)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (qemuMonitorTestAddItem(test, "query-spice",
|
|
||||||
"{"
|
|
||||||
" \"return\": {"
|
|
||||||
" \"migrated\": true,"
|
|
||||||
" \"enabled\": false,"
|
|
||||||
" \"mouse-mode\": \"client\""
|
|
||||||
" },"
|
|
||||||
" \"id\": \"libvirt-14\""
|
|
||||||
"}") < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (qemuMonitorJSONGetSpiceMigrationStatus(qemuMonitorTestGetMonitor(test),
|
|
||||||
&spiceMigrated) < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (!spiceMigrated) {
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
||||||
"Invalid spice migration status: %d, expecting 1",
|
|
||||||
spiceMigrated);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
cleanup:
|
|
||||||
qemuMonitorTestFree(test);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
testHashEqualChardevInfo(const void *value1, const void *value2)
|
testHashEqualChardevInfo(const void *value1, const void *value2)
|
||||||
{
|
{
|
||||||
@ -2400,7 +2361,6 @@ mymain(void)
|
|||||||
DO_TEST(qemuMonitorJSONGetBlockStatsInfo);
|
DO_TEST(qemuMonitorJSONGetBlockStatsInfo);
|
||||||
DO_TEST(qemuMonitorJSONGetMigrationCacheSize);
|
DO_TEST(qemuMonitorJSONGetMigrationCacheSize);
|
||||||
DO_TEST(qemuMonitorJSONGetMigrationStatus);
|
DO_TEST(qemuMonitorJSONGetMigrationStatus);
|
||||||
DO_TEST(qemuMonitorJSONGetSpiceMigrationStatus);
|
|
||||||
DO_TEST(qemuMonitorJSONGetChardevInfo);
|
DO_TEST(qemuMonitorJSONGetChardevInfo);
|
||||||
DO_TEST(qemuMonitorJSONSetBlockIoThrottle);
|
DO_TEST(qemuMonitorJSONSetBlockIoThrottle);
|
||||||
DO_TEST(qemuMonitorJSONGetTargetArch);
|
DO_TEST(qemuMonitorJSONGetTargetArch);
|
||||||
|
Loading…
Reference in New Issue
Block a user