[libvirt] [PATCH resend v2 1/2] qemu: Allow saving QEMU libvirt state to a pipe

Chen Hanxiao chen_han_xiao at 126.com
Wed Jan 18 01:05:13 UTC 2017


From: Chen Hanxiao <chenhanxiao at gmail.com>

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





More information about the libvir-list mailing list