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 <jdenemar@redhat.com>
This commit is contained in:
Jiri Denemark 2015-11-11 18:02:23 +01:00
parent 93d56e9df1
commit 2c4ba8b4f3
7 changed files with 61 additions and 0 deletions

View File

@ -299,6 +299,8 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
"e1000", "e1000",
"virtio-net", "virtio-net",
"gic-version", "gic-version",
"incoming-defer", /* 200 */
); );
@ -1458,6 +1460,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = {
{ "nbd-server-start", QEMU_CAPS_NBD_SERVER }, { "nbd-server-start", QEMU_CAPS_NBD_SERVER },
{ "change-backing-file", QEMU_CAPS_CHANGE_BACKING_FILE }, { "change-backing-file", QEMU_CAPS_CHANGE_BACKING_FILE },
{ "rtc-reset-reinjection", QEMU_CAPS_RTC_RESET_REINJECTION }, { "rtc-reset-reinjection", QEMU_CAPS_RTC_RESET_REINJECTION },
{ "migrate-incoming", QEMU_CAPS_INCOMING_DEFER },
}; };
struct virQEMUCapsStringFlags virQEMUCapsMigration[] = { struct virQEMUCapsStringFlags virQEMUCapsMigration[] = {

View File

@ -325,6 +325,9 @@ typedef enum {
QEMU_CAPS_DEVICE_VIRTIO_NET, /* -device virtio-net-* */ QEMU_CAPS_DEVICE_VIRTIO_NET, /* -device virtio-net-* */
QEMU_CAPS_MACH_VIRT_GIC_VERSION, /* -machine virt,gic-version */ 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 */ QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags; } virQEMUCapsFlags;

View File

@ -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 /* 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 * client which initiated the migration was closed but we were waiting for it
* to follow up with the next phase, that is, in between * to follow up with the next phase, that is, in between

View File

@ -205,4 +205,9 @@ int qemuMigrationCheckIncoming(virQEMUCapsPtr qemuCaps,
char *qemuMigrationIncomingURI(const char *migrateFrom, char *qemuMigrationIncomingURI(const char *migrateFrom,
int migrateFd); int migrateFd);
int qemuMigrationRunIncoming(virQEMUDriverPtr driver,
virDomainObjPtr vm,
const char *uri,
qemuDomainAsyncJob asyncJob);
#endif /* __QEMU_MIGRATION_H__ */ #endif /* __QEMU_MIGRATION_H__ */

View File

@ -4168,6 +4168,7 @@ qemuProcessIncomingDefFree(qemuProcessIncomingDefPtr inc)
return; return;
VIR_FREE(inc->launchURI); VIR_FREE(inc->launchURI);
VIR_FREE(inc->deferredURI);
VIR_FREE(inc); VIR_FREE(inc);
} }
@ -4195,6 +4196,12 @@ qemuProcessIncomingDefNew(virQEMUCapsPtr qemuCaps,
if (!inc->launchURI) if (!inc->launchURI)
goto error; 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->fd = fd;
inc->path = path; inc->path = path;
@ -4940,6 +4947,11 @@ int qemuProcessStart(virConnectPtr conn,
if (qemuProcessUpdateVideoRamSize(driver, vm, asyncJob) < 0) if (qemuProcessUpdateVideoRamSize(driver, vm, asyncJob) < 0)
goto error; goto error;
if (incoming &&
incoming->deferredURI &&
qemuMigrationRunIncoming(driver, vm, incoming->deferredURI, asyncJob) < 0)
goto error;
if (!(flags & VIR_QEMU_PROCESS_START_PAUSED)) { if (!(flags & VIR_QEMU_PROCESS_START_PAUSED)) {
VIR_DEBUG("Starting domain CPUs"); VIR_DEBUG("Starting domain CPUs");
/* Allow the CPUS to start executing */ /* Allow the CPUS to start executing */

View File

@ -48,6 +48,7 @@ typedef struct _qemuProcessIncomingDef qemuProcessIncomingDef;
typedef qemuProcessIncomingDef *qemuProcessIncomingDefPtr; typedef qemuProcessIncomingDef *qemuProcessIncomingDefPtr;
struct _qemuProcessIncomingDef { struct _qemuProcessIncomingDef {
char *launchURI; /* used as a parameter for -incoming command line option */ 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 */ int fd; /* for fd:N URI */
const char *path; /* path associated with fd */ const char *path; /* path associated with fd */
}; };

View File

@ -161,4 +161,5 @@
<flag name='rtl8139'/> <flag name='rtl8139'/>
<flag name='e1000'/> <flag name='e1000'/>
<flag name='virtio-net'/> <flag name='virtio-net'/>
<flag name='incoming-defer'/>
</qemuCaps> </qemuCaps>