|
|
6d3351 |
From b7638da5f8a4ad19fc45f530063044d0b5020422 Mon Sep 17 00:00:00 2001
|
|
|
6d3351 |
Message-Id: <b7638da5f8a4ad19fc45f530063044d0b5020422@dist-git>
|
|
|
6d3351 |
From: Jiri Denemark <jdenemar@redhat.com>
|
|
|
6d3351 |
Date: Thu, 25 May 2017 10:20:57 +0200
|
|
|
6d3351 |
Subject: [PATCH] qemu: Store save cookie in save images and snapshots
|
|
|
6d3351 |
|
|
|
6d3351 |
The following patches will add an actual content in the cookie and use
|
|
|
6d3351 |
the data when restoring a domain.
|
|
|
6d3351 |
|
|
|
6d3351 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
6d3351 |
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
|
|
|
6d3351 |
(cherry picked from commit 5c2f01abcb43810e7617f9a6544ce0d0b6caed34)
|
|
|
6d3351 |
|
|
|
6d3351 |
https://bugzilla.redhat.com/show_bug.cgi?id=1441662
|
|
|
6d3351 |
|
|
|
6d3351 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
6d3351 |
---
|
|
|
6d3351 |
docs/formatsnapshot.html.in | 6 +++
|
|
|
6d3351 |
docs/schemas/domainsnapshot.rng | 7 +++
|
|
|
6d3351 |
src/qemu/qemu_driver.c | 96 ++++++++++++++++++++++++++++++++++++-----
|
|
|
6d3351 |
3 files changed, 99 insertions(+), 10 deletions(-)
|
|
|
6d3351 |
|
|
|
6d3351 |
diff --git a/docs/formatsnapshot.html.in b/docs/formatsnapshot.html.in
|
|
|
6d3351 |
index c3ab516fa4..5e8e21c8a7 100644
|
|
|
6d3351 |
--- a/docs/formatsnapshot.html.in
|
|
|
6d3351 |
+++ b/docs/formatsnapshot.html.in
|
|
|
6d3351 |
@@ -235,6 +235,12 @@
|
|
|
6d3351 |
at the time of the snapshot (since
|
|
|
6d3351 |
0.9.5). Readonly.
|
|
|
6d3351 |
|
|
|
6d3351 |
+ cookie
|
|
|
6d3351 |
+ Save image cookie containing additional data libvirt may need to
|
|
|
6d3351 |
+ properly restore a domain from an active snapshot when such data
|
|
|
6d3351 |
+ cannot be stored directly in the domain to maintain
|
|
|
6d3351 |
+ compatibility with older libvirt or hypervisor. Readonly.
|
|
|
6d3351 |
+
|
|
|
6d3351 |
|
|
|
6d3351 |
|
|
|
6d3351 |
|
|
|
6d3351 |
diff --git a/docs/schemas/domainsnapshot.rng b/docs/schemas/domainsnapshot.rng
|
|
|
6d3351 |
index 4ab1b828f2..2680887095 100644
|
|
|
6d3351 |
--- a/docs/schemas/domainsnapshot.rng
|
|
|
6d3351 |
+++ b/docs/schemas/domainsnapshot.rng
|
|
|
6d3351 |
@@ -90,6 +90,13 @@
|
|
|
6d3351 |
</element>
|
|
|
6d3351 |
</element>
|
|
|
6d3351 |
</optional>
|
|
|
6d3351 |
+ <optional>
|
|
|
6d3351 |
+ <element name='cookie'>
|
|
|
6d3351 |
+ <zeroOrMore>
|
|
|
6d3351 |
+ <ref name='customElement'/>
|
|
|
6d3351 |
+ </zeroOrMore>
|
|
|
6d3351 |
+ </element>
|
|
|
6d3351 |
+ </optional>
|
|
|
6d3351 |
</interleave>
|
|
|
6d3351 |
</element>
|
|
|
6d3351 |
</define>
|
|
|
6d3351 |
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
|
|
6d3351 |
index 7ce0f01f70..dbb1ea9475 100644
|
|
|
6d3351 |
--- a/src/qemu/qemu_driver.c
|
|
|
6d3351 |
+++ b/src/qemu/qemu_driver.c
|
|
|
6d3351 |
@@ -2813,7 +2813,8 @@ struct _virQEMUSaveHeader {
|
|
|
6d3351 |
uint32_t data_len;
|
|
|
6d3351 |
uint32_t was_running;
|
|
|
6d3351 |
uint32_t compressed;
|
|
|
6d3351 |
- uint32_t unused[15];
|
|
|
6d3351 |
+ uint32_t cookieOffset;
|
|
|
6d3351 |
+ uint32_t unused[14];
|
|
|
6d3351 |
};
|
|
|
6d3351 |
|
|
|
6d3351 |
typedef struct _virQEMUSaveData virQEMUSaveData;
|
|
|
6d3351 |
@@ -2821,6 +2822,7 @@ typedef virQEMUSaveData *virQEMUSaveDataPtr;
|
|
|
6d3351 |
struct _virQEMUSaveData {
|
|
|
6d3351 |
virQEMUSaveHeader header;
|
|
|
6d3351 |
char *xml;
|
|
|
6d3351 |
+ char *cookie;
|
|
|
6d3351 |
};
|
|
|
6d3351 |
|
|
|
6d3351 |
|
|
|
6d3351 |
@@ -2831,6 +2833,7 @@ bswap_header(virQEMUSaveHeaderPtr hdr)
|
|
|
6d3351 |
hdr->data_len = bswap_32(hdr->data_len);
|
|
|
6d3351 |
hdr->was_running = bswap_32(hdr->was_running);
|
|
|
6d3351 |
hdr->compressed = bswap_32(hdr->compressed);
|
|
|
6d3351 |
+ hdr->cookieOffset = bswap_32(hdr->cookieOffset);
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
|
|
|
6d3351 |
@@ -2841,6 +2844,7 @@ virQEMUSaveDataFree(virQEMUSaveDataPtr data)
|
|
|
6d3351 |
return;
|
|
|
6d3351 |
|
|
|
6d3351 |
VIR_FREE(data->xml);
|
|
|
6d3351 |
+ VIR_FREE(data->cookie);
|
|
|
6d3351 |
VIR_FREE(data);
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
@@ -2850,8 +2854,10 @@ virQEMUSaveDataFree(virQEMUSaveDataPtr data)
|
|
|
6d3351 |
*/
|
|
|
6d3351 |
static virQEMUSaveDataPtr
|
|
|
6d3351 |
virQEMUSaveDataNew(char *domXML,
|
|
|
6d3351 |
+ qemuDomainSaveCookiePtr cookieObj,
|
|
|
6d3351 |
bool running,
|
|
|
6d3351 |
- int compressed)
|
|
|
6d3351 |
+ int compressed,
|
|
|
6d3351 |
+ virDomainXMLOptionPtr xmlopt)
|
|
|
6d3351 |
{
|
|
|
6d3351 |
virQEMUSaveDataPtr data = NULL;
|
|
|
6d3351 |
virQEMUSaveHeaderPtr header;
|
|
|
6d3351 |
@@ -2861,6 +2867,11 @@ virQEMUSaveDataNew(char *domXML,
|
|
|
6d3351 |
|
|
|
6d3351 |
VIR_STEAL_PTR(data->xml, domXML);
|
|
|
6d3351 |
|
|
|
6d3351 |
+ if (cookieObj &&
|
|
|
6d3351 |
+ !(data->cookie = virSaveCookieFormat((virObjectPtr) cookieObj,
|
|
|
6d3351 |
+ virDomainXMLOptionGetSaveCookie(xmlopt))))
|
|
|
6d3351 |
+ goto error;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
header = &data->header;
|
|
|
6d3351 |
memcpy(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic));
|
|
|
6d3351 |
header->version = QEMU_SAVE_VERSION;
|
|
|
6d3351 |
@@ -2868,6 +2879,10 @@ virQEMUSaveDataNew(char *domXML,
|
|
|
6d3351 |
header->compressed = compressed;
|
|
|
6d3351 |
|
|
|
6d3351 |
return data;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
+ error:
|
|
|
6d3351 |
+ virQEMUSaveDataFree(data);
|
|
|
6d3351 |
+ return NULL;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
|
|
|
6d3351 |
@@ -2887,11 +2902,17 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data,
|
|
|
6d3351 |
{
|
|
|
6d3351 |
virQEMUSaveHeaderPtr header = &data->header;
|
|
|
6d3351 |
size_t len;
|
|
|
6d3351 |
+ size_t xml_len;
|
|
|
6d3351 |
+ size_t cookie_len = 0;
|
|
|
6d3351 |
int ret = -1;
|
|
|
6d3351 |
size_t zerosLen = 0;
|
|
|
6d3351 |
char *zeros = NULL;
|
|
|
6d3351 |
|
|
|
6d3351 |
- len = strlen(data->xml) + 1;
|
|
|
6d3351 |
+ xml_len = strlen(data->xml) + 1;
|
|
|
6d3351 |
+ if (data->cookie)
|
|
|
6d3351 |
+ cookie_len = strlen(data->cookie) + 1;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
+ len = xml_len + cookie_len;
|
|
|
6d3351 |
|
|
|
6d3351 |
if (header->data_len > 0) {
|
|
|
6d3351 |
if (len > header->data_len) {
|
|
|
6d3351 |
@@ -2907,6 +2928,9 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data,
|
|
|
6d3351 |
header->data_len = len;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
+ if (data->cookie)
|
|
|
6d3351 |
+ header->cookieOffset = xml_len;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
|
|
|
6d3351 |
virReportSystemError(errno,
|
|
|
6d3351 |
_("failed to write header to domain save file '%s'"),
|
|
|
6d3351 |
@@ -2914,14 +2938,28 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data,
|
|
|
6d3351 |
goto cleanup;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
- if (safewrite(fd, data->xml, header->data_len) != header->data_len ||
|
|
|
6d3351 |
- safewrite(fd, zeros, zerosLen) != zerosLen) {
|
|
|
6d3351 |
+ if (safewrite(fd, data->xml, xml_len) != xml_len) {
|
|
|
6d3351 |
virReportSystemError(errno,
|
|
|
6d3351 |
_("failed to write domain xml to '%s'"),
|
|
|
6d3351 |
path);
|
|
|
6d3351 |
goto cleanup;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
+ if (data->cookie &&
|
|
|
6d3351 |
+ safewrite(fd, data->cookie, cookie_len) != cookie_len) {
|
|
|
6d3351 |
+ virReportSystemError(errno,
|
|
|
6d3351 |
+ _("failed to write cookie to '%s'"),
|
|
|
6d3351 |
+ path);
|
|
|
6d3351 |
+ goto cleanup;
|
|
|
6d3351 |
+ }
|
|
|
6d3351 |
+
|
|
|
6d3351 |
+ if (safewrite(fd, zeros, zerosLen) != zerosLen) {
|
|
|
6d3351 |
+ virReportSystemError(errno,
|
|
|
6d3351 |
+ _("failed to write padding to '%s'"),
|
|
|
6d3351 |
+ path);
|
|
|
6d3351 |
+ goto cleanup;
|
|
|
6d3351 |
+ }
|
|
|
6d3351 |
+
|
|
|
6d3351 |
ret = 0;
|
|
|
6d3351 |
|
|
|
6d3351 |
cleanup:
|
|
|
6d3351 |
@@ -3236,6 +3274,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
|
|
|
6d3351 |
qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
6d3351 |
virCapsPtr caps;
|
|
|
6d3351 |
virQEMUSaveDataPtr data = NULL;
|
|
|
6d3351 |
+ qemuDomainSaveCookiePtr cookie = NULL;
|
|
|
6d3351 |
|
|
|
6d3351 |
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
|
|
|
6d3351 |
goto cleanup;
|
|
|
6d3351 |
@@ -3301,7 +3340,11 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
|
|
|
6d3351 |
goto endjob;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
- if (!(data = virQEMUSaveDataNew(xml, was_running, compressed)))
|
|
|
6d3351 |
+ if (!(cookie = qemuDomainSaveCookieNew(vm)))
|
|
|
6d3351 |
+ goto endjob;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
+ if (!(data = virQEMUSaveDataNew(xml, cookie, was_running, compressed,
|
|
|
6d3351 |
+ driver->xmlopt)))
|
|
|
6d3351 |
goto endjob;
|
|
|
6d3351 |
xml = NULL;
|
|
|
6d3351 |
|
|
|
6d3351 |
@@ -3338,6 +3381,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
|
|
|
6d3351 |
qemuDomainRemoveInactive(driver, vm);
|
|
|
6d3351 |
|
|
|
6d3351 |
cleanup:
|
|
|
6d3351 |
+ virObjectUnref(cookie);
|
|
|
6d3351 |
VIR_FREE(xml);
|
|
|
6d3351 |
virQEMUSaveDataFree(data);
|
|
|
6d3351 |
qemuDomainEventQueue(driver, event);
|
|
|
6d3351 |
@@ -6282,6 +6326,8 @@ qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
|
|
|
6d3351 |
virDomainDefPtr def = NULL;
|
|
|
6d3351 |
int oflags = open_write ? O_RDWR : O_RDONLY;
|
|
|
6d3351 |
virCapsPtr caps = NULL;
|
|
|
6d3351 |
+ size_t xml_len;
|
|
|
6d3351 |
+ size_t cookie_len;
|
|
|
6d3351 |
|
|
|
6d3351 |
if (bypass_cache) {
|
|
|
6d3351 |
int directFlag = virFileDirectFdFlag();
|
|
|
6d3351 |
@@ -6362,15 +6408,33 @@ qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
|
|
|
6d3351 |
goto error;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
- if (VIR_ALLOC_N(data->xml, header->data_len) < 0)
|
|
|
6d3351 |
+ if (header->cookieOffset)
|
|
|
6d3351 |
+ xml_len = header->cookieOffset;
|
|
|
6d3351 |
+ else
|
|
|
6d3351 |
+ xml_len = header->data_len;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
+ cookie_len = header->data_len - xml_len;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
+ if (VIR_ALLOC_N(data->xml, xml_len) < 0)
|
|
|
6d3351 |
goto error;
|
|
|
6d3351 |
|
|
|
6d3351 |
- if (saferead(fd, data->xml, header->data_len) != header->data_len) {
|
|
|
6d3351 |
+ if (saferead(fd, data->xml, xml_len) != xml_len) {
|
|
|
6d3351 |
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
6d3351 |
"%s", _("failed to read domain XML"));
|
|
|
6d3351 |
goto error;
|
|
|
6d3351 |
}
|
|
|
6d3351 |
|
|
|
6d3351 |
+ if (cookie_len > 0) {
|
|
|
6d3351 |
+ if (VIR_ALLOC_N(data->cookie, cookie_len) < 0)
|
|
|
6d3351 |
+ goto error;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
+ if (saferead(fd, data->cookie, cookie_len) != cookie_len) {
|
|
|
6d3351 |
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
|
6d3351 |
+ _("failed to read cookie"));
|
|
|
6d3351 |
+ goto error;
|
|
|
6d3351 |
+ }
|
|
|
6d3351 |
+ }
|
|
|
6d3351 |
+
|
|
|
6d3351 |
/* Create a domain from this XML */
|
|
|
6d3351 |
if (!(def = virDomainDefParseString(data->xml, caps, driver->xmlopt, NULL,
|
|
|
6d3351 |
VIR_DOMAIN_DEF_PARSE_INACTIVE |
|
|
|
6d3351 |
@@ -6411,6 +6475,11 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
|
|
|
6d3351 |
char *errbuf = NULL;
|
|
|
6d3351 |
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
|
|
|
6d3351 |
virQEMUSaveHeaderPtr header = &data->header;
|
|
|
6d3351 |
+ qemuDomainSaveCookiePtr cookie = NULL;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
+ if (virSaveCookieParseString(data->cookie, (virObjectPtr *) &cookie,
|
|
|
6d3351 |
+ virDomainXMLOptionGetSaveCookie(driver->xmlopt)) < 0)
|
|
|
6d3351 |
+ goto cleanup;
|
|
|
6d3351 |
|
|
|
6d3351 |
if ((header->version == 2) &&
|
|
|
6d3351 |
(header->compressed != QEMU_SAVE_FORMAT_RAW)) {
|
|
|
6d3351 |
@@ -6501,6 +6570,7 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
|
|
|
6d3351 |
ret = 0;
|
|
|
6d3351 |
|
|
|
6d3351 |
cleanup:
|
|
|
6d3351 |
+ virObjectUnref(cookie);
|
|
|
6d3351 |
virCommandFree(cmd);
|
|
|
6d3351 |
VIR_FREE(errbuf);
|
|
|
6d3351 |
if (qemuSecurityRestoreSavedStateLabel(driver->securityManager,
|
|
|
6d3351 |
@@ -13561,6 +13631,9 @@ qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
|
|
|
6d3351 |
if (ret < 0)
|
|
|
6d3351 |
goto cleanup;
|
|
|
6d3351 |
|
|
|
6d3351 |
+ if (!(snap->def->cookie = (virObjectPtr) qemuDomainSaveCookieNew(vm)))
|
|
|
6d3351 |
+ goto cleanup;
|
|
|
6d3351 |
+
|
|
|
6d3351 |
if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
|
|
|
6d3351 |
event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
|
|
|
6d3351 |
VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
|
|
|
6d3351 |
@@ -14439,10 +14512,13 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
|
|
|
6d3351 |
"snapshot", false)) < 0)
|
|
|
6d3351 |
goto cleanup;
|
|
|
6d3351 |
|
|
|
6d3351 |
- if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)))
|
|
|
6d3351 |
+ if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)) ||
|
|
|
6d3351 |
+ !(snap->def->cookie = (virObjectPtr) qemuDomainSaveCookieNew(vm)))
|
|
|
6d3351 |
goto cleanup;
|
|
|
6d3351 |
|
|
|
6d3351 |
- if (!(data = virQEMUSaveDataNew(xml, resume, compressed)))
|
|
|
6d3351 |
+ if (!(data = virQEMUSaveDataNew(xml,
|
|
|
6d3351 |
+ (qemuDomainSaveCookiePtr) snap->def->cookie,
|
|
|
6d3351 |
+ resume, compressed, driver->xmlopt)))
|
|
|
6d3351 |
goto cleanup;
|
|
|
6d3351 |
xml = NULL;
|
|
|
6d3351 |
|
|
|
6d3351 |
--
|
|
|
6d3351 |
2.13.1
|
|
|
6d3351 |
|