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

Jiri Denemark posted 15 patches 7 years, 11 months ago
There is a newer version of this series
[libvirt] [PATCH 10/15] qemu: Store save cookie in save images and snapshots
Posted by Jiri Denemark 7 years, 11 months ago
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@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

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 10/15] qemu: Store save cookie in save images and snapshots
Posted by Pavel Hrdina 7 years, 11 months ago
On Mon, Jun 05, 2017 at 11:26:58AM +0200, Jiri Denemark wrote:
> 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@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;

I would suggest cookieOffset.

> +    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,

I would suggest cookieObj.

>                     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))))

Here it's kind of confusing,

> +        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)

I think that we should drop the expanding and just write 0 to the
remaining data part of save image ... [1]

>              goto cleanup;
>      } else {
>          header->data_len = len;
>      }
>  
> +    if (data->cookie)
> +        header->cookie = xml_len;

and this is also kind of confusing.

> +
>      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;

[1] ... there you write the expanded XML to the save image which will
stop at the end of the our internal data part ... [2]

>      }
>  
> +    if (data->cookie &&
> +        safewrite(fd, data->cookie, cookie_len) != cookie_len) {
> +        virReportSystemError(errno,
> +                             _("failed to write cookie to '%s'"),
> +                             path);
> +        goto cleanup;
> +    }
> +

[2] ... and here you continue writing the cookie data out of the
internal data part.

Pavel
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list