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 <cfont...@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

Reply via email to