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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list