From: Chen Hanxiao <chenhanxiao@xxxxxxxxx> Base upon patches from Roy Keene <rkeene@xxxxxxxxxxxxxxx> Currently qemuDomainSaveMemory can save vm's config and memory to fd. It write a magic QEMU_SAVE_PARTIAL firstly, then re-open it to change QEMU_SAVE_PARTIAL as QEMU_SAVE_MAGIC. For pipes this is not possible, attempting to re-open the pipe will not connect you to the same consumer. Seeking is also not possible on a pipe. This patch introduce VIR_DOMAIN_SAVE_DIRECT If set, write QEMU_SAVE_MAGIC directly. This is useful to me for saving a VM state directly to Ceph RBD images without having an intermediate file. Signed-off-by: Roy Keene <rkeene@xxxxxxxxxxxxxxx> Signed-off-by: Chen Hanxiao <chenhanxiao@xxxxxxxxx> --- v2-resend: rebase on upstream v2: rename VIR_DOMAIN_SAVE_PIPE to VIR_DOMAIN_SAVE_DIRECT remove S_ISFIFO check for dst path include/libvirt/libvirt-domain.h | 1 + src/qemu/qemu_driver.c | 54 ++++++++++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h index e303140..b28b9a4 100644 --- a/include/libvirt/libvirt-domain.h +++ b/include/libvirt/libvirt-domain.h @@ -1169,6 +1169,7 @@ typedef enum { VIR_DOMAIN_SAVE_BYPASS_CACHE = 1 << 0, /* Avoid file system cache pollution */ VIR_DOMAIN_SAVE_RUNNING = 1 << 1, /* Favor running over paused */ VIR_DOMAIN_SAVE_PAUSED = 1 << 2, /* Favor paused over running */ + VIR_DOMAIN_SAVE_DIRECT = 1 << 3, /* Write QEMU_SAVE_MAGIC directly */ } virDomainSaveRestoreFlags; int virDomainSave (virDomainPtr domain, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d4422f3..e44d0c6 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3059,6 +3059,7 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver, virQEMUSaveHeader header; bool bypassSecurityDriver = false; bool needUnlink = false; + bool canReopen = true; int ret = -1; int fd = -1; int directFlag = 0; @@ -3066,7 +3067,6 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver, unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING; memset(&header, 0, sizeof(header)); - memcpy(header.magic, QEMU_SAVE_PARTIAL, sizeof(header.magic)); header.version = QEMU_SAVE_VERSION; header.was_running = was_running ? 1 : 0; header.compressed = compressed; @@ -3082,6 +3082,7 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver, goto cleanup; } } + fd = qemuOpenFile(driver, vm, path, O_WRONLY | O_TRUNC | O_CREAT | directFlag, &needUnlink, &bypassSecurityDriver); @@ -3094,6 +3095,20 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver, if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags))) goto cleanup; + /* Set the header magic. + * Setting flags VIR_DOMAIN_SAVE_DIRECT will write + * magic QEMU_SAVE_MAGIC directly. + * For PIPE, we should do this because it can't be reopen. + * Otherwise we'll update the magic after + * the saving completes successfully. + */ + if (flags & VIR_DOMAIN_SAVE_DIRECT) { + canReopen = false; + memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic)); + } else { + memcpy(header.magic, QEMU_SAVE_PARTIAL, sizeof(header.magic)); + } + /* Write header to file, followed by XML */ if (qemuDomainSaveHeader(fd, path, domXML, &header) < 0) goto cleanup; @@ -3102,28 +3117,30 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver, if (qemuMigrationToFile(driver, vm, fd, compressedpath, asyncJob) < 0) goto cleanup; - /* Touch up file header to mark image complete. */ + if (canReopen) { + /* Touch up file header to mark image complete. */ - /* Reopen the file to touch up the header, since we aren't set - * up to seek backwards on wrapperFd. The reopened fd will - * trigger a single page of file system cache pollution, but - * that's acceptable. */ - if (VIR_CLOSE(fd) < 0) { - virReportSystemError(errno, _("unable to close %s"), path); - goto cleanup; - } + /* Reopen the file to touch up the header, since we aren't set + * up to seek backwards on wrapperFd. The reopened fd will + * trigger a single page of file system cache pollution, but + * that's acceptable. */ + if (VIR_CLOSE(fd) < 0) { + virReportSystemError(errno, _("unable to close %s"), path); + goto cleanup; + } - if (virFileWrapperFdClose(wrapperFd) < 0) - goto cleanup; + if (virFileWrapperFdClose(wrapperFd) < 0) + goto cleanup; - if ((fd = qemuOpenFile(driver, vm, path, O_WRONLY, NULL, NULL)) < 0) - goto cleanup; + if ((fd = qemuOpenFile(driver, vm, path, O_WRONLY, NULL, NULL)) < 0) + goto cleanup; - memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic)); + memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic)); - if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) { - virReportSystemError(errno, _("unable to write %s"), path); - goto cleanup; + if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) { + virReportSystemError(errno, _("unable to write %s"), path); + goto cleanup; + } } if (VIR_CLOSE(fd) < 0) { @@ -3353,6 +3370,7 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml, virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE | VIR_DOMAIN_SAVE_RUNNING | + VIR_DOMAIN_SAVE_DIRECT | VIR_DOMAIN_SAVE_PAUSED, -1); cfg = virQEMUDriverGetConfig(driver); -- 2.7.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list