Traditionally, we pass incoming migration URI on QEMU command line,
which has some drawbacks. Depending on the URI QEMU may initialize its
migration state immediately without giving us a chance to set any
additional migration parameters (this applies mainly for fd: URIs). For
some URIs the monitor may be completely blocked from the beginning until
migration is finished, which means we may be stuck in qmp_capabilities
command without being able to send any QMP commands.
QEMU solved this by introducing "defer" parameter for -incoming command
line option. This will tell QEMU to prepare for an incoming migration
while the actual incoming URI is sent using migrate-incoming QMP
command. Before calling this command we can normally talk to the
monitor and even set any migration parameters which will be honored by
the incoming migration.
Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
src/qemu/qemu_capabilities.c | 3 +++
src/qemu/qemu_capabilities.h | 3 +++
src/qemu/qemu_migration.c | 36 ++++++++++++++++++++++++++++
src/qemu/qemu_migration.h | 5 ++++
src/qemu/qemu_process.c | 12 ++++++++++
src/qemu/qemu_process.h | 1 +
tests/qemucapabilitiesdata/caps_2.4.0-1.caps | 1 +
7 files changed, 61 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 7475298..2813212 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -299,6 +299,8 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
"e1000",
"virtio-net",
"gic-version",
+
+ "incoming-defer", /* 200 */
);
@@ -1458,6 +1460,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = {
{ "nbd-server-start", QEMU_CAPS_NBD_SERVER },
{ "change-backing-file", QEMU_CAPS_CHANGE_BACKING_FILE },
{ "rtc-reset-reinjection", QEMU_CAPS_RTC_RESET_REINJECTION },
+ { "migrate-incoming", QEMU_CAPS_INCOMING_DEFER },
};
struct virQEMUCapsStringFlags virQEMUCapsMigration[] = {
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 14541f6..e3e40e5 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -325,6 +325,9 @@ typedef enum {
QEMU_CAPS_DEVICE_VIRTIO_NET, /* -device virtio-net-* */
QEMU_CAPS_MACH_VIRT_GIC_VERSION, /* -machine virt,gic-version */
+ /* 200 */
+ QEMU_CAPS_INCOMING_DEFER, /* -incoming defer and migrate_incoming */
+
QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags;
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 4d5b966..0c4c94a 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -2951,6 +2951,42 @@ qemuMigrationIncomingURI(const char *migrateFrom,
}
+int
+qemuMigrationRunIncoming(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ const char *uri,
+ qemuDomainAsyncJob asyncJob)
+{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ int ret = -1;
+ int rv;
+
+ VIR_DEBUG("Setting up incoming migration with URI %s", uri);
+
+ if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
+ return -1;
+
+ rv = qemuMonitorMigrateIncoming(priv->mon, uri);
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0 || rv < 0)
+ goto cleanup;
+
+ if (asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
+ /* qemuMigrationWaitForDestCompletion is called from the Finish phase */
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (qemuMigrationWaitForDestCompletion(driver, vm, asyncJob) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ return ret;
+}
+
+
/* This is called for outgoing non-p2p migrations when a connection to the
* client which initiated the migration was closed but we were waiting for it
* to follow up with the next phase, that is, in between
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index ff4fe30..2445e13 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -205,4 +205,9 @@ int qemuMigrationCheckIncoming(virQEMUCapsPtr qemuCaps,
char *qemuMigrationIncomingURI(const char *migrateFrom,
int migrateFd);
+int qemuMigrationRunIncoming(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ const char *uri,
+ qemuDomainAsyncJob asyncJob);
+
#endif /* __QEMU_MIGRATION_H__ */
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index f85e876..3f236d4 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4168,6 +4168,7 @@ qemuProcessIncomingDefFree(qemuProcessIncomingDefPtr inc)
return;
VIR_FREE(inc->launchURI);
+ VIR_FREE(inc->deferredURI);
VIR_FREE(inc);
}
@@ -4190,6 +4191,12 @@ qemuProcessIncomingDefNew(virQEMUCapsPtr qemuCaps,
if (!inc->launchURI)
goto error;
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_INCOMING_DEFER)) {
+ inc->deferredURI = inc->launchURI;
+ if (VIR_STRDUP(inc->launchURI, "defer") < 0)
+ goto error;
+ }
+
inc->fd = fd;
inc->path = path;
@@ -4929,6 +4936,11 @@ int qemuProcessStart(virConnectPtr conn,
if (qemuProcessUpdateVideoRamSize(driver, vm, asyncJob) < 0)
goto error;
+ if (incoming &&
+ incoming->deferredURI &&
+ qemuMigrationRunIncoming(driver, vm, incoming->deferredURI, asyncJob) < 0)
+ goto error;
+
if (!(flags & VIR_QEMU_PROCESS_START_PAUSED)) {
VIR_DEBUG("Starting domain CPUs");
/* Allow the CPUS to start executing */
diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h
index dcba728..dcb7e28 100644
--- a/src/qemu/qemu_process.h
+++ b/src/qemu/qemu_process.h
@@ -48,6 +48,7 @@ typedef struct _qemuProcessIncomingDef qemuProcessIncomingDef;
typedef qemuProcessIncomingDef *qemuProcessIncomingDefPtr;
struct _qemuProcessIncomingDef {
char *launchURI; /* used as a parameter for -incoming command line option */
+ char *deferredURI; /* used when calling migrate-incoming QMP command */
int fd; /* for fd:N URI */
const char *path; /* path associated with fd */
};
diff --git a/tests/qemucapabilitiesdata/caps_2.4.0-1.caps
b/tests/qemucapabilitiesdata/caps_2.4.0-1.caps
index 0d1b1c0..6694b7d 100644
--- a/tests/qemucapabilitiesdata/caps_2.4.0-1.caps
+++ b/tests/qemucapabilitiesdata/caps_2.4.0-1.caps
@@ -161,4 +161,5 @@
<flag name='rtl8139'/>
<flag name='e1000'/>
<flag name='virtio-net'/>
+ <flag name='incoming-defer'/>
</qemuCaps>
--
2.6.3