mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-09 14:35:25 +00:00
qemu: Introduce qemuMigrationDstFinishFresh
Refactors qemuMigrationDstFinish by moving some parts to a dedicated function for easier introduction of postcopy resume code without duplicating common parts of the Finish phase. The goal is to have the following call graph: - qemuMigrationDstFinish - qemuMigrationDstFinishOffline - qemuMigrationDstFinishActive - qemuMigrationDstFinishFresh - qemuMigrationDstFinishResume Signed-off-by: Jiri Denemark <jdenemar@redhat.com> Reviewed-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
This commit is contained in:
parent
3865596cf9
commit
8ede853a9f
@ -5808,6 +5808,137 @@ qemuMigrationDstComplete(virQEMUDriver *driver,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform Finish phase of a fresh (i.e., not recovery) migration of an active
|
||||||
|
* domain.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
qemuMigrationDstFinishFresh(virQEMUDriver *driver,
|
||||||
|
virDomainObj *vm,
|
||||||
|
qemuMigrationCookie *mig,
|
||||||
|
unsigned long flags,
|
||||||
|
bool v3proto,
|
||||||
|
unsigned long long timeReceived,
|
||||||
|
bool *doKill,
|
||||||
|
bool *inPostCopy)
|
||||||
|
{
|
||||||
|
qemuDomainObjPrivate *priv = vm->privateData;
|
||||||
|
g_autoptr(virDomainJobData) jobData = NULL;
|
||||||
|
|
||||||
|
if (qemuMigrationDstVPAssociatePortProfiles(vm->def) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (mig->network && qemuMigrationDstOPDRelocate(driver, vm, mig) < 0)
|
||||||
|
VIR_WARN("unable to provide network data for relocation");
|
||||||
|
|
||||||
|
if (qemuMigrationDstStopNBDServer(driver, vm, mig) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (qemuRefreshVirtioChannelState(driver, vm,
|
||||||
|
VIR_ASYNC_JOB_MIGRATION_IN) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (qemuConnectAgent(driver, vm) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (flags & VIR_MIGRATE_PERSIST_DEST) {
|
||||||
|
if (qemuMigrationDstPersist(driver, vm, mig, !v3proto) < 0) {
|
||||||
|
/* Hmpf. Migration was successful, but making it persistent
|
||||||
|
* was not. If we report successful, then when this domain
|
||||||
|
* shuts down, management tools are in for a surprise. On the
|
||||||
|
* other hand, if we report failure, then the management tools
|
||||||
|
* might try to restart the domain on the source side, even
|
||||||
|
* though the domain is actually running on the destination.
|
||||||
|
* Pretend success and hope that this is a rare situation and
|
||||||
|
* management tools are smart.
|
||||||
|
*
|
||||||
|
* However, in v3 protocol, the source VM is still available
|
||||||
|
* to restart during confirm() step, so we kill it off now.
|
||||||
|
*/
|
||||||
|
if (v3proto)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to wait for QEMU to process all data sent by the source
|
||||||
|
* before starting guest CPUs.
|
||||||
|
*/
|
||||||
|
if (qemuMigrationDstWaitForCompletion(driver, vm,
|
||||||
|
VIR_ASYNC_JOB_MIGRATION_IN,
|
||||||
|
!!(flags & VIR_MIGRATE_POSTCOPY)) < 0) {
|
||||||
|
/* There's not much we can do for v2 protocol since the
|
||||||
|
* original domain on the source host is already gone.
|
||||||
|
*/
|
||||||
|
if (v3proto)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now that the state data was transferred we can refresh the actual state
|
||||||
|
* of the devices */
|
||||||
|
if (qemuProcessRefreshState(driver, vm, VIR_ASYNC_JOB_MIGRATION_IN) < 0) {
|
||||||
|
/* Similarly to the case above v2 protocol will not be able to recover
|
||||||
|
* from this. Let's ignore this and perhaps stuff will not break. */
|
||||||
|
if (v3proto)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->job.current->status == VIR_DOMAIN_JOB_STATUS_POSTCOPY)
|
||||||
|
*inPostCopy = true;
|
||||||
|
|
||||||
|
if (!(flags & VIR_MIGRATE_PAUSED)) {
|
||||||
|
if (qemuProcessStartCPUs(driver, vm,
|
||||||
|
*inPostCopy ? VIR_DOMAIN_RUNNING_POSTCOPY
|
||||||
|
: VIR_DOMAIN_RUNNING_MIGRATED,
|
||||||
|
VIR_ASYNC_JOB_MIGRATION_IN) < 0) {
|
||||||
|
if (virGetLastErrorCode() == VIR_ERR_OK)
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("resume operation failed"));
|
||||||
|
/*
|
||||||
|
* In v3 protocol, the source VM is still available to
|
||||||
|
* restart during confirm() step, so we kill it off
|
||||||
|
* now.
|
||||||
|
* In v2 protocol, the source is dead, so we leave
|
||||||
|
* target in paused state, in case admin can fix
|
||||||
|
* things up.
|
||||||
|
*/
|
||||||
|
if (v3proto)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*inPostCopy)
|
||||||
|
*doKill = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mig->jobData) {
|
||||||
|
jobData = g_steal_pointer(&mig->jobData);
|
||||||
|
|
||||||
|
if (jobData->sent && timeReceived) {
|
||||||
|
jobData->timeDelta = timeReceived - jobData->sent;
|
||||||
|
jobData->received = timeReceived;
|
||||||
|
jobData->timeDeltaSet = true;
|
||||||
|
}
|
||||||
|
qemuDomainJobDataUpdateTime(jobData);
|
||||||
|
qemuDomainJobDataUpdateDowntime(jobData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*inPostCopy &&
|
||||||
|
qemuMigrationDstWaitForCompletion(driver, vm,
|
||||||
|
VIR_ASYNC_JOB_MIGRATION_IN,
|
||||||
|
false) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobData) {
|
||||||
|
priv->job.completed = g_steal_pointer(&jobData);
|
||||||
|
priv->job.completed->status = VIR_DOMAIN_JOB_STATUS_COMPLETED;
|
||||||
|
qemuDomainJobSetStatsType(priv->job.completed,
|
||||||
|
QEMU_DOMAIN_JOB_STATS_TYPE_MIGRATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
virDomainPtr
|
virDomainPtr
|
||||||
qemuMigrationDstFinish(virQEMUDriver *driver,
|
qemuMigrationDstFinish(virQEMUDriver *driver,
|
||||||
virConnectPtr dconn,
|
virConnectPtr dconn,
|
||||||
@ -5829,9 +5960,9 @@ qemuMigrationDstFinish(virQEMUDriver *driver,
|
|||||||
unsigned short port;
|
unsigned short port;
|
||||||
unsigned long long timeReceived = 0;
|
unsigned long long timeReceived = 0;
|
||||||
virObjectEvent *event;
|
virObjectEvent *event;
|
||||||
virDomainJobData *jobData = NULL;
|
|
||||||
bool inPostCopy = false;
|
bool inPostCopy = false;
|
||||||
bool doKill = true;
|
bool doKill = true;
|
||||||
|
int rc;
|
||||||
|
|
||||||
VIR_DEBUG("driver=%p, dconn=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
|
VIR_DEBUG("driver=%p, dconn=%p, vm=%p, cookiein=%s, cookieinlen=%d, "
|
||||||
"cookieout=%p, cookieoutlen=%p, flags=0x%lx, retcode=%d",
|
"cookieout=%p, cookieoutlen=%p, flags=0x%lx, retcode=%d",
|
||||||
@ -5898,116 +6029,12 @@ qemuMigrationDstFinish(virQEMUDriver *driver,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qemuMigrationDstVPAssociatePortProfiles(vm->def) < 0)
|
rc = qemuMigrationDstFinishFresh(driver, vm, mig, flags, v3proto,
|
||||||
|
timeReceived, &doKill, &inPostCopy);
|
||||||
|
if (rc < 0 ||
|
||||||
|
!(dom = virGetDomain(dconn, vm->def->name, vm->def->uuid, vm->def->id)))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (mig->network && qemuMigrationDstOPDRelocate(driver, vm, mig) < 0)
|
|
||||||
VIR_WARN("unable to provide network data for relocation");
|
|
||||||
|
|
||||||
if (qemuMigrationDstStopNBDServer(driver, vm, mig) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (qemuRefreshVirtioChannelState(driver, vm,
|
|
||||||
VIR_ASYNC_JOB_MIGRATION_IN) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (qemuConnectAgent(driver, vm) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (flags & VIR_MIGRATE_PERSIST_DEST) {
|
|
||||||
if (qemuMigrationDstPersist(driver, vm, mig, !v3proto) < 0) {
|
|
||||||
/* Hmpf. Migration was successful, but making it persistent
|
|
||||||
* was not. If we report successful, then when this domain
|
|
||||||
* shuts down, management tools are in for a surprise. On the
|
|
||||||
* other hand, if we report failure, then the management tools
|
|
||||||
* might try to restart the domain on the source side, even
|
|
||||||
* though the domain is actually running on the destination.
|
|
||||||
* Pretend success and hope that this is a rare situation and
|
|
||||||
* management tools are smart.
|
|
||||||
*
|
|
||||||
* However, in v3 protocol, the source VM is still available
|
|
||||||
* to restart during confirm() step, so we kill it off now.
|
|
||||||
*/
|
|
||||||
if (v3proto)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We need to wait for QEMU to process all data sent by the source
|
|
||||||
* before starting guest CPUs.
|
|
||||||
*/
|
|
||||||
if (qemuMigrationDstWaitForCompletion(driver, vm,
|
|
||||||
VIR_ASYNC_JOB_MIGRATION_IN,
|
|
||||||
!!(flags & VIR_MIGRATE_POSTCOPY)) < 0) {
|
|
||||||
/* There's not much we can do for v2 protocol since the
|
|
||||||
* original domain on the source host is already gone.
|
|
||||||
*/
|
|
||||||
if (v3proto)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now that the state data was transferred we can refresh the actual state
|
|
||||||
* of the devices */
|
|
||||||
if (qemuProcessRefreshState(driver, vm, VIR_ASYNC_JOB_MIGRATION_IN) < 0) {
|
|
||||||
/* Similarly to the case above v2 protocol will not be able to recover
|
|
||||||
* from this. Let's ignore this and perhaps stuff will not break. */
|
|
||||||
if (v3proto)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->job.current->status == VIR_DOMAIN_JOB_STATUS_POSTCOPY)
|
|
||||||
inPostCopy = true;
|
|
||||||
|
|
||||||
if (!(flags & VIR_MIGRATE_PAUSED)) {
|
|
||||||
if (qemuProcessStartCPUs(driver, vm,
|
|
||||||
inPostCopy ? VIR_DOMAIN_RUNNING_POSTCOPY
|
|
||||||
: VIR_DOMAIN_RUNNING_MIGRATED,
|
|
||||||
VIR_ASYNC_JOB_MIGRATION_IN) < 0) {
|
|
||||||
if (virGetLastErrorCode() == VIR_ERR_OK)
|
|
||||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
||||||
"%s", _("resume operation failed"));
|
|
||||||
/*
|
|
||||||
* In v3 protocol, the source VM is still available to
|
|
||||||
* restart during confirm() step, so we kill it off
|
|
||||||
* now.
|
|
||||||
* In v2 protocol, the source is dead, so we leave
|
|
||||||
* target in paused state, in case admin can fix
|
|
||||||
* things up.
|
|
||||||
*/
|
|
||||||
if (v3proto)
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inPostCopy)
|
|
||||||
doKill = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mig->jobData) {
|
|
||||||
jobData = g_steal_pointer(&mig->jobData);
|
|
||||||
|
|
||||||
if (jobData->sent && timeReceived) {
|
|
||||||
jobData->timeDelta = timeReceived - jobData->sent;
|
|
||||||
jobData->received = timeReceived;
|
|
||||||
jobData->timeDeltaSet = true;
|
|
||||||
}
|
|
||||||
qemuDomainJobDataUpdateTime(jobData);
|
|
||||||
qemuDomainJobDataUpdateDowntime(jobData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inPostCopy &&
|
|
||||||
qemuMigrationDstWaitForCompletion(driver, vm,
|
|
||||||
VIR_ASYNC_JOB_MIGRATION_IN,
|
|
||||||
false) < 0) {
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jobData) {
|
|
||||||
priv->job.completed = g_steal_pointer(&jobData);
|
|
||||||
priv->job.completed->status = VIR_DOMAIN_JOB_STATUS_COMPLETED;
|
|
||||||
qemuDomainJobSetStatsType(priv->job.completed,
|
|
||||||
QEMU_DOMAIN_JOB_STATS_TYPE_MIGRATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qemuMigrationCookieFormat(mig, driver, vm,
|
if (qemuMigrationCookieFormat(mig, driver, vm,
|
||||||
QEMU_MIGRATION_DESTINATION,
|
QEMU_MIGRATION_DESTINATION,
|
||||||
cookieout, cookieoutlen,
|
cookieout, cookieoutlen,
|
||||||
@ -6017,12 +6044,9 @@ qemuMigrationDstFinish(virQEMUDriver *driver,
|
|||||||
qemuMigrationDstComplete(driver, vm, inPostCopy,
|
qemuMigrationDstComplete(driver, vm, inPostCopy,
|
||||||
VIR_ASYNC_JOB_MIGRATION_IN);
|
VIR_ASYNC_JOB_MIGRATION_IN);
|
||||||
|
|
||||||
dom = virGetDomain(dconn, vm->def->name, vm->def->uuid, vm->def->id);
|
|
||||||
|
|
||||||
qemuMigrationJobFinish(vm);
|
qemuMigrationJobFinish(vm);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
g_clear_pointer(&jobData, virDomainJobDataFree);
|
|
||||||
virPortAllocatorRelease(port);
|
virPortAllocatorRelease(port);
|
||||||
if (priv->mon)
|
if (priv->mon)
|
||||||
qemuMonitorSetDomainLog(priv->mon, NULL, NULL, NULL);
|
qemuMonitorSetDomainLog(priv->mon, NULL, NULL, NULL);
|
||||||
|
Loading…
Reference in New Issue
Block a user