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

Examples

diff --git a/docs/schemas/domainsnapshot.rng b/docs/schemas/domainsnapshot.rng index 4ab1b828f2..2680887095 100644 --- a/docs/schemas/domainsnapshot.rng +++ b/docs/schemas/domainsnapshot.rng @@ -90,6 +90,13 @@ + + + + + + + diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 7ce0f01f70..dbb1ea9475 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2813,7 +2813,8 @@ struct _virQEMUSaveHeader { uint32_t data_len; uint32_t was_running; uint32_t compressed; - uint32_t unused[15]; + uint32_t cookieOffset; + uint32_t unused[14]; }; typedef struct _virQEMUSaveData virQEMUSaveData; @@ -2821,6 +2822,7 @@ typedef virQEMUSaveData *virQEMUSaveDataPtr; struct _virQEMUSaveData { virQEMUSaveHeader header; char *xml; + char *cookie; }; @@ -2831,6 +2833,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->cookieOffset = bswap_32(hdr->cookieOffset); } @@ -2841,6 +2844,7 @@ virQEMUSaveDataFree(virQEMUSaveDataPtr data) return; VIR_FREE(data->xml); + VIR_FREE(data->cookie); VIR_FREE(data); } @@ -2850,8 +2854,10 @@ virQEMUSaveDataFree(virQEMUSaveDataPtr data) */ static virQEMUSaveDataPtr virQEMUSaveDataNew(char *domXML, + qemuDomainSaveCookiePtr cookieObj, bool running, - int compressed) + int compressed, + virDomainXMLOptionPtr xmlopt) { virQEMUSaveDataPtr data = NULL; virQEMUSaveHeaderPtr header; @@ -2861,6 +2867,11 @@ virQEMUSaveDataNew(char *domXML, VIR_STEAL_PTR(data->xml, domXML); + if (cookieObj && + !(data->cookie = virSaveCookieFormat((virObjectPtr) cookieObj, + virDomainXMLOptionGetSaveCookie(xmlopt)))) + goto error; + header = &data->header; memcpy(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic)); header->version = QEMU_SAVE_VERSION; @@ -2868,6 +2879,10 @@ virQEMUSaveDataNew(char *domXML, header->compressed = compressed; return data; + + error: + virQEMUSaveDataFree(data); + return NULL; } @@ -2887,11 +2902,17 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data, { virQEMUSaveHeaderPtr header = &data->header; size_t len; + size_t xml_len; + size_t cookie_len = 0; int ret = -1; size_t zerosLen = 0; char *zeros = NULL; - 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) { @@ -2907,6 +2928,9 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data, header->data_len = len; } + if (data->cookie) + header->cookieOffset = xml_len; + if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) { virReportSystemError(errno, _("failed to write header to domain save file '%s'"), @@ -2914,14 +2938,28 @@ virQEMUSaveDataWrite(virQEMUSaveDataPtr data, goto cleanup; } - if (safewrite(fd, data->xml, header->data_len) != header->data_len || - safewrite(fd, zeros, zerosLen) != zerosLen) { + 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; + } + + if (safewrite(fd, zeros, zerosLen) != zerosLen) { + virReportSystemError(errno, + _("failed to write padding to '%s'"), + path); + goto cleanup; + } + ret = 0; cleanup: @@ -3236,6 +3274,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; @@ -3301,7 +3340,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; @@ -3338,6 +3381,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom, qemuDomainRemoveInactive(driver, vm); cleanup: + virObjectUnref(cookie); VIR_FREE(xml); virQEMUSaveDataFree(data); qemuDomainEventQueue(driver, event); @@ -6282,6 +6326,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(); @@ -6362,15 +6408,33 @@ qemuDomainSaveImageOpen(virQEMUDriverPtr driver, goto error; } - if (VIR_ALLOC_N(data->xml, header->data_len) < 0) + if (header->cookieOffset) + xml_len = header->cookieOffset; + 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 | @@ -6411,6 +6475,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)) { @@ -6501,6 +6570,7 @@ qemuDomainSaveImageStartVM(virConnectPtr conn, ret = 0; cleanup: + virObjectUnref(cookie); virCommandFree(cmd); VIR_FREE(errbuf); if (qemuSecurityRestoreSavedStateLabel(driver->securityManager, @@ -13561,6 +13631,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); @@ -14439,10 +14512,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.1