On Thu, Jun 13, 2024 at 04:43:20PM -0600, Jim Fehlig via Devel wrote:
Signed-off-by: Jim Fehlig <jfehlig(a)suse.com>
---
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).