[libvirt RFCv11 06/33] qemu: saveimage: introduce virQEMUSaveFd

Claudio Fontana cfontana at suse.de
Tue Jun 7 09:19:09 UTC 2022


use this data type to encapsulate the pathname,
file descriptor, wrapper, and need to unlink.

We also carry along the oflags used to open the file,
and the driver configuration.

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 at suse.de>
---
 src/qemu/qemu_saveimage.c | 115 ++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_saveimage.h |  23 ++++++++
 2 files changed, 138 insertions(+)

diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c
index af97f45114..4c440098fa 100644
--- a/src/qemu/qemu_saveimage.c
+++ b/src/qemu/qemu_saveimage.c
@@ -396,6 +396,121 @@ qemuSaveImageGetCompressionCommand(virQEMUSaveFormat compression)
     return ret;
 }
 
+/*
+ * virQEMUSaveFdInit: initialize a virQEMUSaveFd
+ *
+ * @saveFd:   the structure to initialize
+ * @base:     the file name
+ * @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 oflags, virQEMUDriverConfig *cfg)
+{
+    unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
+    bool isCreat = oflags & O_CREAT;
+    bool isDirect = O_DIRECT && (oflags & O_DIRECT);
+
+    saveFd->oflags = oflags;
+    saveFd->cfg = cfg;
+
+    if (isDirect)
+        wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
+
+    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;
+    /*
+     * For O_CREAT, we always add the wrapper,
+     * and for !O_CREAT, we only add the wrapper if using O_DIRECT.
+     */
+    if (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 f12374b3d7..5768e31fa6 100644
--- a/src/qemu/qemu_saveimage.h
+++ b/src/qemu/qemu_saveimage.h
@@ -54,6 +54,29 @@ struct _virQEMUSaveData {
 };
 
 
+typedef struct _virQEMUSaveFd virQEMUSaveFd;
+struct _virQEMUSaveFd {
+    char *path;
+    int fd;
+    int oflags;
+    bool need_unlink;
+    virFileWrapperFd *wrapper;
+    virQEMUDriverConfig *cfg;
+};
+
+#define QEMU_SAVEFD_INVALID (virQEMUSaveFd) { \
+        .path = NULL, .fd = -1, .oflags = 0, \
+        .need_unlink = false, .wrapper = NULL, .cfg = NULL, \
+}
+
+int virQEMUSaveFdInit(virQEMUSaveFd *saveFd, const char *base,
+                      int oflags, virQEMUDriverConfig *cfg)
+    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4);
+
+int virQEMUSaveFdClose(virQEMUSaveFd *saveFd, virDomainObj *vm);
+
+int virQEMUSaveFdFini(virQEMUSaveFd *saveFd, virDomainObj *vm, int ret);
+
 virDomainDef *
 qemuSaveImageUpdateDef(virQEMUDriver *driver,
                        virDomainDef *def,
-- 
2.26.2



More information about the libvir-list mailing list