Signed-off-by: Jim Fehlig <jfehlig(a)suse.com>
---
I'm not happy with this and the subsequent patch, which pass another FD
around for QEMU to use for reading/writing unaligned state when
BYPASS_CACHE has been specified. One idea is to pass the qemuFdPass object
around the various functions, but qemu_fd.h already includes qemu_monitor.h.
E.g. passing a qemuFdPass to qemuMonitorMigrateToMappedFile requires
including qemu_fd.h in qemu_monitor.h, so a cyclical dependency. I could
move qemuFDPass*TransferMonitor* functions to qemu_monitor.[ch] to avoid
the include in qemu_fd.h, but would likely require moving the _qemuFDPass
struct in qemu_fd.c to qemu_fd.h.
Another idea is to move qemuProcessIncomingDefNew in qemu_process.c to
qemuMigrationConnectionDefNew() in qemu_migration.c. Also move
qemuProcessIncomingDef object in qemu_process.h to qemuMigrationConnectDef
(or something like that) in qemu_migration.h. The qemuMigrationConnectDef
can encapsulate all the connection info related to the migration. E.g.
traditional fd, path associated with fd, uri, listen address, qemuFDPass
object containing fds for mapped_ram, etc. This can be used by both save
and restore paths.
Other suggestions kindly welcomed :-).
src/qemu/qemu_migration.c | 3 ++-
src/qemu/qemu_migration.h | 1 +
src/qemu/qemu_monitor.c | 14 +++++++++++---
src/qemu/qemu_monitor.h | 3 ++-
src/qemu/qemu_saveimage.c | 25 +++++++++++++++++--------
5 files changed, 33 insertions(+), 13 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index b1d27e07e1..a0435a0572 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -7084,6 +7084,7 @@ qemuMigrationSrcToFile(virQEMUDriver *driver, virDomainObj *vm,
int
qemuMigrationSrcToMappedFile(virQEMUDriver *driver, virDomainObj *vm,
int fd,
+ int nondirectFD,
virDomainAsyncJob asyncJob)
{
qemuDomainObjPrivate *priv = vm->privateData;
@@ -7121,7 +7122,7 @@ qemuMigrationSrcToMappedFile(virQEMUDriver *driver, virDomainObj
*vm,
if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0)
goto cleanup;
- rc = qemuMonitorMigrateToFdSet(vm, 0, fd);
+ rc = qemuMonitorMigrateToFdSet(vm, 0, fd, nondirectFD);
qemuDomainObjExitMonitor(vm);
if (rc < 0)
goto cleanup;
diff --git a/src/qemu/qemu_migration.h b/src/qemu/qemu_migration.h
index 864f3280e5..939205ef13 100644
--- a/src/qemu/qemu_migration.h
+++ b/src/qemu/qemu_migration.h
@@ -245,6 +245,7 @@ int
qemuMigrationSrcToMappedFile(virQEMUDriver *driver,
virDomainObj *vm,
int fd,
+ int nondirectFD,
virDomainAsyncJob asyncJob)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 4c92bd740a..c0936bee6b 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 nondirectFD)
{
qemuDomainObjPrivate *priv = vm->privateData;
qemuMonitor *mon = priv->mon;
@@ -2249,15 +2250,22 @@ qemuMonitorMigrateToFdSet(virDomainObj *vm,
unsigned int setId;
g_autofree char *uri = NULL;
- VIR_DEBUG("fd=%d flags=0x%x", fd, flags);
+ VIR_DEBUG("fd=%d nondirectFD=%d flags=0x%x", fd, nondirectFD, flags);
QEMU_CHECK_MONITOR(mon);
- if ((offset = lseek(fd, 0, SEEK_CUR)) == -1)
+ if (nondirectFD != -1)
+ offset = lseek(nondirectFD, 0, SEEK_CUR);
+ else
+ offset = lseek(fd, 0, SEEK_CUR);
+
+ if (offset == -1)
return -1;
fdPassMigrate = qemuFDPassNew("migrate", priv);
qemuFDPassAddFD(fdPassMigrate, &fd, "-fd");
+ if (nondirectFD != -1)
+ qemuFDPassAddFD(fdPassMigrate, &nondirectFD, "-nondirect-fd");
qemuFDPassTransferMonitor(fdPassMigrate, mon);
if (qemuFDPassGetId(fdPassMigrate, &setId) < 0)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index c477def138..0fbb2dadc1 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -845,7 +845,8 @@ int qemuMonitorMigrateToFd(qemuMonitor *mon,
int qemuMonitorMigrateToFdSet(virDomainObj *vm,
unsigned int flags,
- int fd);
+ int fd,
+ int nondirectFD);
int qemuMonitorMigrateToHost(qemuMonitor *mon,
unsigned int flags,
diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c
index 1545c00472..2b0281895a 100644
--- a/src/qemu/qemu_saveimage.c
+++ b/src/qemu/qemu_saveimage.c
@@ -431,19 +431,28 @@ qemuSaveImageCreateMapped(virQEMUDriver *driver,
virDomainAsyncJob asyncJob)
{
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+ VIR_AUTOCLOSE nondirectFD = -1;
- /* mapped-ram does not support directIO */
+ /* If BYPASS_CACHE has been specified, fd has been opened with O_DIRECT.
+ * In this case, QEMU requires a second FD without O_DIRECT for writing
+ * unaligned state. We'll use this FD as well to write the header.
+ * Relative to VM RAM size, this data is a drop in the bucket and fine
+ * to write without O_DIRECT.
+ */
if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
- virReportError(VIR_ERR_OPERATION_FAILED, "%s",
- _("bypass cache unsupported by this system"));
- return -1;
+ if ((nondirectFD = qemuDomainOpenFile(cfg, vm->def, path, O_WRONLY, NULL))
< 0)
+ return -1;
+ if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def,
nondirectFD) < 0)
+ return -1;
+ if (virQEMUSaveDataWrite(data, nondirectFD, path) < 0)
+ return -1;
+ } else {
+ if (virQEMUSaveDataWrite(data, fd, path) < 0)
+ return -1;
}
- if (virQEMUSaveDataWrite(data, fd, path) < 0)
- return -1;
-
/* Perform the migration */
- return qemuMigrationSrcToMappedFile(driver, vm, fd, asyncJob);
+ return qemuMigrationSrcToMappedFile(driver, vm, fd, nondirectFD, asyncJob);
}
--
2.44.0