[PATCH 15/20] qemu: Support O_DIRECT with mapped-ram on save

Jim Fehlig via Devel posted 20 patches 3 months, 2 weeks ago
[PATCH 15/20] qemu: Support O_DIRECT with mapped-ram on save
Posted by Jim Fehlig via Devel 3 months, 2 weeks ago
When using the mapped-ram migration capability, direct IO is
enabled by setting the "direct-io" migration parameter to
"true" and passing QEMU an additional fd with O_DIRECT set.

Signed-off-by: Jim Fehlig <jfehlig@suse.com>
---
 src/qemu/qemu_driver.c           |  9 +++++----
 src/qemu/qemu_migration.c        | 32 ++++++++++++++++++++++++++------
 src/qemu/qemu_migration.h        |  1 +
 src/qemu/qemu_migration_params.c | 11 ++++++++++-
 src/qemu/qemu_migration_params.h |  3 ++-
 src/qemu/qemu_monitor.c          |  7 +++++--
 src/qemu/qemu_monitor.h          |  3 ++-
 src/qemu/qemu_saveimage.c        |  2 +-
 8 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 6d0f52951c..0025bad6e7 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2691,7 +2691,7 @@ qemuDomainSaveInternal(virQEMUDriver *driver,
     xml = NULL;
 
     mappedRam = data->header.features & QEMU_SAVE_FEATURE_MAPPED_RAM;
-    if (!(saveParams = qemuMigrationParamsForSave(mappedRam)))
+    if (!(saveParams = qemuMigrationParamsForSave(mappedRam, flags)))
         goto endjob;
 
     ret = qemuSaveImageCreate(driver, vm, path, data, compressor,
@@ -3143,7 +3143,7 @@ doCoreDump(virQEMUDriver *driver,
         if (!(dump_params = qemuMigrationParamsNew()))
             goto cleanup;
 
-        if (qemuMigrationSrcToFile(driver, vm, &fd, compressor,
+        if (qemuMigrationSrcToFile(driver, vm, path, &fd, compressor,
                                    dump_params, dump_flags, VIR_ASYNC_JOB_DUMP) < 0)
             goto cleanup;
     }
@@ -5789,7 +5789,7 @@ qemuDomainRestoreInternal(virConnectPtr conn,
         goto cleanup;
 
     mapped_ram = data->header.features & QEMU_SAVE_FEATURE_MAPPED_RAM;
-    if (!(restoreParams = qemuMigrationParamsForSave(mapped_ram)))
+    if (!(restoreParams = qemuMigrationParamsForSave(mapped_ram, flags)))
         return -1;
 
     fd = qemuSaveImageOpen(driver, path,
@@ -6115,7 +6115,8 @@ qemuDomainObjRestore(virConnectPtr conn,
     }
 
     mapped_ram = data->header.features & QEMU_SAVE_FEATURE_MAPPED_RAM;
-    if (!(restoreParams = qemuMigrationParamsForSave(mapped_ram)))
+    if (!(restoreParams = qemuMigrationParamsForSave(mapped_ram,
+                                                     bypass_cache ? VIR_DOMAIN_SAVE_BYPASS_CACHE : 0)))
         return -1;
 
     fd = qemuSaveImageOpen(driver, path, bypass_cache, mapped_ram, &wrapperFd, false);
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 35d3e26908..daa42bcfe4 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -7012,17 +7012,36 @@ qemuMigrationSrcToLegacyFile(virQEMUDriver *driver,
 static int
 qemuMigrationSrcToMappedFile(virQEMUDriver *driver,
                              virDomainObj *vm,
+                             const char *path,
                              int *fd,
                              unsigned int flags,
                              virDomainAsyncJob asyncJob)
 {
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+    VIR_AUTOCLOSE directFd = -1;
+    int directFlag = 0;
+    bool needUnlink = false;
     int ret;
 
-    /* mapped-ram does not support directIO */
+    /* When using directio with mapped-ram, qemu needs two fds. One with
+     * O_DIRECT set writing the memory, and another without it set for
+     * writing small bits of unaligned state. */
     if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
-        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                       _("bypass cache unsupported by this system"));
-        return -1;
+        directFlag = virFileDirectFdFlag();
+        if (directFlag < 0) {
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("bypass cache unsupported by this system"));
+            return -1;
+        }
+        directFd = virQEMUFileOpenAs(cfg->user, cfg->group, false, path,
+                           O_WRONLY | directFlag, &needUnlink);
+
+        if (directFd < 0)
+            return -1;
+
+        if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, directFd) < 0)
+            return -1;
+
     }
 
     if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, *fd) < 0)
@@ -7031,7 +7050,7 @@ qemuMigrationSrcToMappedFile(virQEMUDriver *driver,
     if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0)
         return -1;
 
-    ret = qemuMonitorMigrateToFdSet(vm, 0, fd);
+    ret = qemuMonitorMigrateToFdSet(vm, 0, fd, &directFd);
     qemuDomainObjExitMonitor(vm);
     return ret;
 }
@@ -7040,6 +7059,7 @@ qemuMigrationSrcToMappedFile(virQEMUDriver *driver,
 /* Helper function called while vm is active.  */
 int
 qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
+                       const char *path,
                        int *fd,
                        virCommand *compressor,
                        qemuMigrationParams *migParams,
@@ -7077,7 +7097,7 @@ qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
 
     if (migParams &&
         qemuMigrationParamsCapEnabled(migParams, QEMU_MIGRATION_CAP_MAPPED_RAM)) {
-        rc = qemuMigrationSrcToMappedFile(driver, vm, fd, flags, asyncJob);
+        rc = qemuMigrationSrcToMappedFile(driver, vm, path, fd, flags, asyncJob);
     } else {
         rc = qemuMigrationSrcToLegacyFile(driver, vm, *fd, compressor, asyncJob);
     }
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 5529f2ee21..51d5b680bc 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -236,6 +236,7 @@ qemuMigrationSrcIsAllowed(virDomainObj *vm,
 int
 qemuMigrationSrcToFile(virQEMUDriver *driver,
                        virDomainObj *vm,
+                       const char *path,
                        int *fd,
                        virCommand *compressor,
                        qemuMigrationParams *migParams,
diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c
index 503d6165b0..8f6003005c 100644
--- a/src/qemu/qemu_migration_params.c
+++ b/src/qemu/qemu_migration_params.c
@@ -129,6 +129,7 @@ VIR_ENUM_IMPL(qemuMigrationParam,
               "multifd-compression",
               "multifd-zlib-level",
               "multifd-zstd-level",
+              "direct-io",
 );
 
 typedef struct _qemuMigrationParamsAlwaysOnItem qemuMigrationParamsAlwaysOnItem;
@@ -319,6 +320,9 @@ static const qemuMigrationParamInfoItem qemuMigrationParamInfo[] = {
     [QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL] = {
         .type = QEMU_MIGRATION_PARAM_TYPE_INT,
     },
+    [QEMU_MIGRATION_PARAM_DIRECT_IO] = {
+        .type = QEMU_MIGRATION_PARAM_TYPE_BOOL,
+    },
 };
 G_STATIC_ASSERT(G_N_ELEMENTS(qemuMigrationParamInfo) == QEMU_MIGRATION_PARAM_LAST);
 
@@ -784,7 +788,7 @@ qemuMigrationParamsFromFlags(virTypedParameterPtr params,
 
 
 qemuMigrationParams *
-qemuMigrationParamsForSave(bool mappedRam)
+qemuMigrationParamsForSave(bool mappedRam, unsigned int flags)
 {
     g_autoptr(qemuMigrationParams) saveParams = NULL;
 
@@ -798,6 +802,11 @@ qemuMigrationParamsForSave(bool mappedRam)
             return NULL;
         saveParams->params[QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS].value.i = 1;
         saveParams->params[QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS].set = true;
+
+        if (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) {
+            saveParams->params[QEMU_MIGRATION_PARAM_DIRECT_IO].value.b = true;
+            saveParams->params[QEMU_MIGRATION_PARAM_DIRECT_IO].set = true;
+        }
     }
 
     return g_steal_pointer(&saveParams);
diff --git a/src/qemu/qemu_migration_params.h b/src/qemu/qemu_migration_params.h
index fe239d9a8f..9700469b5e 100644
--- a/src/qemu/qemu_migration_params.h
+++ b/src/qemu/qemu_migration_params.h
@@ -65,6 +65,7 @@ typedef enum {
     QEMU_MIGRATION_PARAM_MULTIFD_COMPRESSION,
     QEMU_MIGRATION_PARAM_MULTIFD_ZLIB_LEVEL,
     QEMU_MIGRATION_PARAM_MULTIFD_ZSTD_LEVEL,
+    QEMU_MIGRATION_PARAM_DIRECT_IO,
 
     QEMU_MIGRATION_PARAM_LAST
 } qemuMigrationParam;
@@ -87,7 +88,7 @@ qemuMigrationParamsFromFlags(virTypedParameterPtr params,
                              qemuMigrationParty party);
 
 qemuMigrationParams *
-qemuMigrationParamsForSave(bool mappedRam);
+qemuMigrationParamsForSave(bool mappedRam, unsigned int flags);
 
 int
 qemuMigrationParamsDump(qemuMigrationParams *migParams,
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 9a454a1d08..832ede639e 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2240,7 +2240,8 @@ qemuMonitorMigrateToFd(qemuMonitor *mon,
 int
 qemuMonitorMigrateToFdSet(virDomainObj *vm,
                           unsigned int flags,
-                          int *fd)
+                          int *fd,
+                          int *directFd)
 {
     qemuDomainObjPrivate *priv = vm->privateData;
     qemuMonitor *mon = priv->mon;
@@ -2250,7 +2251,7 @@ qemuMonitorMigrateToFdSet(virDomainObj *vm,
     g_autofree char *uri = NULL;
     int ret;
 
-    VIR_DEBUG("fd=%d flags=0x%x", *fd, flags);
+    VIR_DEBUG("fd=%d directFd=%d flags=0x%x", *fd, *directFd, flags);
 
     QEMU_CHECK_MONITOR(mon);
 
@@ -2262,6 +2263,8 @@ qemuMonitorMigrateToFdSet(virDomainObj *vm,
 
     fdPassMigrate = qemuFDPassNew("migrate", priv);
     qemuFDPassAddFD(fdPassMigrate, fd, "-buffered-fd");
+    if (*directFd != -1)
+        qemuFDPassAddFD(fdPassMigrate, directFd, "-directio-fd");
     if (qemuFDPassTransferMonitor(fdPassMigrate, mon) < 0)
         return -1;
 
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index ebacdf110e..63385e93f3 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -846,7 +846,8 @@ int qemuMonitorMigrateToFd(qemuMonitor *mon,
 
 int qemuMonitorMigrateToFdSet(virDomainObj *vm,
                               unsigned int flags,
-                              int *fd);
+                              int *fd,
+                              int *directFd);
 
 int qemuMonitorMigrateToHost(qemuMonitor *mon,
                              unsigned int flags,
diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c
index b99e0de1ff..8ffd26d57a 100644
--- a/src/qemu/qemu_saveimage.c
+++ b/src/qemu/qemu_saveimage.c
@@ -450,7 +450,7 @@ qemuSaveImageCreate(virQEMUDriver *driver,
         goto cleanup;
 
     /* Perform the migration */
-    if (qemuMigrationSrcToFile(driver, vm, &fd, compressor, saveParams, flags, asyncJob) < 0)
+    if (qemuMigrationSrcToFile(driver, vm, path, &fd, compressor, saveParams, flags, asyncJob) < 0)
         goto cleanup;
 
     /* Touch up file header to mark image complete. */
-- 
2.35.3