]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: Decompose qemuSaveImageOpen
authorJim Fehlig via Devel <devel@lists.libvirt.org>
Fri, 31 Jan 2025 02:29:03 +0000 (19:29 -0700)
committerMichal Privoznik <mprivozn@redhat.com>
Fri, 31 Jan 2025 07:53:51 +0000 (08:53 +0100)
Split the reading of libvirt's save image metadata from the opening
of the fd that will be passed to QEMU. This allows improved error
handling and provides more flexibility users of qemu_saveimage.

Signed-off-by: Jim Fehlig <jfehlig@suse.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
src/qemu/qemu_driver.c
src/qemu/qemu_saveimage.c
src/qemu/qemu_saveimage.h
src/qemu/qemu_snapshot.c

index 2e80ce79219c5c267a2dbe436a396b7c8ce962f6..f326937585a189eaacce042297141db14e64c059 100644 (file)
@@ -5775,7 +5775,10 @@ qemuDomainRestoreInternal(virConnectPtr conn,
     if (flags & VIR_DOMAIN_SAVE_RESET_NVRAM)
         reset_nvram = true;
 
-    fd = qemuSaveImageOpen(driver, NULL, path, &def, &data,
+    if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0)
+        goto cleanup;
+
+    fd = qemuSaveImageOpen(driver, path,
                            (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
                            &wrapperFd, false);
     if (fd < 0)
@@ -5906,15 +5909,11 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
     virQEMUDriver *driver = conn->privateData;
     char *ret = NULL;
     g_autoptr(virDomainDef) def = NULL;
-    int fd = -1;
     virQEMUSaveData *data = NULL;
 
     virCheckFlags(VIR_DOMAIN_SAVE_IMAGE_XML_SECURE, NULL);
 
-    fd = qemuSaveImageOpen(driver, NULL, path, &def, &data,
-                           false, NULL, false);
-
-    if (fd < 0)
+    if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0)
         goto cleanup;
 
     if (virDomainSaveImageGetXMLDescEnsureACL(conn, def) < 0)
@@ -5924,7 +5923,6 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
 
  cleanup:
     virQEMUSaveDataFree(data);
-    VIR_FORCE_CLOSE(fd);
     return ret;
 }
 
@@ -5948,9 +5946,10 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
     else if (flags & VIR_DOMAIN_SAVE_PAUSED)
         state = 0;
 
-    fd = qemuSaveImageOpen(driver, NULL, path, &def, &data,
-                           false, NULL, true);
+    if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0)
+        goto cleanup;
 
+    fd = qemuSaveImageOpen(driver, path, 0, NULL, false);
     if (fd < 0)
         goto cleanup;
 
@@ -6007,7 +6006,6 @@ qemuDomainManagedSaveGetXMLDesc(virDomainPtr dom, unsigned int flags)
     g_autofree char *path = NULL;
     char *ret = NULL;
     g_autoptr(virDomainDef) def = NULL;
-    int fd = -1;
     virQEMUSaveData *data = NULL;
     qemuDomainObjPrivate *priv;
 
@@ -6029,15 +6027,13 @@ qemuDomainManagedSaveGetXMLDesc(virDomainPtr dom, unsigned int flags)
         goto cleanup;
     }
 
-    if ((fd = qemuSaveImageOpen(driver, priv->qemuCaps, path, &def, &data,
-                                false, NULL, false)) < 0)
+    if (qemuSaveImageGetMetadata(driver, priv->qemuCaps, path, &def, &data) < 0)
         goto cleanup;
 
     ret = qemuDomainDefFormatXML(driver, priv->qemuCaps, def, flags);
 
  cleanup:
     virQEMUSaveDataFree(data);
-    VIR_FORCE_CLOSE(fd);
     virDomainObjEndAPI(&vm);
     return ret;
 }
@@ -6093,9 +6089,8 @@ qemuDomainObjRestore(virConnectPtr conn,
     virQEMUSaveData *data = NULL;
     virFileWrapperFd *wrapperFd = NULL;
 
-    fd = qemuSaveImageOpen(driver, NULL, path, &def, &data,
-                           bypass_cache, &wrapperFd, false);
-    if (fd < 0) {
+    ret = qemuSaveImageGetMetadata(driver, NULL, path, &def, &data);
+    if (ret < 0) {
         if (qemuSaveImageIsCorrupt(driver, path)) {
             if (unlink(path) < 0) {
                 virReportSystemError(errno,
@@ -6110,6 +6105,10 @@ qemuDomainObjRestore(virConnectPtr conn,
         goto cleanup;
     }
 
+    fd = qemuSaveImageOpen(driver, path, bypass_cache, &wrapperFd, false);
+    if (fd < 0)
+        goto cleanup;
+
     if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
         int hookret;
 
index 385ac8a649839d4ad3dbc939102563eb9d57a430..8315171b786547602e0d468b3d80f724ef9d645c 100644 (file)
@@ -249,6 +249,84 @@ qemuSaveImageGetCompressionCommand(virQEMUSaveFormat format)
 }
 
 
+static int
+qemuSaveImageReadHeader(int fd, virQEMUSaveData **ret_data)
+{
+    g_autoptr(virQEMUSaveData) data = NULL;
+    virQEMUSaveHeader *header;
+    size_t xml_len;
+    size_t cookie_len;
+
+    data = g_new0(virQEMUSaveData, 1);
+    header = &data->header;
+    if (saferead(fd, header, sizeof(*header)) != sizeof(*header)) {
+         virReportError(VIR_ERR_OPERATION_FAILED,
+                        "%s", _("failed to read qemu header"));
+         return -1;
+    }
+
+    if (memcmp(header->magic, QEMU_SAVE_MAGIC, sizeof(header->magic)) != 0) {
+        if (memcmp(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic)) == 0) {
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("save image is incomplete"));
+            return -1;
+        }
+
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("image magic is incorrect"));
+        return -1;
+    }
+
+    if (header->version > QEMU_SAVE_VERSION) {
+        /* convert endianness and try again */
+        qemuSaveImageBswapHeader(header);
+    }
+
+    if (header->version > QEMU_SAVE_VERSION) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("image version is not supported (%1$d > %2$d)"),
+                       header->version, QEMU_SAVE_VERSION);
+        return -1;
+    }
+
+    if (header->data_len <= 0) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("invalid header data length: %1$d"), header->data_len);
+        return -1;
+    }
+
+    if (header->cookieOffset)
+        xml_len = header->cookieOffset;
+    else
+        xml_len = header->data_len;
+
+    cookie_len = header->data_len - xml_len;
+
+    data->xml = g_new0(char, xml_len);
+
+    if (saferead(fd, data->xml, xml_len) != xml_len) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       "%s", _("failed to read domain XML"));
+        return -1;
+    }
+
+    if (cookie_len > 0) {
+        data->cookie = g_new0(char, cookie_len);
+
+        if (saferead(fd, data->cookie, cookie_len) != cookie_len) {
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("failed to read cookie"));
+            return -1;
+        }
+    }
+
+    if (ret_data)
+        *ret_data = g_steal_pointer(&data);
+
+    return 0;
+}
+
+
 /**
  * qemuSaveImageDecompressionStart:
  * @data: data from memory state file
@@ -520,6 +598,7 @@ qemuSaveImageGetCompressionProgram(const char *imageFormat,
     return -1;
 }
 
+
 /**
  * qemuSaveImageIsCorrupt:
  * @driver: qemu driver data
@@ -551,26 +630,61 @@ qemuSaveImageIsCorrupt(virQEMUDriver *driver, const char *path)
 
 
 /**
- * qemuSaveImageOpen:
+ * qemuSaveImageGetMetadata:
  * @driver: qemu driver data
  * @qemuCaps: pointer to qemuCaps if the domain is running or NULL
  * @path: path of the save image
  * @ret_def: returns domain definition created from the XML stored in the image
  * @ret_data: returns structure filled with data from the image header
+ *
+ * Open the save image file, read libvirt's save image metadata, and populate
+ * the @ret_def and @ret_data structures. Returns 0 on success and -1 on failure.
+ */
+int
+qemuSaveImageGetMetadata(virQEMUDriver *driver,
+                         virQEMUCaps *qemuCaps,
+                         const char *path,
+                         virDomainDef **ret_def,
+                         virQEMUSaveData **ret_data)
+{
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
+    VIR_AUTOCLOSE fd = -1;
+    virQEMUSaveData *data;
+    g_autoptr(virDomainDef) def = NULL;
+    int rc;
+
+    if ((fd = qemuDomainOpenFile(cfg, NULL, path, O_RDONLY, NULL)) < 0)
+        return -1;
+
+    if ((rc = qemuSaveImageReadHeader(fd, ret_data)) < 0)
+        return rc;
+
+    data = *ret_data;
+    /* Create a domain from this XML */
+    if (!(def = virDomainDefParseString(data->xml, driver->xmlopt, qemuCaps,
+                                        VIR_DOMAIN_DEF_PARSE_INACTIVE |
+                                        VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
+        return -1;
+
+    *ret_def = g_steal_pointer(&def);
+
+    return 0;
+}
+
+
+/**
+ * qemuSaveImageOpen:
+ * @driver: qemu driver data
+ * @path: path of the save image
  * @bypass_cache: bypass cache when opening the file
  * @wrapperFd: returns the file wrapper structure
  * @open_write: open the file for writing (for updates)
  *
- * Returns the opened fd of the save image file and fills the appropriate fields
- * on success. On error returns -1 on most failures, -3 if a corrupt image was
- * detected.
+ * Returns the opened fd of the save image file on success, -1 on failure.
  */
 int
 qemuSaveImageOpen(virQEMUDriver *driver,
-                  virQEMUCaps *qemuCaps,
                   const char *path,
-                  virDomainDef **ret_def,
-                  virQEMUSaveData **ret_data,
                   bool bypass_cache,
                   virFileWrapperFd **wrapperFd,
                   bool open_write)
@@ -578,12 +692,7 @@ qemuSaveImageOpen(virQEMUDriver *driver,
     g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
     VIR_AUTOCLOSE fd = -1;
     int ret = -1;
-    g_autoptr(virQEMUSaveData) data = NULL;
-    virQEMUSaveHeader *header;
-    g_autoptr(virDomainDef) def = NULL;
     int oflags = open_write ? O_RDWR : O_RDONLY;
-    size_t xml_len;
-    size_t cookie_len;
 
     if (bypass_cache) {
         int directFlag = virFileDirectFdFlag();
@@ -603,79 +712,11 @@ qemuSaveImageOpen(virQEMUDriver *driver,
                                            VIR_FILE_WRAPPER_BYPASS_CACHE)))
         return -1;
 
-    data = g_new0(virQEMUSaveData, 1);
-
-    header = &data->header;
-    if (saferead(fd, header, sizeof(*header)) != sizeof(*header)) {
-        virReportError(VIR_ERR_OPERATION_FAILED,
-                       "%s", _("failed to read qemu header"));
-        return -1;
-    }
-
-    if (memcmp(header->magic, QEMU_SAVE_MAGIC, sizeof(header->magic)) != 0) {
-        if (memcmp(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic)) == 0) {
-            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                           _("save image is incomplete"));
-            return -1;
-        }
-
-        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                       _("image magic is incorrect"));
-        return -1;
-    }
-
-    if (header->version > QEMU_SAVE_VERSION) {
-        /* convert endianness and try again */
-        qemuSaveImageBswapHeader(header);
-    }
-
-    if (header->version > QEMU_SAVE_VERSION) {
-        virReportError(VIR_ERR_OPERATION_FAILED,
-                       _("image version is not supported (%1$d > %2$d)"),
-                       header->version, QEMU_SAVE_VERSION);
-        return -1;
-    }
-
-    if (header->data_len <= 0) {
-        virReportError(VIR_ERR_OPERATION_FAILED,
-                       _("invalid header data length: %1$d"), header->data_len);
-        return -1;
-    }
-
-    if (header->cookieOffset)
-        xml_len = header->cookieOffset;
-    else
-        xml_len = header->data_len;
-
-    cookie_len = header->data_len - xml_len;
-
-    data->xml = g_new0(char, xml_len);
-
-    if (saferead(fd, data->xml, xml_len) != xml_len) {
-        virReportError(VIR_ERR_OPERATION_FAILED,
-                       "%s", _("failed to read domain XML"));
-        return -1;
-    }
-
-    if (cookie_len > 0) {
-        data->cookie = g_new0(char, cookie_len);
-
-        if (saferead(fd, data->cookie, cookie_len) != cookie_len) {
-            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
-                           _("failed to read cookie"));
-            return -1;
-        }
-    }
-
-    /* Create a domain from this XML */
-    if (!(def = virDomainDefParseString(data->xml, driver->xmlopt, qemuCaps,
-                                        VIR_DOMAIN_DEF_PARSE_INACTIVE |
-                                        VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
+    /* Read the header to position the file pointer for QEMU. Unfortunately we
+     * can't use lseek with virFileWrapperFD. */
+    if (qemuSaveImageReadHeader(fd, NULL) < 0)
         return -1;
 
-    *ret_def = g_steal_pointer(&def);
-    *ret_data = g_steal_pointer(&data);
-
     ret = fd;
     fd = -1;
 
index dc49f8463f3823353672da13f784e103e0cf8977..53ae222467a4464cb299bc139d07f2d1682e3603 100644 (file)
@@ -74,16 +74,21 @@ qemuSaveImageIsCorrupt(virQEMUDriver *driver,
                        const char *path)
     ATTRIBUTE_NONNULL(2);
 
+int
+qemuSaveImageGetMetadata(virQEMUDriver *driver,
+                         virQEMUCaps *qemuCaps,
+                         const char *path,
+                         virDomainDef **ret_def,
+                         virQEMUSaveData **ret_data)
+    ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
+
 int
 qemuSaveImageOpen(virQEMUDriver *driver,
-                  virQEMUCaps *qemuCaps,
                   const char *path,
-                  virDomainDef **ret_def,
-                  virQEMUSaveData **ret_data,
                   bool bypass_cache,
                   virFileWrapperFd **wrapperFd,
                   bool open_write)
-    ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
+    ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4);
 
 int
 qemuSaveImageGetCompressionProgram(const char *imageFormat,
index b9c398347219ea735a0b1dbb4f7f85e3c7d9a57e..7ce018b026c19e87f64e35b014cc4795a90b241a 100644 (file)
@@ -2377,10 +2377,12 @@ qemuSnapshotRevertExternalPrepare(virDomainObj *vm,
         g_autoptr(virDomainDef) savedef = NULL;
 
         memdata->path = snapdef->memorysnapshotfile;
-        memdata->fd = qemuSaveImageOpen(driver, NULL, memdata->path,
-                                        &savedef, &memdata->data,
-                                        false, NULL, false);
+        if (qemuSaveImageGetMetadata(driver, NULL, memdata->path, &savedef,
+                                     &memdata->data) < 0)
+            return -1;
 
+        memdata->fd = qemuSaveImageOpen(driver, memdata->path,
+                                        false, NULL, false);
         if (memdata->fd < 0)
             return -1;