Signed-off-by: Claudio Fontana <cfontana(a)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 5a569fa52e..65d9a3fef5 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 idx;
+
+ if (!multiFd)
+ return ret;
+
+ for (idx = 0; idx < nconn; idx++) {
+ ret = virQEMUSaveFdFini(&multiFd[idx], vm, ret);
+ }
+ /*
+ * do it again to unlink all in the error case,
+ * if error happened in the middle of previous loop.
+ */
+ for (idx = 0; idx < nconn; idx++) {
+ ret = virQEMUSaveFdFini(&multiFd[idx], 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 idx;
+
+ if (!multiFd)
+ return 0;
+
+ for (idx = 0; idx < nconn; idx++) {
+ if (virQEMUSaveFdClose(&multiFd[idx], 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 idx;
+
+ for (idx = 0; idx < nconn; idx++) {
+ virQEMUSaveFd *m = &multiFd[idx];
+ if (virQEMUSaveFdInit(m, path, idx + 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;
@@ -402,10 +491,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;
@@ -424,7 +546,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