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(a)redhat.com>
---
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 bbea2f6e0e..385bd91a6b 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5839,111 +5839,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) {
@@ -5960,7 +5887,7 @@ qemuMigrationDstFinish(virQEMUDriver *driver,
* to restart during confirm() step, so we kill it off now.
*/
if (v3proto)
- goto error;
+ return -1;
}
}
@@ -5974,7 +5901,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
@@ -5983,16 +5910,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,
@@ -6006,11 +5933,11 @@ qemuMigrationDstFinish(virQEMUDriver *driver,
* things up.
*/
if (v3proto)
- goto error;
+ return -1;
}
- if (inPostCopy)
- doKill = false;
+ if (*inPostCopy)
+ *doKill = false;
}
if (mig->jobData) {
@@ -6025,11 +5952,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) {
@@ -6039,6 +5966,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,
@@ -6048,12 +6075,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