[PATCH RFC 6/9] qemu: Add support for mapped-ram on save

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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;
+
+    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



[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux