3e5111
From b7638da5f8a4ad19fc45f530063044d0b5020422 Mon Sep 17 00:00:00 2001
3e5111
Message-Id: <b7638da5f8a4ad19fc45f530063044d0b5020422@dist-git>
3e5111
From: Jiri Denemark <jdenemar@redhat.com>
3e5111
Date: Thu, 25 May 2017 10:20:57 +0200
3e5111
Subject: [PATCH] qemu: Store save cookie in save images and snapshots
3e5111
3e5111
The following patches will add an actual content in the cookie and use
3e5111
the data when restoring a domain.
3e5111
3e5111
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
3e5111
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
3e5111
(cherry picked from commit 5c2f01abcb43810e7617f9a6544ce0d0b6caed34)
3e5111
3e5111
https://bugzilla.redhat.com/show_bug.cgi?id=1441662
3e5111
3e5111
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
3e5111
---
3e5111
 docs/formatsnapshot.html.in     |  6 +++
3e5111
 docs/schemas/domainsnapshot.rng |  7 +++
3e5111
 src/qemu/qemu_driver.c          | 96 ++++++++++++++++++++++++++++++++++++-----
3e5111
 3 files changed, 99 insertions(+), 10 deletions(-)
3e5111
3e5111
diff --git a/docs/formatsnapshot.html.in b/docs/formatsnapshot.html.in
3e5111
index c3ab516fa4..5e8e21c8a7 100644
3e5111
--- a/docs/formatsnapshot.html.in
3e5111
+++ b/docs/formatsnapshot.html.in
3e5111
@@ -235,6 +235,12 @@
3e5111
         at the time of the snapshot (since
3e5111
         0.9.5).  Readonly.
3e5111
       
3e5111
+      
cookie
3e5111
+      
Save image cookie containing additional data libvirt may need to
3e5111
+        properly restore a domain from an active snapshot when such data
3e5111
+        cannot be stored directly in the domain to maintain
3e5111
+        compatibility with older libvirt or hypervisor. Readonly.
3e5111
+      
3e5111
     
3e5111
 
3e5111
     

Examples

3e5111
diff --git a/docs/schemas/domainsnapshot.rng b/docs/schemas/domainsnapshot.rng
3e5111
index 4ab1b828f2..2680887095 100644
3e5111
--- a/docs/schemas/domainsnapshot.rng
3e5111
+++ b/docs/schemas/domainsnapshot.rng
3e5111
@@ -90,6 +90,13 @@
3e5111
             </element>
3e5111
           </element>
3e5111
         </optional>
3e5111
+        <optional>
3e5111
+          <element name='cookie'>
3e5111
+            <zeroOrMore>
3e5111
+              <ref name='customElement'/>
3e5111
+            </zeroOrMore>
3e5111
+          </element>
3e5111
+        </optional>
3e5111
       </interleave>
3e5111
     </element>
3e5111
   </define>
3e5111
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
3e5111
index 7ce0f01f70..dbb1ea9475 100644
3e5111
--- a/src/qemu/qemu_driver.c
3e5111
+++ b/src/qemu/qemu_driver.c
3e5111
@@ -2813,7 +2813,8 @@ struct _virQEMUSaveHeader {
3e5111
     uint32_t data_len;
3e5111
     uint32_t was_running;
3e5111
     uint32_t compressed;
3e5111
-    uint32_t unused[15];
3e5111
+    uint32_t cookieOffset;
3e5111
+    uint32_t unused[14];
3e5111
 };
3e5111
 
3e5111
 typedef struct _virQEMUSaveData virQEMUSaveData;
3e5111
@@ -2821,6 +2822,7 @@ typedef virQEMUSaveData *virQEMUSaveDataPtr;
3e5111
 struct _virQEMUSaveData {
3e5111
     virQEMUSaveHeader header;
3e5111
     char *xml;
3e5111
+    char *cookie;
3e5111
 };
3e5111
 
3e5111
 
3e5111
@@ -2831,6 +2833,7 @@ bswap_header(virQEMUSaveHeaderPtr hdr)
3e5111
     hdr->data_len = bswap_32(hdr->data_len);
3e5111
     hdr->was_running = bswap_32(hdr->was_running);
3e5111
     hdr->compressed = bswap_32(hdr->compressed);
3e5111
+    hdr->cookieOffset = bswap_32(hdr->cookieOffset);
3e5111
 }
3e5111
 
3e5111
 
3e5111
@@ -2841,6 +2844,7 @@ virQEMUSaveDataFree(virQEMUSaveDataPtr data)
3e5111
         return;
3e5111
 
3e5111
     VIR_FREE(data->xml);
3e5111
+    VIR_FREE(data->cookie);
3e5111
     VIR_FREE(data);
3e5111
 }
3e5111
 
3e5111
@@ -2850,8 +2854,10 @@ virQEMUSaveDataFree(virQEMUSaveDataPtr data)
3e5111
  */
3e5111
 static virQEMUSaveDataPtr
3e5111
 virQEMUSaveDataNew(char *domXML,
3e5111
+                   qemuDomainSaveCookiePtr cookieObj,
3e5111
                    bool running,
3e5111
-                   int compressed)
3e5111
+                   int compressed,
3e5111
+                   virDomainXMLOptionPtr xmlopt)
3e5111
 {
3e5111
     virQEMUSaveDataPtr data = NULL;
3e5111
     virQEMUSaveHeaderPtr header;
3e5111
@@ -2861,6 +2867,11 @@ virQEMUSaveDataNew(char *domXML,
3e5111
 
3e5111
     VIR_STEAL_PTR(data->xml, domXML);
3e5111
 
3e5111
+    if (cookieObj &&
3e5111
+        !(data->cookie = virSaveCookieFormat((virObjectPtr) cookieObj,
3e5111
+                                             virDomainXMLOptionGetSaveCookie(xmlopt))))
3e5111
+        goto error;
3e5111
+
3e5111
     header = &data->header;
3e5111
     memcpy(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic));
3e5111
     header->version = QEMU_SAVE_VERSION;
3e5111
@@ -2868,6 +2879,10 @@ virQEMUSaveDataNew(char *domXML,
3e5111
     header->compressed = compressed;
3e5111
 
3e5111
     return data;
3e5111
+
3e5111
+ error:
3e5111
+    virQEMUSaveDataFree(data);
3e5111
+    return NULL;
3e5111
 }
3e5111
 
3e5111
 
3e5111
@@ -2887,11 +2902,17 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data,
3e5111
 {
3e5111
     virQEMUSaveHeaderPtr header = &data->header;
3e5111
     size_t len;
3e5111
+    size_t xml_len;
3e5111
+    size_t cookie_len = 0;
3e5111
     int ret = -1;
3e5111
     size_t zerosLen = 0;
3e5111
     char *zeros = NULL;
3e5111
 
3e5111
-    len = strlen(data->xml) + 1;
3e5111
+    xml_len = strlen(data->xml) + 1;
3e5111
+    if (data->cookie)
3e5111
+        cookie_len = strlen(data->cookie) + 1;
3e5111
+
3e5111
+    len = xml_len + cookie_len;
3e5111
 
3e5111
     if (header->data_len > 0) {
3e5111
         if (len > header->data_len) {
3e5111
@@ -2907,6 +2928,9 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data,
3e5111
         header->data_len = len;
3e5111
     }
3e5111
 
3e5111
+    if (data->cookie)
3e5111
+        header->cookieOffset = xml_len;
3e5111
+
3e5111
     if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
3e5111
         virReportSystemError(errno,
3e5111
                              _("failed to write header to domain save file '%s'"),
3e5111
@@ -2914,14 +2938,28 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data,
3e5111
         goto cleanup;
3e5111
     }
3e5111
 
3e5111
-    if (safewrite(fd, data->xml, header->data_len) != header->data_len ||
3e5111
-        safewrite(fd, zeros, zerosLen) != zerosLen) {
3e5111
+    if (safewrite(fd, data->xml, xml_len) != xml_len) {
3e5111
         virReportSystemError(errno,
3e5111
                              _("failed to write domain xml to '%s'"),
3e5111
                              path);
3e5111
         goto cleanup;
3e5111
     }
3e5111
 
3e5111
+    if (data->cookie &&
3e5111
+        safewrite(fd, data->cookie, cookie_len) != cookie_len) {
3e5111
+        virReportSystemError(errno,
3e5111
+                             _("failed to write cookie to '%s'"),
3e5111
+                             path);
3e5111
+        goto cleanup;
3e5111
+    }
3e5111
+
3e5111
+    if (safewrite(fd, zeros, zerosLen) != zerosLen) {
3e5111
+        virReportSystemError(errno,
3e5111
+                             _("failed to write padding to '%s'"),
3e5111
+                             path);
3e5111
+        goto cleanup;
3e5111
+    }
3e5111
+
3e5111
     ret = 0;
3e5111
 
3e5111
  cleanup:
3e5111
@@ -3236,6 +3274,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
3e5111
     qemuDomainObjPrivatePtr priv = vm->privateData;
3e5111
     virCapsPtr caps;
3e5111
     virQEMUSaveDataPtr data = NULL;
3e5111
+    qemuDomainSaveCookiePtr cookie = NULL;
3e5111
 
3e5111
     if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
3e5111
         goto cleanup;
3e5111
@@ -3301,7 +3340,11 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
3e5111
         goto endjob;
3e5111
     }
3e5111
 
3e5111
-    if (!(data = virQEMUSaveDataNew(xml, was_running, compressed)))
3e5111
+    if (!(cookie = qemuDomainSaveCookieNew(vm)))
3e5111
+        goto endjob;
3e5111
+
3e5111
+    if (!(data = virQEMUSaveDataNew(xml, cookie, was_running, compressed,
3e5111
+                                    driver->xmlopt)))
3e5111
         goto endjob;
3e5111
     xml = NULL;
3e5111
 
3e5111
@@ -3338,6 +3381,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
3e5111
         qemuDomainRemoveInactive(driver, vm);
3e5111
 
3e5111
  cleanup:
3e5111
+    virObjectUnref(cookie);
3e5111
     VIR_FREE(xml);
3e5111
     virQEMUSaveDataFree(data);
3e5111
     qemuDomainEventQueue(driver, event);
3e5111
@@ -6282,6 +6326,8 @@ qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
3e5111
     virDomainDefPtr def = NULL;
3e5111
     int oflags = open_write ? O_RDWR : O_RDONLY;
3e5111
     virCapsPtr caps = NULL;
3e5111
+    size_t xml_len;
3e5111
+    size_t cookie_len;
3e5111
 
3e5111
     if (bypass_cache) {
3e5111
         int directFlag = virFileDirectFdFlag();
3e5111
@@ -6362,15 +6408,33 @@ qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
3e5111
         goto error;
3e5111
     }
3e5111
 
3e5111
-    if (VIR_ALLOC_N(data->xml, header->data_len) < 0)
3e5111
+    if (header->cookieOffset)
3e5111
+        xml_len = header->cookieOffset;
3e5111
+    else
3e5111
+        xml_len = header->data_len;
3e5111
+
3e5111
+    cookie_len = header->data_len - xml_len;
3e5111
+
3e5111
+    if (VIR_ALLOC_N(data->xml, xml_len) < 0)
3e5111
         goto error;
3e5111
 
3e5111
-    if (saferead(fd, data->xml, header->data_len) != header->data_len) {
3e5111
+    if (saferead(fd, data->xml, xml_len) != xml_len) {
3e5111
         virReportError(VIR_ERR_OPERATION_FAILED,
3e5111
                        "%s", _("failed to read domain XML"));
3e5111
         goto error;
3e5111
     }
3e5111
 
3e5111
+    if (cookie_len > 0) {
3e5111
+        if (VIR_ALLOC_N(data->cookie, cookie_len) < 0)
3e5111
+            goto error;
3e5111
+
3e5111
+        if (saferead(fd, data->cookie, cookie_len) != cookie_len) {
3e5111
+            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3e5111
+                           _("failed to read cookie"));
3e5111
+            goto error;
3e5111
+        }
3e5111
+    }
3e5111
+
3e5111
     /* Create a domain from this XML */
3e5111
     if (!(def = virDomainDefParseString(data->xml, caps, driver->xmlopt, NULL,
3e5111
                                         VIR_DOMAIN_DEF_PARSE_INACTIVE |
3e5111
@@ -6411,6 +6475,11 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
3e5111
     char *errbuf = NULL;
3e5111
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3e5111
     virQEMUSaveHeaderPtr header = &data->header;
3e5111
+    qemuDomainSaveCookiePtr cookie = NULL;
3e5111
+
3e5111
+    if (virSaveCookieParseString(data->cookie, (virObjectPtr *) &cookie,
3e5111
+                                 virDomainXMLOptionGetSaveCookie(driver->xmlopt)) < 0)
3e5111
+        goto cleanup;
3e5111
 
3e5111
     if ((header->version == 2) &&
3e5111
         (header->compressed != QEMU_SAVE_FORMAT_RAW)) {
3e5111
@@ -6501,6 +6570,7 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
3e5111
     ret = 0;
3e5111
 
3e5111
  cleanup:
3e5111
+    virObjectUnref(cookie);
3e5111
     virCommandFree(cmd);
3e5111
     VIR_FREE(errbuf);
3e5111
     if (qemuSecurityRestoreSavedStateLabel(driver->securityManager,
3e5111
@@ -13561,6 +13631,9 @@ qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
3e5111
     if (ret < 0)
3e5111
         goto cleanup;
3e5111
 
3e5111
+    if (!(snap->def->cookie = (virObjectPtr) qemuDomainSaveCookieNew(vm)))
3e5111
+        goto cleanup;
3e5111
+
3e5111
     if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
3e5111
         event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
3e5111
                                          VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
3e5111
@@ -14439,10 +14512,13 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
3e5111
                                                     "snapshot", false)) < 0)
3e5111
             goto cleanup;
3e5111
 
3e5111
-        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)))
3e5111
+        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)) ||
3e5111
+            !(snap->def->cookie = (virObjectPtr) qemuDomainSaveCookieNew(vm)))
3e5111
             goto cleanup;
3e5111
 
3e5111
-        if (!(data = virQEMUSaveDataNew(xml, resume, compressed)))
3e5111
+        if (!(data = virQEMUSaveDataNew(xml,
3e5111
+                                        (qemuDomainSaveCookiePtr) snap->def->cookie,
3e5111
+                                        resume, compressed, driver->xmlopt)))
3e5111
             goto cleanup;
3e5111
         xml = NULL;
3e5111
 
3e5111
-- 
3e5111
2.13.1
3e5111