On Sat, Dec 03, 2016 at 17:45:47 +0800, Chen Hanxiao wrote:
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 writes a magic QEMU_SAVE_PARTIAL firstly,
then re-open it to change QEMU_SAVE_PARTIAL as QEMU_SAVE_MAGIC
after a success write.
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_PIPE.
If set, write QEMU_SAVE_MAGIC directly.
Try to write a regular file with VIR_DOMAIN_SAVE_PIPE
is not supportted.
This is useful to me for saving a VM state directly to
Ceph RBD images without having an intermediate file.
Cc: Roy Keene <rkeene(a)knightpoint.com>
Signed-off-by: Chen Hanxiao <chenhanxiao(a)gmail.com>
---
include/libvirt/libvirt-domain.h | 1 +
src/qemu/qemu_driver.c | 71 ++++++++++++++++++++++++++++++----------
2 files changed, 54 insertions(+), 18 deletions(-)
diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h
index a8435ab..c3e4c15 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_PIPE = 1 << 3, /* Output is a pipe */
It doesn't have necessarily to be a pipe.
} virDomainSaveRestoreFlags;
int virDomainSave (virDomainPtr domain,
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 3517aa2..58422ac 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3054,14 +3054,15 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
virQEMUSaveHeader header;
bool bypassSecurityDriver = false;
bool needUnlink = false;
+ bool canReopen = true;
int ret = -1;
int fd = -1;
int directFlag = 0;
virFileWrapperFdPtr wrapperFd = NULL;
unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
+ struct stat statbuf;
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;
@@ -3077,6 +3078,27 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
goto cleanup;
}
}
+
+ /*
+ * Determine if this file is a PIPE, which could not be reopen.
+ */
+ if (virFileExists(path)) {
+ fd = qemuOpenFile(driver, vm, path, O_RDONLY | O_NONBLOCK, NULL, NULL);
+ if (fd < 0)
+ goto cleanup;
+ if (fstat(fd, &statbuf) < 0)
+ goto cleanup;
+ if (S_ISFIFO(statbuf.st_mode)) {
You should not try to check this. If the user wishes to write the
complete header right away, then we should obey it and not have to check
prior to do so.
+ if (flags & VIR_DOMAIN_SAVE_PIPE) {
+ canReopen = false;
+ } else {
+ virReportSystemError(EINVAL, _("%s is not PIPE"), path);
+ goto cleanup;
+ }
+ }
+ VIR_FORCE_CLOSE(fd);
+ }
+
fd = qemuOpenFile(driver, vm, path,
O_WRONLY | O_TRUNC | O_CREAT | directFlag,
&needUnlink, &bypassSecurityDriver);