[libvirt] [PATCH 10/15] qemu: Store save cookie in save images and snapshots

Jiri Denemark jdenemar at redhat.com
Mon Jun 5 09:26:58 UTC 2017


The following patches will add an actual content in the cookie and use
the data when restoring a domain.

Signed-off-by: Jiri Denemark <jdenemar at redhat.com>
---
 docs/formatsnapshot.html.in     |  6 +++
 docs/schemas/domainsnapshot.rng |  7 ++++
 src/qemu/qemu_driver.c          | 90 ++++++++++++++++++++++++++++++++++++-----
 3 files changed, 93 insertions(+), 10 deletions(-)

diff --git a/docs/formatsnapshot.html.in b/docs/formatsnapshot.html.in
index c3ab516fa..5e8e21c8a 100644
--- a/docs/formatsnapshot.html.in
+++ b/docs/formatsnapshot.html.in
@@ -235,6 +235,12 @@
         at the time of the snapshot (<span class="since">since
         0.9.5</span>).  Readonly.
       </dd>
+      <dt><code>cookie</code></dt>
+      <dd>Save image cookie containing additional data libvirt may need to
+        properly restore a domain from an active snapshot when such data
+        cannot be stored directly in the <code>domain</code> to maintain
+        compatibility with older libvirt or hypervisor. Readonly.
+      </dd>
     </dl>
 
     <h2><a name="example">Examples</a></h2>
diff --git a/docs/schemas/domainsnapshot.rng b/docs/schemas/domainsnapshot.rng
index 4ab1b828f..268088709 100644
--- a/docs/schemas/domainsnapshot.rng
+++ b/docs/schemas/domainsnapshot.rng
@@ -90,6 +90,13 @@
             </element>
           </element>
         </optional>
+        <optional>
+          <element name='cookie'>
+            <zeroOrMore>
+              <ref name='customElement'/>
+            </zeroOrMore>
+          </element>
+        </optional>
       </interleave>
     </element>
   </define>
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 96077df78..10df56e61 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2808,7 +2808,8 @@ struct _virQEMUSaveHeader {
     uint32_t data_len;
     uint32_t was_running;
     uint32_t compressed;
-    uint32_t unused[15];
+    uint32_t cookie;
+    uint32_t unused[14];
 };
 
 typedef struct _virQEMUSaveData virQEMUSaveData;
@@ -2816,6 +2817,7 @@ typedef virQEMUSaveData *virQEMUSaveDataPtr;
 struct _virQEMUSaveData {
     virQEMUSaveHeader header;
     char *xml;
+    char *cookie;
 };
 
 
@@ -2826,6 +2828,7 @@ bswap_header(virQEMUSaveHeaderPtr hdr)
     hdr->data_len = bswap_32(hdr->data_len);
     hdr->was_running = bswap_32(hdr->was_running);
     hdr->compressed = bswap_32(hdr->compressed);
+    hdr->cookie = bswap_32(hdr->cookie);
 }
 
 
@@ -2836,6 +2839,7 @@ virQEMUSaveDataFree(virQEMUSaveDataPtr data)
         return;
 
     VIR_FREE(data->xml);
+    VIR_FREE(data->cookie);
     VIR_FREE(data);
 }
 
@@ -2845,8 +2849,10 @@ virQEMUSaveDataFree(virQEMUSaveDataPtr data)
  */
 static virQEMUSaveDataPtr
 virQEMUSaveDataNew(char *domXML,
+                   qemuDomainSaveCookiePtr cookie,
                    bool running,
-                   int compressed)
+                   int compressed,
+                   virDomainXMLOptionPtr xmlopt)
 {
     virQEMUSaveDataPtr data = NULL;
     virQEMUSaveHeaderPtr header;
@@ -2856,6 +2862,11 @@ virQEMUSaveDataNew(char *domXML,
 
     VIR_STEAL_PTR(data->xml, domXML);
 
+    if (cookie &&
+        !(data->cookie = virSaveCookieFormat((virObjectPtr) cookie,
+                                             virDomainXMLOptionGetSaveCookie(xmlopt))))
+        goto error;
+
     header = &data->header;
     memcpy(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic));
     header->version = QEMU_SAVE_VERSION;
@@ -2863,6 +2874,10 @@ virQEMUSaveDataNew(char *domXML,
     header->compressed = compressed;
 
     return data;
+
+ error:
+    virQEMUSaveDataFree(data);
+    return NULL;
 }
 
 
@@ -2882,9 +2897,15 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data,
 {
     virQEMUSaveHeaderPtr header = &data->header;
     size_t len;
+    size_t xml_len;
+    size_t cookie_len = 0;
     int ret = -1;
 
-    len = strlen(data->xml) + 1;
+    xml_len = strlen(data->xml) + 1;
+    if (data->cookie)
+        cookie_len = strlen(data->cookie) + 1;
+
+    len = xml_len + cookie_len;
 
     if (header->data_len > 0) {
         if (len > header->data_len) {
@@ -2893,12 +2914,15 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data,
             goto cleanup;
         }
 
-        if (VIR_EXPAND_N(data->xml, len, header->data_len - len) < 0)
+        if (VIR_EXPAND_N(data->xml, xml_len, header->data_len - len) < 0)
             goto cleanup;
     } else {
         header->data_len = len;
     }
 
+    if (data->cookie)
+        header->cookie = xml_len;
+
     if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
         virReportSystemError(errno,
                              _("failed to write header to domain save file '%s'"),
@@ -2906,13 +2930,21 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data,
         goto cleanup;
     }
 
-    if (safewrite(fd, data->xml, header->data_len) != header->data_len) {
+    if (safewrite(fd, data->xml, xml_len) != xml_len) {
         virReportSystemError(errno,
                              _("failed to write domain xml to '%s'"),
                              path);
         goto cleanup;
     }
 
+    if (data->cookie &&
+        safewrite(fd, data->cookie, cookie_len) != cookie_len) {
+        virReportSystemError(errno,
+                             _("failed to write cookie to '%s'"),
+                             path);
+        goto cleanup;
+    }
+
     ret = 0;
 
  cleanup:
@@ -3245,6 +3277,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
     qemuDomainObjPrivatePtr priv = vm->privateData;
     virCapsPtr caps;
     virQEMUSaveDataPtr data = NULL;
+    qemuDomainSaveCookiePtr cookie = NULL;
 
     if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
         goto cleanup;
@@ -3310,7 +3343,11 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
         goto endjob;
     }
 
-    if (!(data = virQEMUSaveDataNew(xml, was_running, compressed)))
+    if (!(cookie = qemuDomainSaveCookieNew(vm)))
+        goto endjob;
+
+    if (!(data = virQEMUSaveDataNew(xml, cookie, was_running, compressed,
+                                    driver->xmlopt)))
         goto endjob;
     xml = NULL;
 
@@ -3347,6 +3384,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
         qemuDomainRemoveInactive(driver, vm);
 
  cleanup:
+    virObjectUnref(cookie);
     VIR_FREE(xml);
     virQEMUSaveDataFree(data);
     qemuDomainEventQueue(driver, event);
@@ -6283,6 +6321,8 @@ qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
     virDomainDefPtr def = NULL;
     int oflags = open_write ? O_RDWR : O_RDONLY;
     virCapsPtr caps = NULL;
+    size_t xml_len;
+    size_t cookie_len;
 
     if (bypass_cache) {
         int directFlag = virFileDirectFdFlag();
@@ -6363,15 +6403,33 @@ qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
         goto error;
     }
 
-    if (VIR_ALLOC_N(data->xml, header->data_len) < 0)
+    if (header->cookie)
+        xml_len = header->cookie;
+    else
+        xml_len = header->data_len;
+
+    cookie_len = header->data_len - xml_len;
+
+    if (VIR_ALLOC_N(data->xml, xml_len) < 0)
         goto error;
 
-    if (saferead(fd, data->xml, header->data_len) != header->data_len) {
+    if (saferead(fd, data->xml, xml_len) != xml_len) {
         virReportError(VIR_ERR_OPERATION_FAILED,
                        "%s", _("failed to read domain XML"));
         goto error;
     }
 
+    if (cookie_len > 0) {
+        if (VIR_ALLOC_N(data->cookie, cookie_len) < 0)
+            goto error;
+
+        if (saferead(fd, data->cookie, cookie_len) != cookie_len) {
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                           _("failed to read cookie"));
+            goto error;
+        }
+    }
+
     /* Create a domain from this XML */
     if (!(def = virDomainDefParseString(data->xml, caps, driver->xmlopt, NULL,
                                         VIR_DOMAIN_DEF_PARSE_INACTIVE |
@@ -6412,6 +6470,11 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
     char *errbuf = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
     virQEMUSaveHeaderPtr header = &data->header;
+    qemuDomainSaveCookiePtr cookie = NULL;
+
+    if (virSaveCookieParseString(data->cookie, (virObjectPtr *) &cookie,
+                                 virDomainXMLOptionGetSaveCookie(driver->xmlopt)) < 0)
+        goto cleanup;
 
     if ((header->version == 2) &&
         (header->compressed != QEMU_SAVE_FORMAT_RAW)) {
@@ -6502,6 +6565,7 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
     ret = 0;
 
  cleanup:
+    virObjectUnref(cookie);
     virCommandFree(cmd);
     VIR_FREE(errbuf);
     if (qemuSecurityRestoreSavedStateLabel(driver->securityManager,
@@ -13554,6 +13618,9 @@ qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
     if (ret < 0)
         goto cleanup;
 
+    if (!(snap->def->cookie = (virObjectPtr) qemuDomainSaveCookieNew(vm)))
+        goto cleanup;
+
     if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
         event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                          VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
@@ -14433,10 +14500,13 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
                                                     "snapshot", false)) < 0)
             goto cleanup;
 
-        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)))
+        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)) ||
+            !(snap->def->cookie = (virObjectPtr) qemuDomainSaveCookieNew(vm)))
             goto cleanup;
 
-        if (!(data = virQEMUSaveDataNew(xml, resume, compressed)))
+        if (!(data = virQEMUSaveDataNew(xml,
+                                        (qemuDomainSaveCookiePtr) snap->def->cookie,
+                                        resume, compressed, driver->xmlopt)))
             goto cleanup;
         xml = NULL;
 
-- 
2.13.0




More information about the libvir-list mailing list