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@xxxxxxxxxx> Reviewed-by: Peter Krempa <pkrempa@xxxxxxxxxx> Reviewed-by: Pavel Hrdina <phrdina@xxxxxxxxxx> --- Notes: Version 2: - no change src/qemu/qemu_migration.c | 234 +++++++++++++++++++++----------------- 1 file changed, 129 insertions(+), 105 deletions(-) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 10c4f7a470..72f22f09e4 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -5808,111 +5808,38 @@ qemuMigrationDstComplete(virQEMUDriver *driver, } -virDomainPtr -qemuMigrationDstFinish(virQEMUDriver *driver, - virConnectPtr dconn, - virDomainObj *vm, - const char *cookiein, - int cookieinlen, - char **cookieout, - int *cookieoutlen, - unsigned long flags, - int retcode, - bool v3proto) +/* + * 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) { - virDomainPtr dom = NULL; - g_autoptr(qemuMigrationCookie) mig = NULL; - virErrorPtr orig_err = NULL; - int cookie_flags = 0; qemuDomainObjPrivate *priv = vm->privateData; - qemuDomainJobPrivate *jobPriv = priv->job.privateData; - unsigned short port; - unsigned long long timeReceived = 0; - virObjectEvent *event; - virDomainJobData *jobData = NULL; - bool inPostCopy = false; - bool doKill = true; - - VIR_DEBUG("driver=%p, dconn=%p, vm=%p, cookiein=%s, cookieinlen=%d, " - "cookieout=%p, cookieoutlen=%p, flags=0x%lx, retcode=%d", - driver, dconn, vm, NULLSTR(cookiein), cookieinlen, - cookieout, cookieoutlen, flags, retcode); - - port = priv->migrationPort; - priv->migrationPort = 0; - - if (!qemuMigrationJobIsActive(vm, VIR_ASYNC_JOB_MIGRATION_IN)) { - qemuMigrationDstErrorReport(driver, vm->def->name); - goto cleanup; - } - - ignore_value(virTimeMillisNow(&timeReceived)); - - qemuMigrationJobStartPhase(vm, - v3proto ? QEMU_MIGRATION_PHASE_FINISH3 - : QEMU_MIGRATION_PHASE_FINISH2); - - qemuDomainCleanupRemove(vm, qemuMigrationDstPrepareCleanup); - g_clear_pointer(&priv->job.completed, virDomainJobDataFree); - - cookie_flags = QEMU_MIGRATION_COOKIE_NETWORK | - QEMU_MIGRATION_COOKIE_STATS | - QEMU_MIGRATION_COOKIE_NBD; - /* Some older versions of libvirt always send persistent XML in the cookie - * even though VIR_MIGRATE_PERSIST_DEST was not used. */ - cookie_flags |= QEMU_MIGRATION_COOKIE_PERSISTENT; - - if (!(mig = qemuMigrationCookieParse(driver, vm->def, priv->origname, priv, - cookiein, cookieinlen, cookie_flags))) - goto error; - - if (flags & VIR_MIGRATE_OFFLINE) { - if (retcode == 0 && - qemuMigrationDstPersist(driver, vm, mig, false) == 0) { - dom = virGetDomain(dconn, vm->def->name, vm->def->uuid, -1); - - if (dom && - qemuMigrationCookieFormat(mig, driver, vm, - QEMU_MIGRATION_DESTINATION, - cookieout, cookieoutlen, - QEMU_MIGRATION_COOKIE_STATS) < 0) - VIR_WARN("Unable to encode migration cookie"); - } - - qemuMigrationJobFinish(vm); - goto cleanup; - } - - if (retcode != 0) { - /* Check for a possible error on the monitor in case Finish was called - * earlier than monitor EOF handler got a chance to process the error - */ - qemuDomainCheckMonitor(driver, vm, VIR_ASYNC_JOB_MIGRATION_IN); - goto error; - } - - if (!virDomainObjIsActive(vm)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("guest unexpectedly quit")); - qemuMigrationDstErrorReport(driver, vm->def->name); - goto error; - } + g_autoptr(virDomainJobData) jobData = NULL; if (qemuMigrationDstVPAssociatePortProfiles(vm->def) < 0) - goto error; + 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) - goto error; + return -1; if (qemuRefreshVirtioChannelState(driver, vm, VIR_ASYNC_JOB_MIGRATION_IN) < 0) - goto error; + return -1; if (qemuConnectAgent(driver, vm) < 0) - goto error; + return -1; if (flags & VIR_MIGRATE_PERSIST_DEST) { if (qemuMigrationDstPersist(driver, vm, mig, !v3proto) < 0) { @@ -5929,7 +5856,7 @@ qemuMigrationDstFinish(virQEMUDriver *driver, * to restart during confirm() step, so we kill it off now. */ if (v3proto) - goto error; + return -1; } } @@ -5943,7 +5870,7 @@ qemuMigrationDstFinish(virQEMUDriver *driver, * original domain on the source host is already gone. */ if (v3proto) - goto error; + return -1; } /* Now that the state data was transferred we can refresh the actual state @@ -5952,16 +5879,16 @@ qemuMigrationDstFinish(virQEMUDriver *driver, /* 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; + return -1; } if (priv->job.current->status == VIR_DOMAIN_JOB_STATUS_POSTCOPY) - inPostCopy = true; + *inPostCopy = true; if (!(flags & VIR_MIGRATE_PAUSED)) { if (qemuProcessStartCPUs(driver, vm, - inPostCopy ? VIR_DOMAIN_RUNNING_POSTCOPY - : VIR_DOMAIN_RUNNING_MIGRATED, + *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, @@ -5975,11 +5902,11 @@ qemuMigrationDstFinish(virQEMUDriver *driver, * things up. */ if (v3proto) - goto error; + return -1; } - if (inPostCopy) - doKill = false; + if (*inPostCopy) + *doKill = false; } if (mig->jobData) { @@ -5994,11 +5921,11 @@ qemuMigrationDstFinish(virQEMUDriver *driver, qemuDomainJobDataUpdateDowntime(jobData); } - if (inPostCopy && + if (*inPostCopy && qemuMigrationDstWaitForCompletion(driver, vm, VIR_ASYNC_JOB_MIGRATION_IN, false) < 0) { - goto error; + return -1; } if (jobData) { @@ -6008,6 +5935,106 @@ qemuMigrationDstFinish(virQEMUDriver *driver, QEMU_DOMAIN_JOB_STATS_TYPE_MIGRATION); } + return 0; +} + + +virDomainPtr +qemuMigrationDstFinish(virQEMUDriver *driver, + virConnectPtr dconn, + virDomainObj *vm, + const char *cookiein, + int cookieinlen, + char **cookieout, + int *cookieoutlen, + unsigned long flags, + int retcode, + bool v3proto) +{ + virDomainPtr dom = NULL; + g_autoptr(qemuMigrationCookie) mig = NULL; + virErrorPtr orig_err = NULL; + int cookie_flags = 0; + qemuDomainObjPrivate *priv = vm->privateData; + qemuDomainJobPrivate *jobPriv = priv->job.privateData; + unsigned short port; + unsigned long long timeReceived = 0; + virObjectEvent *event; + bool inPostCopy = false; + bool doKill = true; + int rc; + + VIR_DEBUG("driver=%p, dconn=%p, vm=%p, cookiein=%s, cookieinlen=%d, " + "cookieout=%p, cookieoutlen=%p, flags=0x%lx, retcode=%d", + driver, dconn, vm, NULLSTR(cookiein), cookieinlen, + cookieout, cookieoutlen, flags, retcode); + + port = priv->migrationPort; + priv->migrationPort = 0; + + if (!qemuMigrationJobIsActive(vm, VIR_ASYNC_JOB_MIGRATION_IN)) { + qemuMigrationDstErrorReport(driver, vm->def->name); + goto cleanup; + } + + ignore_value(virTimeMillisNow(&timeReceived)); + + qemuMigrationJobStartPhase(vm, + v3proto ? QEMU_MIGRATION_PHASE_FINISH3 + : QEMU_MIGRATION_PHASE_FINISH2); + + qemuDomainCleanupRemove(vm, qemuMigrationDstPrepareCleanup); + g_clear_pointer(&priv->job.completed, virDomainJobDataFree); + + cookie_flags = QEMU_MIGRATION_COOKIE_NETWORK | + QEMU_MIGRATION_COOKIE_STATS | + QEMU_MIGRATION_COOKIE_NBD; + /* Some older versions of libvirt always send persistent XML in the cookie + * even though VIR_MIGRATE_PERSIST_DEST was not used. */ + cookie_flags |= QEMU_MIGRATION_COOKIE_PERSISTENT; + + if (!(mig = qemuMigrationCookieParse(driver, vm->def, priv->origname, priv, + cookiein, cookieinlen, cookie_flags))) + goto error; + + if (flags & VIR_MIGRATE_OFFLINE) { + if (retcode == 0 && + qemuMigrationDstPersist(driver, vm, mig, false) == 0) { + dom = virGetDomain(dconn, vm->def->name, vm->def->uuid, -1); + + if (dom && + qemuMigrationCookieFormat(mig, driver, vm, + QEMU_MIGRATION_DESTINATION, + cookieout, cookieoutlen, + QEMU_MIGRATION_COOKIE_STATS) < 0) + VIR_WARN("Unable to encode migration cookie"); + } + + qemuMigrationJobFinish(vm); + goto cleanup; + } + + if (retcode != 0) { + /* Check for a possible error on the monitor in case Finish was called + * earlier than monitor EOF handler got a chance to process the error + */ + qemuDomainCheckMonitor(driver, vm, VIR_ASYNC_JOB_MIGRATION_IN); + goto error; + } + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("guest unexpectedly quit")); + qemuMigrationDstErrorReport(driver, vm->def->name); + goto error; + } + + 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; + if (qemuMigrationCookieFormat(mig, driver, vm, QEMU_MIGRATION_DESTINATION, cookieout, cookieoutlen, @@ -6017,12 +6044,9 @@ qemuMigrationDstFinish(virQEMUDriver *driver, qemuMigrationDstComplete(driver, vm, inPostCopy, VIR_ASYNC_JOB_MIGRATION_IN); - dom = virGetDomain(dconn, vm->def->name, vm->def->uuid, vm->def->id); - qemuMigrationJobFinish(vm); cleanup: - g_clear_pointer(&jobData, virDomainJobDataFree); virPortAllocatorRelease(port); if (priv->mon) qemuMonitorSetDomainLog(priv->mon, NULL, NULL, NULL); -- 2.35.1