From: Chen Hanxiao <chenhanxiao(a)gmail.com>
Base upon patches from Roy Keene <rkeene(a)knightpoint.com>
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(a)knightpoint.com>
Signed-off-by: Chen Hanxiao <chenhanxiao(a)gmail.com>
---
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