implement a function similar to qemuMigrationSrcToFile
that migrates to multiple files using QEMU multifd.
Signed-off-by: Claudio Fontana <cfontana(a)suse.de>
---
src/qemu/qemu_capabilities.c | 1 +
src/qemu/qemu_migration.c | 129 ++++++++++++++++++++-----------
src/qemu/qemu_migration.h | 7 ++
src/qemu/qemu_migration_params.c | 22 ++++++
src/qemu/qemu_migration_params.h | 9 +++
src/qemu/qemu_saveimage.c | 3 +-
6 files changed, 124 insertions(+), 47 deletions(-)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 6b4ed08499..01b570807b 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -1240,6 +1240,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = {
struct virQEMUCapsStringFlags virQEMUCapsMigration[] = {
{ "rdma-pin-all", QEMU_CAPS_MIGRATE_RDMA },
+ { "multifd", QEMU_MIGRATION_CAP_MULTIFD },
};
/* Use virQEMUCapsQMPSchemaQueries for querying parameters of events */
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 3e653543c6..9ce24c8cfc 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -5897,13 +5897,14 @@ qemuMigrationDstFinish(virQEMUDriver *driver,
return dom;
}
-
/* Helper function called while vm is active. */
-int
-qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
- int fd,
- virCommand *compressor,
- virDomainAsyncJob asyncJob)
+static int
+qemuMigrationSrcToFileAux(virQEMUDriver *driver, virDomainObj *vm,
+ int fd,
+ virCommand *compressor,
+ virDomainAsyncJob asyncJob,
+ const char *sun_path,
+ int nchannels)
{
qemuDomainObjPrivate *priv = vm->privateData;
bool bwParam = virQEMUCapsGet(priv->qemuCaps,
QEMU_CAPS_MIGRATION_PARAM_BANDWIDTH);
@@ -5914,24 +5915,24 @@ qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
char *errbuf = NULL;
virErrorPtr orig_err = NULL;
g_autoptr(qemuMigrationParams) migParams = NULL;
+ bool needParams = (bwParam || sun_path);
if (qemuMigrationSetDBusVMState(driver, vm) < 0)
return -1;
+ if (sun_path && !virQEMUCapsGet(priv->qemuCaps,
QEMU_MIGRATION_CAP_MULTIFD))
+ return -1;
+
/* Increase migration bandwidth to unlimited since target is a file.
* Failure to change migration speed is not fatal. */
- if (bwParam) {
- if (!(migParams = qemuMigrationParamsNew()))
- return -1;
+ if (needParams && !((migParams = qemuMigrationParamsNew())))
+ return -1;
+ if (bwParam) {
if (qemuMigrationParamsSetULL(migParams,
QEMU_MIGRATION_PARAM_MAX_BANDWIDTH,
QEMU_DOMAIN_MIG_BANDWIDTH_MAX * 1024 * 1024) <
0)
return -1;
-
- if (qemuMigrationParamsApply(driver, vm, asyncJob, migParams) < 0)
- return -1;
-
priv->migMaxBandwidth = QEMU_DOMAIN_MIG_BANDWIDTH_MAX;
} else {
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
@@ -5942,6 +5943,17 @@ qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
}
}
+ if (sun_path) {
+ qemuMigrationParamsSetCap(migParams, QEMU_MIGRATION_CAP_MULTIFD);
+ if (qemuMigrationParamsSetInt(migParams,
+ QEMU_MIGRATION_PARAM_MULTIFD_CHANNELS,
+ nchannels) < 0)
+ return -1;
+ }
+
+ if (needParams && qemuMigrationParamsApply(driver, vm, asyncJob, migParams)
< 0)
+ return -1;
+
if (!virDomainObjIsActive(vm)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("guest unexpectedly quit"));
@@ -5949,45 +5961,53 @@ qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
return -1;
}
- if (compressor && virPipe(pipeFD) < 0)
+ if (!sun_path && compressor && virPipe(pipeFD) < 0)
return -1;
- /* All right! We can use fd migration, which means that qemu
- * doesn't have to open() the file, so while we still have to
- * grant SELinux access, we can do it on fd and avoid cleanup
- * later, as well as skip futzing with cgroup. */
- if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def,
- compressor ? pipeFD[1] : fd) < 0)
- goto cleanup;
-
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
goto cleanup;
- if (!compressor) {
- rc = qemuMonitorMigrateToFd(priv->mon,
- QEMU_MONITOR_MIGRATE_BACKGROUND,
- fd);
+ if (sun_path) {
+ rc = qemuMonitorMigrateToSocket(priv->mon,
+ QEMU_MONITOR_MIGRATE_BACKGROUND,
+ sun_path);
} else {
- virCommandSetInputFD(compressor, pipeFD[0]);
- virCommandSetOutputFD(compressor, &fd);
- virCommandSetErrorBuffer(compressor, &errbuf);
- virCommandDoAsyncIO(compressor);
- if (virSetCloseExec(pipeFD[1]) < 0) {
- virReportSystemError(errno, "%s",
- _("Unable to set cloexec flag"));
- qemuDomainObjExitMonitor(vm);
- goto cleanup;
- }
- if (virCommandRunAsync(compressor, NULL) < 0) {
- qemuDomainObjExitMonitor(vm);
+ /*
+ * All right! We can use fd migration, which means that qemu
+ * doesn't have to open() the file, so while we still have to
+ * grant SELinux access, we can do it on fd and avoid cleanup
+ * later, as well as skip futzing with cgroup.
+ */
+ if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def,
+ compressor ? pipeFD[1] : fd) < 0)
goto cleanup;
+
+ if (!compressor) {
+ rc = qemuMonitorMigrateToFd(priv->mon,
+ QEMU_MONITOR_MIGRATE_BACKGROUND,
+ fd);
+ } else {
+ virCommandSetInputFD(compressor, pipeFD[0]);
+ virCommandSetOutputFD(compressor, &fd);
+ virCommandSetErrorBuffer(compressor, &errbuf);
+ virCommandDoAsyncIO(compressor);
+ if (virSetCloseExec(pipeFD[1]) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to set cloexec flag"));
+ qemuDomainObjExitMonitor(vm);
+ goto cleanup;
+ }
+ if (virCommandRunAsync(compressor, NULL) < 0) {
+ qemuDomainObjExitMonitor(vm);
+ goto cleanup;
+ }
+ rc = qemuMonitorMigrateToFd(priv->mon,
+ QEMU_MONITOR_MIGRATE_BACKGROUND,
+ pipeFD[1]);
+ if (VIR_CLOSE(pipeFD[0]) < 0 ||
+ VIR_CLOSE(pipeFD[1]) < 0)
+ VIR_WARN("failed to close intermediate pipe");
}
- rc = qemuMonitorMigrateToFd(priv->mon,
- QEMU_MONITOR_MIGRATE_BACKGROUND,
- pipeFD[1]);
- if (VIR_CLOSE(pipeFD[0]) < 0 ||
- VIR_CLOSE(pipeFD[1]) < 0)
- VIR_WARN("failed to close intermediate pipe");
}
qemuDomainObjExitMonitor(vm);
if (rc < 0)
@@ -6008,7 +6028,7 @@ qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
goto cleanup;
}
- if (compressor && virCommandWait(compressor, NULL) < 0)
+ if (!sun_path && compressor && virCommandWait(compressor, NULL) <
0)
goto cleanup;
qemuDomainEventEmitJobCompleted(driver, vm);
@@ -6047,6 +6067,25 @@ qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
return ret;
}
+int
+qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
+ int fd,
+ virCommand *compressor,
+ virDomainAsyncJob asyncJob)
+{
+ return qemuMigrationSrcToFileAux(driver, vm, fd, compressor,
+ asyncJob, NULL, -1);
+}
+
+int
+qemuMigrationSrcToFilesMultiFd(virQEMUDriver *driver, virDomainObj *vm,
+ virDomainAsyncJob asyncJob,
+ const char *sun_path,
+ int nchannels)
+{
+ return qemuMigrationSrcToFileAux(driver, vm, -1, NULL,
+ asyncJob, sun_path, nchannels);
+}
int
qemuMigrationSrcCancel(virQEMUDriver *driver,
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index a8afa66119..ddc8e65489 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -213,6 +213,13 @@ qemuMigrationSrcToFile(virQEMUDriver *driver,
virDomainAsyncJob asyncJob)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
+int
+qemuMigrationSrcToFilesMultiFd(virQEMUDriver *driver, virDomainObj *vm,
+ virDomainAsyncJob asyncJob,
+ const char *sun_path,
+ int nchannels)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
+
int
qemuMigrationSrcCancel(virQEMUDriver *driver,
virDomainObj *vm);
diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c
index df2384b213..36174a66d8 100644
--- a/src/qemu/qemu_migration_params.c
+++ b/src/qemu/qemu_migration_params.c
@@ -1109,6 +1109,28 @@ qemuMigrationParamsFetch(virQEMUDriver *driver,
}
+void
+qemuMigrationParamsSetCap(qemuMigrationParams *migParams,
+ virQEMUCapsFlags flag)
+{
+ ignore_value(virBitmapSetBit(migParams->caps, flag));
+}
+
+
+int
+qemuMigrationParamsSetInt(qemuMigrationParams *migParams,
+ qemuMigrationParam param,
+ int value)
+{
+ if (qemuMigrationParamsCheckType(param, QEMU_MIGRATION_PARAM_TYPE_INT) < 0)
+ return -1;
+
+ migParams->params[param].value.i = value;
+ migParams->params[param].set = true;
+ return 0;
+}
+
+
int
qemuMigrationParamsSetULL(qemuMigrationParams *migParams,
qemuMigrationParam param,
diff --git a/src/qemu/qemu_migration_params.h b/src/qemu/qemu_migration_params.h
index 4a8815e776..99af73b4a4 100644
--- a/src/qemu/qemu_migration_params.h
+++ b/src/qemu/qemu_migration_params.h
@@ -123,6 +123,15 @@ qemuMigrationParamsFetch(virQEMUDriver *driver,
int asyncJob,
qemuMigrationParams **migParams);
+void
+qemuMigrationParamsSetCap(qemuMigrationParams *migParams,
+ virQEMUCapsFlags flag);
+
+int
+qemuMigrationParamsSetInt(qemuMigrationParams *migParams,
+ qemuMigrationParam param,
+ int value);
+
int
qemuMigrationParamsSetULL(qemuMigrationParams *migParams,
qemuMigrationParam param,
diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c
index bb23788a5e..9147acd70a 100644
--- a/src/qemu/qemu_saveimage.c
+++ b/src/qemu/qemu_saveimage.c
@@ -492,8 +492,7 @@ qemuSaveImageCreate(virQEMUDriver *driver,
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)
+ if (qemuMigrationSrcToFilesMultiFd(driver, vm, asyncJob, sun_path, nconn) <
0)
goto cleanup;
if (qemuSaveImageCloseMultiFd(multiFd, nconn, vm) < 0)
goto cleanup;
--
2.34.1