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 - 2024 Red Hat, Inc.