On Thu, Jun 13, 2024 at 04:43:20PM -0600, Jim Fehlig via Devel wrote:
Signed-off-by: Jim Fehlig <jfehlig@xxxxxxxx> --- src/qemu/qemu_driver.c | 2 +- src/qemu/qemu_migration.c | 79 ++++++++++++++++++++++++++++ src/qemu/qemu_migration.h | 7 +++ src/qemu/qemu_monitor.c | 32 ++++++++++++ src/qemu/qemu_monitor.h | 4 ++ src/qemu/qemu_saveimage.c | 105 ++++++++++++++++++++++++++++++-------- src/qemu/qemu_saveimage.h | 1 + src/qemu/qemu_snapshot.c | 2 +- 8 files changed, 208 insertions(+), 24 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f9761242d2..34f37210d9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2696,7 +2696,7 @@ qemuDomainSaveInternal(virQEMUDriver *driver, if (!(cookie = qemuDomainSaveCookieNew(vm))) goto endjob; - if (!(data = virQEMUSaveDataNew(driver, xml, cookie, was_running, compressed))) + if (!(data = virQEMUSaveDataNew(driver, vm, xml, cookie, was_running, compressed))) goto endjob; xml = NULL; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 1faab5dd23..3110ef2621 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -7072,6 +7072,85 @@ qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm, } +int +qemuMigrationSrcToMappedFile(virQEMUDriver *driver, virDomainObj *vm, + int fd, + virDomainAsyncJob asyncJob) +{ + qemuDomainObjPrivate *priv = vm->privateData; + g_autoptr(qemuMigrationParams) saveParams = NULL; + unsigned long saveMigBandwidth = priv->migMaxBandwidth; + int rc; + int ret = -1; + virErrorPtr orig_err = NULL; + + if (qemuMigrationSetDBusVMState(driver, vm) < 0) + return -1; + + if (!(saveParams = qemuMigrationParamsForMappedSave())) + return -1; + + /* Increase migration bandwidth to unlimited since target is a file. + * Failure to change migration speed is not fatal. */ + if (qemuMigrationParamsSetULL(saveParams, + QEMU_MIGRATION_PARAM_MAX_BANDWIDTH, + QEMU_DOMAIN_MIG_BANDWIDTH_MAX * 1024 * 1024) < 0) + return -1; + + if (qemuMigrationParamsApply(vm, asyncJob, saveParams, 0) < 0) + return -1; + + priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX; + + if (!virDomainObjIsActive(vm)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("guest unexpectedly quit")); + /* nothing to tear down */ + return -1; + } + + if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0) + goto cleanup; + + rc = qemuMonitorMigrateToFdSet(vm, 0, fd); + qemuDomainObjExitMonitor(vm); + if (rc < 0) + goto cleanup; + + rc = qemuMigrationSrcWaitForCompletion(vm, asyncJob, NULL, 0); + + if (rc < 0) { + if (rc == -2) { + virErrorPreserveLast(&orig_err); + if (virDomainObjIsActive(vm)) + qemuMigrationSrcCancel(vm, asyncJob, true); + } + goto cleanup; + } + + qemuDomainEventEmitJobCompleted(driver, vm); + ret = 0; + + cleanup: + if (ret < 0 && !orig_err) + virErrorPreserveLast(&orig_err); + + /* Restore max migration bandwidth */ + if (virDomainObjIsActive(vm)) { + if (qemuMigrationParamsSetULL(saveParams, + QEMU_MIGRATION_PARAM_MAX_BANDWIDTH, + saveMigBandwidth * 1024 * 1024) == 0) + ignore_value(qemuMigrationParamsApply(vm, asyncJob, + saveParams, 0)); + priv->migMaxBandwidth = saveMigBandwidth; + } + + virErrorRestore(&orig_err); + + return ret; +} + + /** * This function is supposed to be used only to while reconnecting to a domain * with an active migration job. diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h index ed62fd4a91..f845a0198b 100644 --- a/src/qemu/qemu_migration.h +++ b/src/qemu/qemu_migration.h @@ -241,6 +241,13 @@ qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainAsyncJob asyncJob) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; +int +qemuMigrationSrcToMappedFile(virQEMUDriver *driver, + virDomainObj *vm, + int fd, + virDomainAsyncJob asyncJob) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; + int qemuMigrationSrcCancelUnattended(virDomainObj *vm, virDomainJobObj *oldJob); diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 34e2ccab97..4c92bd740a 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2237,6 +2237,38 @@ qemuMonitorMigrateToFd(qemuMonitor *mon, } +int +qemuMonitorMigrateToFdSet(virDomainObj *vm, + unsigned int flags, + int fd) +{ + qemuDomainObjPrivate *priv = vm->privateData; + qemuMonitor *mon = priv->mon; + off_t offset; + g_autoptr(qemuFDPass) fdPassMigrate = NULL; + unsigned int setId; + g_autofree char *uri = NULL; + + VIR_DEBUG("fd=%d flags=0x%x", fd, flags); + + QEMU_CHECK_MONITOR(mon); + + if ((offset = lseek(fd, 0, SEEK_CUR)) == -1) + return -1;
virReportSystemError() should probably be here or this could be checked/gathered before entering the monitor
+ + fdPassMigrate = qemuFDPassNew("migrate", priv); + qemuFDPassAddFD(fdPassMigrate, &fd, "-fd"); + qemuFDPassTransferMonitor(fdPassMigrate, mon);
This function can fail (and set an error)
+ + if (qemuFDPassGetId(fdPassMigrate, &setId) < 0) + return -1;
No error set here, but I see no way for it failing in this case.
+ + uri = g_strdup_printf("file:/dev/fdset/%u,offset=%#lx", setId, offset); + + return qemuMonitorJSONMigrate(mon, flags, uri); +} + + int qemuMonitorMigrateToHost(qemuMonitor *mon, unsigned int flags, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 6e81945201..c477def138 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -843,6 +843,10 @@ int qemuMonitorMigrateToFd(qemuMonitor *mon, unsigned int flags, int fd); +int qemuMonitorMigrateToFdSet(virDomainObj *vm, + unsigned int flags, + int fd); + int qemuMonitorMigrateToHost(qemuMonitor *mon, unsigned int flags, const char *protocol, diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c index 30085dc7bc..8f28770086 100644 --- a/src/qemu/qemu_saveimage.c +++ b/src/qemu/qemu_saveimage.c @@ -96,6 +96,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virQEMUSaveData, virQEMUSaveDataFree); */ virQEMUSaveData * virQEMUSaveDataNew(virQEMUDriver *driver, + virDomainObj *vm, char *domXML, qemuDomainSaveCookie *cookieObj, bool running, @@ -122,6 +123,10 @@ virQEMUSaveDataNew(virQEMUDriver *driver, goto error; } header->version = cfg->saveImageVersion; + /* Enable mapped-ram feature if available and save version >= 3 */ + if (header->version >= QEMU_SAVE_VERSION &&
This should really be "3" and not the save version in case we increase it, but to be readable without magic numbers and also more error proof, there should be a mapping of feature->minVersion maybe?
+ qemuMigrationCapsGet(vm, QEMU_MIGRATION_CAP_MAPPED_RAM)) + header->features |= QEMU_SAVE_FEATURE_MAPPED_RAM; header->was_running = running ? 1 : 0; header->compressed = compressed;
Also in case we add support for compressed mapped-ram save images this might screw up later since you record the compression, but don't execute it (as mentioned in the cover letter).
Attachment:
signature.asc
Description: PGP signature