Signed-off-by: Jim Fehlig <jfehlig@xxxxxxxx> --- 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