diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 48e0d44a41be83d2f7396fe8419099623bf1507f..7d3b1859f39eafbeb2077172b385593b066a5c06 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1592,6 +1592,40 @@ cleanup: return ret; } +static int +qemuMigrationWaitForSpice(virQEMUDriverPtr driver, + virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + bool wait_for_spice = false; + bool spice_migrated = false; + + if (vm->def->ngraphics == 1 && + vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE && + virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_SEAMLESS_MIGRATION)) + wait_for_spice = true; + + if (!wait_for_spice) + return 0; + + while (!spice_migrated) { + /* Poll every 50ms for progress & to allow cancellation */ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull }; + + qemuDomainObjEnterMonitor(driver, vm); + if (qemuMonitorGetSpiceMigrationStatus(priv->mon, + &spice_migrated) < 0) { + qemuDomainObjExitMonitor(driver, vm); + return -1; + } + qemuDomainObjExitMonitor(driver, vm); + virObjectUnlock(vm); + nanosleep(&ts, NULL); + virObjectLock(vm); + } + + return 0; +} static int qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver, @@ -1601,19 +1635,10 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver, { qemuDomainObjPrivatePtr priv = vm->privateData; int ret; - bool wait_for_spice = false; - bool spice_migrated = false; qemuMonitorMigrationStatus status; memset(&status, 0, sizeof(status)); - /* If guest uses SPICE and supports seamles_migration we have to hold up - * migration finish until SPICE server transfers its data */ - if (vm->def->ngraphics == 1 && - vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE && - virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_SEAMLESS_MIGRATION)) - wait_for_spice = true; - ret = qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob); if (ret < 0) { /* Guest already exited; nothing further to update. */ @@ -1621,13 +1646,6 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver, } ret = qemuMonitorGetMigrationStatus(priv->mon, &status); - /* If qemu says migrated, check spice */ - if (wait_for_spice && - ret == 0 && - status.status == QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) - ret = qemuMonitorGetSpiceMigrationStatus(priv->mon, - &spice_migrated); - qemuDomainObjExitMonitor(driver, vm); priv->job.status = status; @@ -1667,8 +1685,7 @@ qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver, break; case QEMU_MONITOR_MIGRATION_STATUS_COMPLETED: - if ((wait_for_spice && spice_migrated) || (!wait_for_spice)) - priv->job.info.type = VIR_DOMAIN_JOB_COMPLETED; + priv->job.info.type = VIR_DOMAIN_JOB_COMPLETED; ret = 0; break; @@ -4151,6 +4168,10 @@ int qemuMigrationConfirm(virQEMUDriverPtr driver, * domain object, but if no, resume CPUs */ if (retcode == 0) { + /* If guest uses SPICE and supports seamless migration we have to hold + * up domain shutdown until SPICE server transfers its data */ + qemuMigrationWaitForSpice(driver, vm); + qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_MIGRATED, VIR_QEMU_PROCESS_STOP_MIGRATED); virDomainAuditStop(vm, "migrated");