Signed-off-by: Claudio Fontana <cfont...@suse.de>
---
 src/qemu/qemu_saveimage.c | 130 ++++++++++++++++++++++++++++++++++++--
 src/qemu/qemu_saveimage.h |  11 ++++
 2 files changed, 137 insertions(+), 4 deletions(-)

diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c
index 6af256aabe..fbeb355272 100644
--- a/src/qemu/qemu_saveimage.c
+++ b/src/qemu/qemu_saveimage.c
@@ -17,6 +17,7 @@
  */
 
 #include <config.h>
+#include <configmake.h>
 
 #include "qemu_saveimage.h"
 #include "qemu_domain.h"
@@ -365,6 +366,93 @@ int virQEMUSaveFdFini(virQEMUSaveFd *saveFd, virDomainObj 
*vm, int ret)
     return ret;
 }
 
+/*
+ * qemuSaveImageFreeMultiFd: free all multifd virQEMUSaveFds.
+ * @multiFd: the array of saveFds
+ * @vm:      the virDomainObj, to release lock
+ * @nconn:   number of multifd channels
+ * @ret:     the current operation result (< 0 is failure)
+ *
+ * If multiFd is NULL, the return value will be unchanged.
+ *
+ * Returns ret, or -1 if an error is detected.
+ */
+int qemuSaveImageFreeMultiFd(virQEMUSaveFd *multiFd, virDomainObj *vm, int 
nconn, int ret)
+{
+    int i;
+
+    if (!multiFd)
+        return ret;
+
+    for (i = 0; i < nconn; i++) {
+        ret = virQEMUSaveFdFini(&multiFd[i], vm, ret);
+    }
+    /*
+     * do it again to unlink all in the error case,
+     * if error happened in the middle of previous loop.
+     */
+    for (i = 0; i < nconn; i++) {
+        ret = virQEMUSaveFdFini(&multiFd[i], vm, ret);
+    }
+    g_free(multiFd);
+    return ret;
+}
+
+/*
+ * qemuSaveImageCloseMultiFd: perform normal close on all multifd 
virQEMUSaveFds.
+ * If multiFd is NULL, the function will return success.
+ *
+ * Returns -1 on error, 0 on success.
+ */
+
+int qemuSaveImageCloseMultiFd(virQEMUSaveFd *multiFd, int nconn, virDomainObj 
*vm)
+{
+    int i;
+
+    if (!multiFd)
+        return 0;
+
+    for (i = 0; i < nconn; i++) {
+        if (virQEMUSaveFdClose(&multiFd[i], vm) < 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/*
+ * qemuSaveImageCreateMultiFd: allocate and initialize all multifd 
virQEMUSaveFds.
+ *
+ * Returns the new array of virQEMUSaveFds, or NULL on error.
+ */
+
+virQEMUSaveFd *
+qemuSaveImageCreateMultiFd(virQEMUDriver *driver, virDomainObj *vm,
+                           virCommand *cmd, const char *path,
+                           int oflags, virQEMUDriverConfig *cfg,
+                           int nconn)
+{
+    virQEMUSaveFd *multiFd = g_new0(virQEMUSaveFd, nconn);
+    int i;
+
+    for (i = 0; i < nconn; i++) {
+        virQEMUSaveFd *m = &multiFd[i];
+        if (virQEMUSaveFdInit(m, path, i + 1, oflags, cfg) < 0 ||
+            qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, 
m->fd) < 0) {
+
+            virQEMUSaveFdFini(m, vm, -1);
+            goto error;
+        }
+        virCommandAddArgFormat(cmd, "%d", m->fd);
+        virCommandPassFD(cmd, m->fd, 0);
+    }
+    return multiFd;
+
+ error:
+    qemuSaveImageFreeMultiFd(multiFd, vm, nconn, -1);
+    return NULL;
+}
+
 
 /* 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
@@ -381,6 +469,7 @@ qemuSaveImageCreate(virQEMUDriver *driver,
 {
     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
     virQEMUSaveFd saveFd = QEMU_SAVEFD_INVALID;
+    virQEMUSaveFd *multiFd = NULL;
     unsigned int oflags = O_WRONLY | O_TRUNC | O_CREAT;
     int ret = -1;
     nconn = nconn; /* unused */
@@ -403,10 +492,43 @@ qemuSaveImageCreate(virQEMUDriver *driver,
     if (virQEMUSaveDataWrite(data, saveFd.fd, saveFd.path) < 0)
         goto cleanup;
 
+    if (flags & VIR_DOMAIN_SAVE_PARALLEL) {
+        g_autoptr(virCommand) cmd = NULL;
+        g_autofree char *helper_path = NULL;
+        qemuDomainObjPrivate *priv = vm->privateData;
+        g_autofree char *sun_path = g_strdup_printf("%s/save-multifd.sock", 
priv->libDir);
+        char buf[1];
+        int helper_out = -1;
+        if (!(helper_path = virFileFindResource("libvirt_multifd_helper",
+                                                abs_top_builddir "/src",
+                                                LIBEXECDIR)))
+            goto cleanup;
+        cmd = virCommandNewArgList(helper_path, sun_path, NULL);
+        virCommandAddArgFormat(cmd, "%d", nconn);
+        virCommandAddArgFormat(cmd, "%d", saveFd.fd);
+        virCommandPassFD(cmd, saveFd.fd, 0);
+        virCommandSetOutputFD(cmd, &helper_out); /* should create pipe 
automagically */
+
+        /* Perform parallel multifd migration to files (main fd + channels) */
+        if (!(multiFd = qemuSaveImageCreateMultiFd(driver, vm, cmd, 
saveFd.path, oflags, cfg, nconn)))
+            goto cleanup;
+        if (virCommandRunAsync(cmd, NULL) < 0)
+            goto cleanup;
+        if (saferead(helper_out, &buf, 1) != 1 || buf[0] != 'R')
+            goto cleanup;
+        if (chown(sun_path, cfg->user, cfg->group) < 0)
+            goto cleanup;
+        /* still using single fd migration for now */
+        if (qemuMigrationSrcToFile(driver, vm, saveFd.fd, compressor, 
asyncJob) < 0)
+            goto cleanup;
+        if (qemuSaveImageCloseMultiFd(multiFd, nconn, vm) < 0)
+            goto cleanup;
+    } else {
+        /* Perform non-parallel migration to file */
+        if (qemuMigrationSrcToFile(driver, vm, saveFd.fd, compressor, 
asyncJob) < 0)
+            goto cleanup;
+    }
 
-    /* Perform the migration */
-    if (qemuMigrationSrcToFile(driver, vm, saveFd.fd, compressor, asyncJob) < 
0)
-        goto cleanup;
     if (virQEMUSaveFdClose(&saveFd, vm) < 0)
         goto cleanup;
 
@@ -425,7 +547,7 @@ qemuSaveImageCreate(virQEMUDriver *driver,
 
 
  cleanup:
-
+    ret = qemuSaveImageFreeMultiFd(multiFd, vm, nconn, ret);
     ret = virQEMUSaveFdFini(&saveFd, vm, ret);
     return ret;
 }
diff --git a/src/qemu/qemu_saveimage.h b/src/qemu/qemu_saveimage.h
index 5dc63f3661..b775c5eb08 100644
--- a/src/qemu/qemu_saveimage.h
+++ b/src/qemu/qemu_saveimage.h
@@ -72,6 +72,17 @@ int virQEMUSaveFdClose(virQEMUSaveFd *saveFd, virDomainObj 
*vm);
 
 int virQEMUSaveFdFini(virQEMUSaveFd *saveFd, virDomainObj *vm, int ret);
 
+virQEMUSaveFd *
+qemuSaveImageCreateMultiFd(virQEMUDriver *driver, virDomainObj *vm,
+                           virCommand *cmd, const char *path,
+                           int oflags, virQEMUDriverConfig *cfg,
+                           int nconn)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) 
ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(6);
+
+int qemuSaveImageCloseMultiFd(virQEMUSaveFd *multiFd, int nconn, virDomainObj 
*vm);
+
+int qemuSaveImageFreeMultiFd(virQEMUSaveFd *multiFd, virDomainObj *vm, int 
nconn, int ret);
+
 virDomainDef *
 qemuSaveImageUpdateDef(virQEMUDriver *driver,
                        virDomainDef *def,
-- 
2.34.1

Reply via email to