[libvirt RFCv8 07/27] qemu: saveimage: introduce virQEMUSaveFd

Claudio Fontana posted 27 patches 1 month, 2 weeks ago
[libvirt RFCv8 07/27] qemu: saveimage: introduce virQEMUSaveFd
Posted by Claudio Fontana 1 month, 2 weeks ago
use this data type to encapsulate the pathname,
file descriptor, wrapper, and need to unlink.

This will make management of the resources associated
with an FD used for QEMU save/restore much easier,
reducing the amount of explicit cleanup required.

Signed-off-by: Claudio Fontana <cfontana@suse.de>
---
 src/qemu/qemu_saveimage.c | 117 ++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_saveimage.h |  18 ++++++
 2 files changed, 135 insertions(+)

diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c
index 7c76db359e..67c93e3865 100644
--- a/src/qemu/qemu_saveimage.c
+++ b/src/qemu/qemu_saveimage.c
@@ -248,6 +248,123 @@ 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.
+ * @oflags  the file descriptor open flags
+ * @cfg:    the driver config
+ *
+ * Returns -1 on error, 0 on success,
+ * and in both cases virQEMUSaveFdFini must be called to free resources.
+ */
+int virQEMUSaveFdInit(virQEMUSaveFd *saveFd, const char *base, int idx,
+                      int oflags, virQEMUDriverConfig *cfg)
+{
+    unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
+    bool isCreat = oflags & O_CREAT;
+    bool isDirect = O_DIRECT && (oflags & O_DIRECT);
+
+    if (isDirect)
+        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;
+    if (isCreat) {
+        saveFd->fd = virQEMUFileOpenAs(cfg->user, cfg->group, false, saveFd->path,
+                                       oflags, &saveFd->need_unlink);
+    } else {
+        saveFd->fd = qemuDomainOpenFile(cfg, NULL, saveFd->path, oflags, NULL);
+    }
+    if (saveFd->fd < 0)
+        return -1;
+    /*
+     * no wrapper required for the multifd channels.
+     * For O_CREAT, we always add the wrapper for the main file.
+     * For !O_CREAT, we only add the wrapper if using O_DIRECT.
+     */
+    if (idx == 0 && (isDirect || isCreat)) {
+        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), or NULL.
+ *
+ * If saveFd is NULL, the function will return success.
+ *
+ * Returns -1 on error, 0 on success.
+ */
+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 (vm) {
+        if (qemuDomainFileWrapperFDClose(vm, saveFd->wrapper) < 0)
+            return -1;
+    } else {
+        if (virFileWrapperFdClose(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 for long close ops), or NULL.
+ * @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.
+ */
+int virQEMUSaveFdFini(virQEMUSaveFd *saveFd, virDomainObj *vm, int ret)
+{
+    if (!saveFd)
+        return ret;
+    VIR_FORCE_CLOSE(saveFd->fd);
+    if (vm) {
+        if (qemuDomainFileWrapperFDClose(vm, saveFd->wrapper) < 0)
+            ret = -1;
+    } else {
+        if (virFileWrapperFdClose(saveFd->wrapper) < 0)
+            ret = -1;
+    }
+
+    if (ret < 0 && saveFd->need_unlink && saveFd->path) {
+        if (unlink(saveFd->path) < 0) {
+            virReportSystemError(errno, _("cannot remove file: %s"),
+                                 saveFd->path);
+        }
+    }
+    if (saveFd->wrapper) {
+        virFileWrapperFdFree(saveFd->wrapper);
+        saveFd->wrapper = NULL;
+    }
+
+    g_free(saveFd->path);
+    saveFd->path = NULL;
+    return ret;
+}
+
 
 /* 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
diff --git a/src/qemu/qemu_saveimage.h b/src/qemu/qemu_saveimage.h
index b3d5c02fd6..41937e5eb5 100644
--- a/src/qemu/qemu_saveimage.h
+++ b/src/qemu/qemu_saveimage.h
@@ -54,6 +54,24 @@ struct _virQEMUSaveData {
 };
 
 
+typedef struct _virQEMUSaveFd virQEMUSaveFd;
+struct _virQEMUSaveFd {
+    char *path;
+    int fd;
+    bool need_unlink;
+    virFileWrapperFd *wrapper;
+};
+
+#define QEMU_SAVEFD_INVALID (virQEMUSaveFd) { .path = NULL, .fd = -1, .need_unlink = false, .wrapper = NULL }
+
+int virQEMUSaveFdInit(virQEMUSaveFd *saveFd, const char *base, int idx,
+                      int oflags, virQEMUDriverConfig *cfg)
+    ATTRIBUTE_NONNULL(5);
+
+int virQEMUSaveFdClose(virQEMUSaveFd *saveFd, virDomainObj *vm);
+
+int virQEMUSaveFdFini(virQEMUSaveFd *saveFd, virDomainObj *vm, int ret);
+
 virDomainDef *
 qemuSaveImageUpdateDef(virQEMUDriver *driver,
                        virDomainDef *def,
-- 
2.35.3