From 2c4ba8b4f3d20c0cb14e8ee91f087d98a0406802 Mon Sep 17 00:00:00 2001 From: Jiri Denemark Date: Wed, 11 Nov 2015 18:02:23 +0100 Subject: [PATCH] qemu: Use -incoming defer for migrations 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 --- 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 7475298357..2813212c75 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 14541f629e..e3e40e5954 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 4d5b966b25..0c4c94aeea 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 ff4fe30b88..2445e13936 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 1b20f412f5..82f914ac39 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); } @@ -4195,6 +4196,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; @@ -4940,6 +4947,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 dcba728162..dcb7e2848e 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 0d1b1c0818..6694b7dbc1 100644 --- a/tests/qemucapabilitiesdata/caps_2.4.0-1.caps +++ b/tests/qemucapabilitiesdata/caps_2.4.0-1.caps @@ -161,4 +161,5 @@ +