[libvirt RFC v2 04/11] qemu: initial implementation for the virDomainSaveParametersFlags API

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



make the qemuDomainSaveParametersFlags minimally functional
by preparing the files for the multifd channels, but stop short of
using them, relying on normal migration to file for now.

Signed-off-by: Claudio Fontana <cfontana@xxxxxxx>
---
 src/qemu/qemu_saveimage.c | 256 +++++++++++++++++++++++++++++++-------
 src/qemu/qemu_saveimage.h |   8 ++
 2 files changed, 220 insertions(+), 44 deletions(-)

diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c
index 6e7f067be2..6a65d72fb3 100644
--- a/src/qemu/qemu_saveimage.c
+++ b/src/qemu/qemu_saveimage.c
@@ -248,6 +248,192 @@ qemuSaveImageGetCompressionCommand(virQEMUSaveFormat compression)
     return ret;
 }
 
+/*
+ * virQEMUSaveFdInit: initialize a virQEMUSaveFd
+ *
+ * @saveFd: the structure to initialize
+ * @base:   the main file name
+ * @idx:    0 for the main file, >0 for multifd channels.
+ * @user:   uid
+ * @group:  gid
+ * @flags:  the general flags
+ *
+ * Returns -1 on error, 0 on success,
+ * and in both cases virQEMUSaveFdFini must be called to free resources.
+ */
+static int virQEMUSaveFdInit(virQEMUSaveFd *saveFd, const char *base, int idx,
+                             uid_t user, gid_t group, unsigned int flags)
+{
+    unsigned int directFlag = 0;
+    unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
+
+    if (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) {
+        directFlag = virFileDirectFdFlag();
+        wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
+    }
+    if (idx > 0) {
+        saveFd->path = g_strdup_printf("%s.%d", base, idx);
+    } else {
+        saveFd->path = g_strdup(base);
+    }
+    saveFd->wrapper = NULL;
+    saveFd->fd = virQEMUFileOpenAs(user, group, false, saveFd->path,
+                                   O_WRONLY | O_TRUNC | O_CREAT | directFlag,
+                                   &saveFd->need_unlink);
+    if (saveFd->fd < 0)
+        return -1;
+
+    if (idx > 0) {
+        /* no wrapper required for the multifd channels */
+    } else {
+        saveFd->wrapper = virFileWrapperFdNew(&saveFd->fd, saveFd->path, wrapperFlags);
+        if (!saveFd->wrapper)
+            return -1;
+    }
+    return 0;
+}
+
+/*
+ * virQEMUSaveFdClose: close a virQEMUSaveFd descriptor with normal close.
+ *
+ * @saveFd: the saveFd structure with the file descriptors to close.
+ * @vm:     the virDomainObj (necessary to release lock)
+ *
+ * If saveFd is NULL, the function will return success.
+ *
+ * Returns -1 on error, 0 on success.
+ */
+static int virQEMUSaveFdClose(virQEMUSaveFd *saveFd, virDomainObj *vm)
+{
+    if (!saveFd)
+        return 0;
+
+    if (VIR_CLOSE(saveFd->fd) < 0) {
+        virReportSystemError(errno, _("unable to close %s"), saveFd->path);
+        return -1;
+    }
+    if (qemuDomainFileWrapperFDClose(vm, saveFd->wrapper) < 0)
+        return -1;
+
+    return 0;
+}
+
+/*
+ * virQEMUSaveFdFini: finalize a virQEMUSaveFd
+ *
+ * @saveFd: the saveFd structure containing the resources to free.
+ * @vm:     the virDomainObj (necessary to release lock)
+ * @ret:    the current operation result (< 0 is failure)
+ *
+ * If saveFd is NULL, the return value will be unchanged.
+ *
+ * Returns ret, or -1 if an error is detected.
+ */
+static int virQEMUSaveFdFini(virQEMUSaveFd *saveFd, virDomainObj *vm, int ret)
+{
+    if (!saveFd)
+        return ret;
+    VIR_FORCE_CLOSE(saveFd->fd);
+    if (qemuDomainFileWrapperFDClose(vm, saveFd->wrapper) < 0) {
+        ret = -1;
+    }
+    if (ret < 0 && saveFd->need_unlink && saveFd->path) {
+        unlink(saveFd->path);
+    }
+    if (saveFd->wrapper) {
+        virFileWrapperFdFree(saveFd->wrapper);
+        saveFd->wrapper = NULL;
+    }
+
+    g_free(saveFd->path);
+    saveFd->path = NULL;
+    return ret;
+}
+
+/*
+ * qemuSaveImageFreeMultiFd: free all multifd virQEMUSaveFds.
+ * @multiFd: the array of saveFds
+ * @vm:      the virDomainObj, to release lock
+ * @nconn:   number of multifd channels
+ * @ret:     the current operation result (< 0 is failure)
+ *
+ * If multiFd is NULL, the return value will be unchanged.
+ *
+ * Returns ret, or -1 if an error is detected.
+ */
+static int qemuSaveImageFreeMultiFd(virQEMUSaveFd *multiFd, virDomainObj *vm, int nconn, int ret)
+{
+    int i;
+
+    if (!multiFd)
+        return ret;
+
+    for (i = 0; i < nconn; i++) {
+        ret = virQEMUSaveFdFini(&multiFd[i], vm, ret);
+    }
+    /*
+     * do it again to unlink all in the error case,
+     * if error happened in the middle of previous loop.
+     */
+    for (i = 0; i < nconn; i++) {
+        ret = virQEMUSaveFdFini(&multiFd[i], vm, ret);
+    }
+    g_free(multiFd);
+    return ret;
+}
+
+/*
+ * qemuSaveImageCloseMultiFd: perform normal close on all multifd virQEMUSaveFds.
+ * If multiFd is NULL, the function will return success.
+ *
+ * Returns -1 on error, 0 on success.
+ */
+
+static int qemuSaveImageCloseMultiFd(virQEMUSaveFd *multiFd, int nconn, virDomainObj *vm)
+{
+    int i;
+
+    if (!multiFd)
+        return 0;
+
+    for (i = 0; i < nconn; i++) {
+        if (virQEMUSaveFdClose(&multiFd[i], vm) < 0) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/*
+ * qemuSaveImageCreateMultiFd: allocate and initialize all multifd virQEMUSaveFds.
+ *
+ * Returns the new array of virQEMUSaveFds, or NULL on error.
+ */
+
+static virQEMUSaveFd *
+qemuSaveImageCreateMultiFd(virQEMUDriver *driver, virDomainObj *vm,
+                           const char *path, uid_t user, gid_t group,
+                           int nconn, unsigned int flags)
+{
+    virQEMUSaveFd *multiFd = g_new0(virQEMUSaveFd, nconn);
+    int i;
+
+    for (i = 0; i < nconn; i++) {
+        virQEMUSaveFd *m = &multiFd[i];
+        if (virQEMUSaveFdInit(m, path, i + 1, user, group, flags) < 0 ||
+            qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, m->fd) < 0) {
+
+            virQEMUSaveFdFini(m, vm, -1);
+            goto error;
+        }
+    }
+    return multiFd;
+
+ error:
+    qemuSaveImageFreeMultiFd(multiFd, vm, nconn, -1);
+    return NULL;
+}
+
 
 /* Helper function to execute a migration to file with a correct save header
  * the caller needs to make sure that the processors are stopped and do all other
@@ -263,42 +449,35 @@ qemuSaveImageCreate(virQEMUDriver *driver,
                     virDomainAsyncJob asyncJob)
 {
     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
-    bool needUnlink = false;
+    virQEMUSaveFd saveFd;
+    virQEMUSaveFd *multiFd = NULL;
     int ret = -1;
-    int fd = -1;
-    int directFlag = 0;
-    virFileWrapperFd *wrapperFd = NULL;
-    unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
-
-    nconn = nconn; /* unused */
-    /* Obtain the file handle.  */
-    if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
-        wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
-        directFlag = virFileDirectFdFlag();
-        if (directFlag < 0) {
-            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                           _("bypass cache unsupported by this system"));
-            goto cleanup;
-        }
-    }
 
-    fd = virQEMUFileOpenAs(cfg->user, cfg->group, false, path,
-                           O_WRONLY | O_TRUNC | O_CREAT | directFlag,
-                           &needUnlink);
-    if (fd < 0)
+    if (virQEMUSaveFdInit(&saveFd, path, 0, cfg->user, cfg->group, flags) < 0) {
         goto cleanup;
-
-    if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, fd) < 0)
+    }
+    if (qemuSecuritySetImageFDLabel(driver->securityManager, vm->def, saveFd.fd) < 0)
         goto cleanup;
 
-    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
+    if (virQEMUSaveDataWrite(data, saveFd.fd, saveFd.path) < 0)
         goto cleanup;
 
-    if (virQEMUSaveDataWrite(data, fd, path) < 0)
-        goto cleanup;
+    if (flags & VIR_DOMAIN_SAVE_PARALLEL) {
+        /* Perform parallel multifd migration to files (main fd + channels) */
+        if (!(multiFd = qemuSaveImageCreateMultiFd(driver, vm, saveFd.path, cfg->user, cfg->group, nconn, flags)))
+            goto cleanup;
+        /* still using single fd migration for now */
+        if (qemuMigrationSrcToFile(driver, vm, saveFd.fd, compressor, asyncJob) < 0)
+            goto cleanup;
+        if (qemuSaveImageCloseMultiFd(multiFd, nconn, vm) < 0)
+            goto cleanup;
+    } else {
+        /* Perform non-parallel migration to file */
+        if (qemuMigrationSrcToFile(driver, vm, saveFd.fd, compressor, asyncJob) < 0)
+            goto cleanup;
+    }
 
-    /* Perform the migration */
-    if (qemuMigrationSrcToFile(driver, vm, fd, compressor, asyncJob) < 0)
+    if (virQEMUSaveFdClose(&saveFd, vm) < 0)
         goto cleanup;
 
     /* Touch up file header to mark image complete. */
@@ -307,29 +486,18 @@ qemuSaveImageCreate(virQEMUDriver *driver,
      * 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 (qemuDomainFileWrapperFDClose(vm, wrapperFd) < 0)
-        goto cleanup;
 
-    if ((fd = qemuDomainOpenFile(cfg, vm->def, path, O_WRONLY, NULL)) < 0 ||
-        virQEMUSaveDataFinish(data, &fd, path) < 0)
+    if ((saveFd.fd = qemuDomainOpenFile(cfg, vm->def, saveFd.path, O_WRONLY, NULL)) < 0 ||
+        virQEMUSaveDataFinish(data, &saveFd.fd, saveFd.path) < 0)
         goto cleanup;
 
     ret = 0;
 
- cleanup:
-    VIR_FORCE_CLOSE(fd);
-    if (qemuDomainFileWrapperFDClose(vm, wrapperFd) < 0)
-        ret = -1;
-    virFileWrapperFdFree(wrapperFd);
 
-    if (ret < 0 && needUnlink)
-        unlink(path);
+ cleanup:
 
+    ret = qemuSaveImageFreeMultiFd(multiFd, vm, nconn, ret);
+    ret = virQEMUSaveFdFini(&saveFd, vm, ret);
     return ret;
 }
 
diff --git a/src/qemu/qemu_saveimage.h b/src/qemu/qemu_saveimage.h
index b3d5c02fd6..24dcd213a5 100644
--- a/src/qemu/qemu_saveimage.h
+++ b/src/qemu/qemu_saveimage.h
@@ -54,6 +54,14 @@ struct _virQEMUSaveData {
 };
 
 
+typedef struct _virQEMUSaveFd virQEMUSaveFd;
+struct _virQEMUSaveFd {
+    char *path;
+    int fd;
+    bool need_unlink;
+    virFileWrapperFd *wrapper;
+};
+
 virDomainDef *
 qemuSaveImageUpdateDef(virQEMUDriver *driver,
                        virDomainDef *def,
-- 
2.34.1





[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux