]> xenbits.xensource.com Git - libvirt.git/commitdiff
save: support qemu modifying xml on domain save/restore
authorEric Blake <eblake@redhat.com>
Mon, 18 Jul 2011 23:27:59 +0000 (17:27 -0600)
committerEric Blake <eblake@redhat.com>
Thu, 28 Jul 2011 21:31:08 +0000 (15:31 -0600)
With this, it is possible to update the path to a disk backing
image on either the save or restore action, without having to
binary edit the XML embedded in the state file.

This also modifies virDomainSave to output a smaller xml (only
the inactive xml, which is all the more virDomainRestore parses),
while still guaranteeing padding for most typical abi-compatible
xml replacements, necessary so that the next patch for
virDomainSaveImageDefineXML will not cause unnecessary
modifications to the save image file.

* src/qemu/qemu_driver.c (qemuDomainSaveInternal): Add parameter,
only use inactive state, and guarantee padding.
(qemuDomainSaveImageOpen): Add parameter.
(qemuDomainSaveFlags, qemuDomainManagedSave)
(qemuDomainRestoreFlags, qemuDomainObjRestore): Update callers.

src/qemu/qemu_driver.c

index d45c7c56acaa0d1df4b0b1350d353f9d6156670b..5e0825c02f22cba90da75a464f1fc7717df2431a 100644 (file)
@@ -2194,7 +2194,7 @@ qemuCompressProgramName(int compress)
 static int
 qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
                        virDomainObjPtr vm, const char *path,
-                       int compressed, bool bypass_cache)
+                       int compressed, bool bypass_cache, const char *xmlin)
 {
     char *xml = NULL;
     struct qemud_save_header header;
@@ -2205,7 +2205,9 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
     qemuDomainObjPrivatePtr priv;
     struct stat sb;
     bool is_reg = false;
+    size_t len;
     unsigned long long offset;
+    unsigned long long pad;
     int fd = -1;
     uid_t uid = getuid();
     gid_t gid = getgid();
@@ -2240,15 +2242,55 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
         }
     }
 
-    /* Get XML for the domain */
-    xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
+    /* Get XML for the domain.  Restore needs only the inactive xml,
+     * including secure.  We should get the same result whether xmlin
+     * is NULL or whether it was the live xml of the domain moments
+     * before.  */
+    if (xmlin) {
+        virDomainDefPtr def = NULL;
+
+        if (!(def = virDomainDefParseString(driver->caps, xmlin,
+                                            QEMU_EXPECTED_VIRT_TYPES,
+                                            VIR_DOMAIN_XML_INACTIVE))) {
+            goto endjob;
+        }
+        if (!virDomainDefCheckABIStability(vm->def, def)) {
+            virDomainDefFree(def);
+            goto endjob;
+        }
+        xml = virDomainDefFormat(def, (VIR_DOMAIN_XML_INACTIVE |
+                                       VIR_DOMAIN_XML_SECURE));
+    } else {
+        xml = virDomainDefFormat(vm->def, (VIR_DOMAIN_XML_INACTIVE |
+                                           VIR_DOMAIN_XML_SECURE));
+    }
     if (!xml) {
         qemuReportError(VIR_ERR_OPERATION_FAILED,
                         "%s", _("failed to get domain xml"));
         goto endjob;
     }
-    header.xml_len = strlen(xml) + 1;
+    len = strlen(xml) + 1;
+    offset = sizeof(header) + len;
+
+    /* Due to way we append QEMU state on our header with dd,
+     * we need to ensure there's a 512 byte boundary. Unfortunately
+     * we don't have an explicit offset in the header, so we fake
+     * it by padding the XML string with NUL bytes.  Additionally,
+     * we want to ensure that virDomainSaveImageDefineXML can supply
+     * slightly larger XML, so we add a miminum padding prior to
+     * rounding out to page boundaries.
+     */
+    pad = 1024;
+    pad += (QEMU_MONITOR_MIGRATE_TO_FILE_BS -
+            ((offset + pad) % QEMU_MONITOR_MIGRATE_TO_FILE_BS));
+    if (VIR_EXPAND_N(xml, len, pad) < 0) {
+        virReportOOMError();
+        goto endjob;
+    }
+    offset += pad;
+    header.xml_len = len;
 
+    /* Obtain the file handle.  */
     /* path might be a pre-existing block dev, in which case
      * we need to skip the create step, and also avoid unlink
      * in the failure case */
@@ -2269,29 +2311,6 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
         }
     }
 
-    offset = sizeof(header) + header.xml_len;
-
-    /* Due to way we append QEMU state on our header with dd,
-     * we need to ensure there's a 512 byte boundary. Unfortunately
-     * we don't have an explicit offset in the header, so we fake
-     * it by padding the XML string with NULLs.
-     */
-    if (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS) {
-        unsigned long long pad =
-            QEMU_MONITOR_MIGRATE_TO_FILE_BS -
-            (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS);
-
-        if (VIR_REALLOC_N(xml, header.xml_len + pad) < 0) {
-            virReportOOMError();
-            goto endjob;
-        }
-        memset(xml + header.xml_len, 0, pad);
-        offset += pad;
-        header.xml_len += pad;
-    }
-
-    /* Obtain the file handle.  */
-
     /* First try creating the file as root */
     if (bypass_cache) {
         directFlag = virFileDirectFdFlag();
@@ -2462,11 +2481,6 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
     virDomainObjPtr vm = NULL;
 
     virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE, -1);
-    if (dxml) {
-        qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                        _("xml modification unsupported"));
-        return -1;
-    }
 
     qemuDriverLock(driver);
 
@@ -2504,7 +2518,8 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
     }
 
     ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
-                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0);
+                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
+                                 dxml);
     vm = NULL;
 
 cleanup:
@@ -2568,7 +2583,8 @@ qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
 
     compressed = QEMUD_SAVE_FORMAT_RAW;
     ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
-                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0);
+                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
+                                 NULL);
     vm = NULL;
 
 cleanup:
@@ -3711,7 +3727,8 @@ qemuDomainSaveImageOpen(struct qemud_driver *driver,
                         const char *path,
                         virDomainDefPtr *ret_def,
                         struct qemud_save_header *ret_header,
-                        bool bypass_cache, virFileDirectFdPtr *directFd)
+                        bool bypass_cache, virFileDirectFdPtr *directFd,
+                        const char *xmlin)
 {
     int fd;
     struct qemud_save_header header;
@@ -3795,6 +3812,20 @@ qemuDomainSaveImageOpen(struct qemud_driver *driver,
                                         QEMU_EXPECTED_VIRT_TYPES,
                                         VIR_DOMAIN_XML_INACTIVE)))
         goto error;
+    if (xmlin) {
+        virDomainDefPtr def2 = NULL;
+
+        if (!(def2 = virDomainDefParseString(driver->caps, xmlin,
+                                             QEMU_EXPECTED_VIRT_TYPES,
+                                             VIR_DOMAIN_XML_INACTIVE)))
+            goto error;
+        if (!virDomainDefCheckABIStability(def, def2)) {
+            virDomainDefFree(def2);
+            goto error;
+        }
+        virDomainDefFree(def);
+        def = def2;
+    }
 
     VIR_FREE(xml);
 
@@ -3929,17 +3960,12 @@ qemuDomainRestoreFlags(virConnectPtr conn,
     virFileDirectFdPtr directFd = NULL;
 
     virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE, -1);
-    if (dxml) {
-        qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                        _("xml modification unsupported"));
-        return -1;
-    }
 
     qemuDriverLock(driver);
 
     fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
                                  (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
-                                 &directFd);
+                                 &directFd, dxml);
     if (fd < 0)
         goto cleanup;
 
@@ -3999,7 +4025,7 @@ qemuDomainObjRestore(virConnectPtr conn,
     virFileDirectFdPtr directFd = NULL;
 
     fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
-                                 bypass_cache, &directFd);
+                                 bypass_cache, &directFd, NULL);
     if (fd < 0)
         goto cleanup;