diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 295d5511b9..82c602b6d1 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1200,6 +1200,7 @@ typedef enum { VIR_MIGRATE_OFFLINE = (1 << 10), /* offline migrate */ VIR_MIGRATE_COMPRESSED = (1 << 11), /* compress data during migration */ VIR_MIGRATE_ABORT_ON_ERROR = (1 << 12), /* abort migration on I/O errors happened during migration */ + VIR_MIGRATE_AUTO_CONVERGE = (1 << 13), /* force convergence */ } virDomainMigrateFlags; diff --git a/src/libvirt.c b/src/libvirt.c index 2201b07336..c5c3136d0b 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -4408,7 +4408,8 @@ virDomainMigrateVersion1(virDomainPtr domain, if (ret == 0 && info.state == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; - destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; + destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR | + VIR_MIGRATE_AUTO_CONVERGE); /* Prepare the migration. * @@ -4538,7 +4539,8 @@ virDomainMigrateVersion2(virDomainPtr domain, if (ret == 0 && info.state == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; - destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; + destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR | + VIR_MIGRATE_AUTO_CONVERGE); VIR_DEBUG("Prepare2 %p flags=%lx", dconn, destflags); ret = dconn->driver->domainMigratePrepare2 @@ -4710,7 +4712,8 @@ virDomainMigrateVersion3Full(virDomainPtr domain, if (ret == 0 && state == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; - destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; + destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR | + VIR_MIGRATE_AUTO_CONVERGE); VIR_DEBUG("Prepare3 %p flags=%x", dconn, destflags); cookiein = cookieout; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index ab6f2878ad..57e2436949 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1621,6 +1621,41 @@ cleanup: return ret; } +static int +qemuMigrationSetAutoConverge(virQEMUDriverPtr driver, + virDomainObjPtr vm, + enum qemuDomainAsyncJob job) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + int ret; + + if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0) + return -1; + + ret = qemuMonitorGetMigrationCapability( + priv->mon, + QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE); + + if (ret < 0) { + goto cleanup; + } else if (ret == 0) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Auto-Converge is not supported by " + "QEMU binary")); + ret = -1; + goto cleanup; + } + + ret = qemuMonitorSetMigrationCapability( + priv->mon, + QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE); + +cleanup: + qemuDomainObjExitMonitor(driver, vm); + return ret; +} + + static int qemuMigrationWaitForSpice(virQEMUDriverPtr driver, virDomainObjPtr vm) @@ -3234,6 +3269,11 @@ qemuMigrationRun(virQEMUDriverPtr driver, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup; + if (flags & VIR_MIGRATE_AUTO_CONVERGE && + qemuMigrationSetAutoConverge(driver, vm, + QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) + goto cleanup; + if (qemuDomainObjEnterMonitorAsync(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0) goto cleanup; @@ -3587,7 +3627,8 @@ static int doPeer2PeerMigrate2(virQEMUDriverPtr driver, if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; - destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; + destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR | + VIR_MIGRATE_AUTO_CONVERGE); VIR_DEBUG("Prepare2 %p", dconn); if (flags & VIR_MIGRATE_TUNNELLED) { @@ -3780,7 +3821,8 @@ doPeer2PeerMigrate3(virQEMUDriverPtr driver, if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) flags |= VIR_MIGRATE_PAUSED; - destflags = flags & ~VIR_MIGRATE_ABORT_ON_ERROR; + destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR | + VIR_MIGRATE_AUTO_CONVERGE); VIR_DEBUG("Prepare3 %p", dconn); cookiein = cookieout; diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index cafa2a2998..a802fb7ee6 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -39,7 +39,8 @@ VIR_MIGRATE_UNSAFE | \ VIR_MIGRATE_OFFLINE | \ VIR_MIGRATE_COMPRESSED | \ - VIR_MIGRATE_ABORT_ON_ERROR) + VIR_MIGRATE_ABORT_ON_ERROR | \ + VIR_MIGRATE_AUTO_CONVERGE) /* All supported migration parameters and their types. */ # define QEMU_MIGRATION_PARAMETERS \ diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 48fc51cf87..357c9709fc 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -121,7 +121,7 @@ VIR_ENUM_IMPL(qemuMonitorMigrationStatus, VIR_ENUM_IMPL(qemuMonitorMigrationCaps, QEMU_MONITOR_MIGRATION_CAPS_LAST, - "xbzrle") + "xbzrle", "auto-converge") VIR_ENUM_IMPL(qemuMonitorVMStatus, QEMU_MONITOR_VM_STATUS_LAST, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index f626cc1223..d8f1d10c32 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -451,6 +451,7 @@ int qemuMonitorGetSpiceMigrationStatus(qemuMonitorPtr mon, typedef enum { QEMU_MONITOR_MIGRATION_CAPS_XBZRLE, + QEMU_MONITOR_MIGRATION_CAPS_AUTO_CONVERGE, QEMU_MONITOR_MIGRATION_CAPS_LAST } qemuMonitorMigrationCaps; diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index eb3397df56..0664774341 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -8757,6 +8757,10 @@ static const vshCmdOptDef opts_migrate[] = { .type = VSH_OT_BOOL, .help = N_("compress repeated pages during live migration") }, + {.name = "auto-converge", + .type = VSH_OT_BOOL, + .help = N_("force convergence during live migration") + }, {.name = "abort-on-error", .type = VSH_OT_BOOL, .help = N_("abort on soft errors during migration") @@ -8901,6 +8905,9 @@ doMigrate(void *opaque) if (vshCommandOptBool(cmd, "compressed")) flags |= VIR_MIGRATE_COMPRESSED; + if (vshCommandOptBool(cmd, "auto-converge")) + flags |= VIR_MIGRATE_AUTO_CONVERGE; + if (vshCommandOptBool(cmd, "offline")) { flags |= VIR_MIGRATE_OFFLINE; }