Signed-off-by: Jim Fehlig <jfehlig@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;
+
+ fdPassMigrate = qemuFDPassNew("migrate", priv);
+ qemuFDPassAddFD(fdPassMigrate, &fd, "-fd");
+ qemuFDPassTransferMonitor(fdPassMigrate, mon);
+
+ if (qemuFDPassGetId(fdPassMigrate, &setId) < 0)
+ return -1;
+
+ 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 &&
+ qemuMigrationCapsGet(vm, QEMU_MIGRATION_CAP_MAPPED_RAM))
+ header->features |= QEMU_SAVE_FEATURE_MAPPED_RAM;
header->was_running = running ? 1 : 0;
header->compressed = compressed;
@@ -369,6 +374,79 @@ qemuSaveImageDecompressionStop(virCommand *cmd,
}
+static int
+qemuSaveImageCreateSequential(virQEMUDriver *driver,
+ virDomainObj *vm,
+ const char *path,
+ int fd,
+ virQEMUSaveData *data,
+ virCommand *compressor,
+ unsigned int flags,
+ virDomainAsyncJob asyncJob)
+{
+ int ret = -1;
+ virFileWrapperFd *wrapperFd = NULL;
+ unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
+
+ if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE))
+ wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
+
+ if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
+ goto cleanup;
+
+ if (virQEMUSaveDataWrite(data, fd, path) < 0)
+ goto cleanup;
+
+ /* Perform the migration */
+ if (qemuMigrationSrcToFile(driver, vm, fd, compressor, asyncJob) < 0)
+ goto cleanup;
+
+ if (VIR_CLOSE(fd) < 0) {
+ virReportSystemError(errno, _("unable to close %1$s"), path);
+ goto cleanup;
+ }
+
+ if (qemuDomainFileWrapperFDClose(vm, wrapperFd) < 0)
+ goto cleanup;
+
+ ret = 0;
+
+ cleanup:
+ VIR_FORCE_CLOSE(fd);
+ if (qemuDomainFileWrapperFDClose(vm, wrapperFd) < 0)
+ ret = -1;
+ virFileWrapperFdFree(wrapperFd);
+
+ return ret;
+}
+
+
+static int
+qemuSaveImageCreateMapped(virQEMUDriver *driver,
+ virDomainObj *vm,
+ const char *path,
+ int fd,
+ virQEMUSaveData *data,
+ unsigned int flags,
+ virDomainAsyncJob asyncJob)
+{
+ g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+
+ /* mapped-ram does not support directIO */
+ if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("bypass cache unsupported by this system"));
+ return -1;
+ }
+
+ if (virQEMUSaveDataWrite(data, fd, path) < 0)
+ return -1;
+
+ /* Perform the migration */
+ return qemuMigrationSrcToMappedFile(driver, vm, fd, asyncJob);
+}
+
+
/* Helper function to execute a migration to file with a correct save header
* the caller needs to make sure that the processors are stopped and do all other
* actions besides saving memory */
@@ -386,12 +464,9 @@ qemuSaveImageCreate(virQEMUDriver *driver,
int ret = -1;
int fd = -1;
int directFlag = 0;
- virFileWrapperFd *wrapperFd = NULL;
- unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
/* Obtain the file handle. */
if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
- wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
directFlag = virFileDirectFdFlag();
if (directFlag < 0) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
@@ -409,14 +484,12 @@ qemuSaveImageCreate(virQEMUDriver *driver,
if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, fd) < 0)
goto cleanup;
- if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
- goto cleanup;
+ if (data->header.features & QEMU_SAVE_FEATURE_MAPPED_RAM)
+ ret = qemuSaveImageCreateMapped(driver, vm, path, fd, data, flags, asyncJob);
+ else
+ ret = qemuSaveImageCreateSequential(driver, vm, path, fd, data, compressor, flags, asyncJob);
- if (virQEMUSaveDataWrite(data, fd, path) < 0)
- goto cleanup;
-
- /* Perform the migration */
- if (qemuMigrationSrcToFile(driver, vm, fd, compressor, asyncJob) < 0)
+ if (ret < 0)
goto cleanup;
/* Touch up file header to mark image complete. */
@@ -425,14 +498,6 @@ qemuSaveImageCreate(virQEMUDriver *driver,
* up to seek backwards on wrapperFd. The reopened fd will
* trigger a single page of file system cache pollution, but
* that's acceptable. */
- if (VIR_CLOSE(fd) < 0) {
- virReportSystemError(errno, _("unable to close %1$s"), path);
- goto cleanup;
- }
-
- if (qemuDomainFileWrapperFDClose(vm, wrapperFd) < 0)
- goto cleanup;
-
if ((fd = qemuDomainOpenFile(cfg, vm->def, path, O_WRONLY, NULL)) < 0 ||
virQEMUSaveDataFinish(data, &fd, path) < 0)
goto cleanup;
@@ -441,10 +506,6 @@ qemuSaveImageCreate(virQEMUDriver *driver,
cleanup:
VIR_FORCE_CLOSE(fd);
- if (qemuDomainFileWrapperFDClose(vm, wrapperFd) < 0)
- ret = -1;
- virFileWrapperFdFree(wrapperFd);
-
if (ret < 0 && needUnlink)
unlink(path);
diff --git a/src/qemu/qemu_saveimage.h b/src/qemu/qemu_saveimage.h
index 63ad5508ed..81d93bf33c 100644
--- a/src/qemu/qemu_saveimage.h
+++ b/src/qemu/qemu_saveimage.h
@@ -124,6 +124,7 @@ virQEMUSaveDataWrite(virQEMUSaveData *data,
virQEMUSaveData *
virQEMUSaveDataNew(virQEMUDriver *driver,
+ virDomainObj *vm,
char *domXML,
qemuDomainSaveCookie *cookieObj,
bool running,
diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
index 1d75208814..1e9e0e31d7 100644
--- a/src/qemu/qemu_snapshot.c
+++ b/src/qemu/qemu_snapshot.c
@@ -1390,7 +1390,7 @@ qemuSnapshotCreateActiveExternal(virQEMUDriver *driver,
!(snapdef->cookie = (virObject *) qemuDomainSaveCookieNew(vm)))
goto cleanup;
- if (!(data = virQEMUSaveDataNew(driver, xml,
+ if (!(data = virQEMUSaveDataNew(driver, vm, xml,
(qemuDomainSaveCookie *) snapdef->cookie,
resume, compressed)))
goto cleanup;
--
2.44.0
On Thu, Jun 13, 2024 at 04:43:20PM -0600, Jim Fehlig via Devel wrote:
>Signed-off-by: Jim Fehlig <jfehlig@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).
© 2016 - 2026 Red Hat, Inc.