[libvirt RFCv9 05/31] qemu: saveimage: introduce virQEMUSaveFd

Claudio Fontana cfontana at suse.de
Sat May 14 15:52:47 UTC 2022


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

diff --git a/src/qemu/qemu_saveimage.c b/src/qemu/qemu_saveimage.c
index 7db54f11e1..63c3116407 100644
--- a/src/qemu/qemu_saveimage.c
+++ b/src/qemu/qemu_saveimage.c
@@ -354,6 +354,118 @@ 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);
+
+    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 58d0949b9c..21cb1dc78d 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 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.35.3



More information about the libvir-list mailing list