Signed-off-by: Jiri Denemark <jdenemar(a)redhat.com>
---
src/qemu/qemu_driver.c | 324 ++++++++++++++++++++++++++++++-------------------
1 file changed, 198 insertions(+), 126 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index b0d67adc1..96077df78 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2811,6 +2811,14 @@ struct _virQEMUSaveHeader {
uint32_t unused[15];
};
+typedef struct _virQEMUSaveData virQEMUSaveData;
+typedef virQEMUSaveData *virQEMUSaveDataPtr;
+struct _virQEMUSaveData {
+ virQEMUSaveHeader header;
+ char *xml;
+};
+
+
static inline void
bswap_header(virQEMUSaveHeaderPtr hdr)
{
@@ -2821,32 +2829,118 @@ bswap_header(virQEMUSaveHeaderPtr hdr)
}
-/* return -errno on failure, or 0 on success */
-static int
-qemuDomainSaveHeader(int fd, const char *path, const char *xml,
- virQEMUSaveHeaderPtr header)
+static void
+virQEMUSaveDataFree(virQEMUSaveDataPtr data)
{
- int ret = 0;
+ if (!data)
+ return;
+
+ VIR_FREE(data->xml);
+ VIR_FREE(data);
+}
+
+
+/**
+ * This function steals @domXML on success.
+ */
+static virQEMUSaveDataPtr
+virQEMUSaveDataNew(char *domXML,
+ bool running,
+ int compressed)
+{
+ virQEMUSaveDataPtr data = NULL;
+ virQEMUSaveHeaderPtr header;
+
+ if (VIR_ALLOC(data) < 0)
+ return NULL;
+
+ VIR_STEAL_PTR(data->xml, domXML);
+
+ header = &data->header;
+ memcpy(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic));
+ header->version = QEMU_SAVE_VERSION;
+ header->was_running = running ? 1 : 0;
+ header->compressed = compressed;
+
+ return data;
+}
+
+
+/* virQEMUSaveDataWrite:
+ *
+ * Writes libvirt's header (including domain XML) into a saved image of a
+ * running domain. If @header has data_len filled in (because it was previously
+ * read from the file), the function will make sure the new data will fit
+ * within data_len.
+ *
+ * Returns -1 on failure, or 0 on success.
+ */
+static int
+virQEMUSaveDataWrite(virQEMUSaveDataPtr data,
+ int fd,
+ const char *path)
+{
+ virQEMUSaveHeaderPtr header = &data->header;
+ size_t len;
+ int ret = -1;
+
+ len = strlen(data->xml) + 1;
+
+ if (header->data_len > 0) {
+ if (len > header->data_len) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("new xml too large to fit in file"));
+ goto cleanup;
+ }
+
+ if (VIR_EXPAND_N(data->xml, len, header->data_len - len) < 0)
+ goto cleanup;
+ } else {
+ header->data_len = len;
+ }
if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
- ret = -errno;
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("failed to write header to domain save file
'%s'"),
- path);
- goto endjob;
+ virReportSystemError(errno,
+ _("failed to write header to domain save file
'%s'"),
+ path);
+ goto cleanup;
}
- if (safewrite(fd, xml, header->data_len) != header->data_len) {
- ret = -errno;
- virReportError(VIR_ERR_OPERATION_FAILED,
- _("failed to write xml to '%s'"), path);
- goto endjob;
+ if (safewrite(fd, data->xml, header->data_len) != header->data_len) {
+ virReportSystemError(errno,
+ _("failed to write domain xml to '%s'"),
+ path);
+ goto cleanup;
}
- endjob:
+
+ ret = 0;
+
+ cleanup:
return ret;
}
+static int
+virQEMUSaveDataFinish(virQEMUSaveDataPtr data,
+ int *fd,
+ const char *path)
+{
+ virQEMUSaveHeaderPtr header = &data->header;
+
+ memcpy(header->magic, QEMU_SAVE_MAGIC, sizeof(header->magic));
+
+ if (safewrite(*fd, header, sizeof(*header)) != sizeof(*header) ||
+ VIR_CLOSE(*fd) < 0) {
+ virReportSystemError(errno,
+ _("failed to write header to domain save file
'%s'"),
+ path);
+ return -1;
+ }
+
+ return 0;
+}
+
+
static virCommandPtr
qemuCompressGetCommand(virQEMUSaveFormat compression)
{
@@ -3061,14 +3155,11 @@ static int
qemuDomainSaveMemory(virQEMUDriverPtr driver,
virDomainObjPtr vm,
const char *path,
- const char *domXML,
- int compressed,
+ virQEMUSaveDataPtr data,
const char *compressedpath,
- bool was_running,
unsigned int flags,
qemuDomainAsyncJob asyncJob)
{
- virQEMUSaveHeader header;
bool bypassSecurityDriver = false;
bool needUnlink = false;
int ret = -1;
@@ -3077,13 +3168,6 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
virFileWrapperFdPtr wrapperFd = NULL;
unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
- memset(&header, 0, sizeof(header));
- memcpy(header.magic, QEMU_SAVE_PARTIAL, sizeof(header.magic));
- header.version = QEMU_SAVE_VERSION;
- header.was_running = was_running ? 1 : 0;
- header.compressed = compressed;
- header.data_len = strlen(domXML) + 1;
-
/* Obtain the file handle. */
if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
@@ -3106,8 +3190,7 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
goto cleanup;
- /* Write header to file, followed by XML */
- if (qemuDomainSaveHeader(fd, path, domXML, &header) < 0)
+ if (virQEMUSaveDataWrite(data, fd, path) < 0)
goto cleanup;
/* Perform the migration */
@@ -3128,21 +3211,10 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
if (virFileWrapperFdClose(wrapperFd) < 0)
goto cleanup;
- if ((fd = qemuOpenFile(driver, vm, path, O_WRONLY, NULL, NULL)) < 0)
+ if ((fd = qemuOpenFile(driver, vm, path, O_WRONLY, NULL, NULL)) < 0 ||
+ virQEMUSaveDataFinish(data, &fd, path) < 0)
goto cleanup;
- memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic));
-
- if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
- virReportSystemError(errno, _("unable to write %s"), path);
- goto cleanup;
- }
-
- if (VIR_CLOSE(fd) < 0) {
- virReportSystemError(errno, _("unable to close %s"), path);
- goto cleanup;
- }
-
ret = 0;
cleanup:
@@ -3172,6 +3244,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
virObjectEventPtr event = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
virCapsPtr caps;
+ virQEMUSaveDataPtr data = NULL;
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
goto cleanup;
@@ -3237,9 +3310,12 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
goto endjob;
}
- ret = qemuDomainSaveMemory(driver, vm, path, xml, compressed,
- compressedpath, was_running, flags,
- QEMU_ASYNC_JOB_SAVE);
+ if (!(data = virQEMUSaveDataNew(xml, was_running, compressed)))
+ goto endjob;
+ xml = NULL;
+
+ ret = qemuDomainSaveMemory(driver, vm, path, data, compressedpath,
+ flags, QEMU_ASYNC_JOB_SAVE);
if (ret < 0)
goto endjob;
@@ -3272,6 +3348,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
cleanup:
VIR_FREE(xml);
+ virQEMUSaveDataFree(data);
qemuDomainEventQueue(driver, event);
virObjectUnref(caps);
return ret;
@@ -6180,8 +6257,7 @@ qemuDomainSaveImageUpdateDef(virQEMUDriverPtr driver,
* @driver: qemu driver data
* @path: path of the save image
* @ret_def: returns domain definition created from the XML stored in the image
- * @ret_header: returns structure filled with data from the image header
- * @xmlout: returns the XML from the image file (may be NULL)
+ * @ret_data: returns structure filled with data from the image header
* @bypass_cache: bypass cache when opening the file
* @wrapperFd: returns the file wrapper structure
* @open_write: open the file for writing (for updates)
@@ -6195,16 +6271,15 @@ static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
const char *path,
virDomainDefPtr *ret_def,
- virQEMUSaveHeaderPtr ret_header,
- char **xmlout,
+ virQEMUSaveDataPtr *ret_data,
bool bypass_cache,
virFileWrapperFdPtr *wrapperFd,
bool open_write,
bool unlink_corrupt)
{
int fd = -1;
- virQEMUSaveHeader header;
- char *xml = NULL;
+ virQEMUSaveDataPtr data = NULL;
+ virQEMUSaveHeaderPtr header;
virDomainDefPtr def = NULL;
int oflags = open_write ? O_RDWR : O_RDONLY;
virCapsPtr caps = NULL;
@@ -6229,81 +6304,82 @@ qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
VIR_FILE_WRAPPER_BYPASS_CACHE)))
goto error;
- if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
+ if (VIR_ALLOC(data) < 0)
+ goto error;
+
+ header = &data->header;
+ if (saferead(fd, header, sizeof(*header)) != sizeof(*header)) {
if (unlink_corrupt) {
if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
virReportSystemError(errno,
_("cannot remove corrupt file: %s"),
path);
- goto error;
+ } else {
+ fd = -3;
}
- return -3;
+ } else {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("failed to read qemu header"));
}
- virReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("failed to read qemu header"));
goto error;
}
- if (memcmp(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic)) != 0) {
+ if (memcmp(header->magic, QEMU_SAVE_MAGIC, sizeof(header->magic)) != 0) {
const char *msg = _("image magic is incorrect");
- if (memcmp(header.magic, QEMU_SAVE_PARTIAL,
- sizeof(header.magic)) == 0) {
+ if (memcmp(header->magic, QEMU_SAVE_PARTIAL,
+ sizeof(header->magic)) == 0) {
msg = _("save image is incomplete");
if (unlink_corrupt) {
if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
virReportSystemError(errno,
_("cannot remove corrupt file: %s"),
path);
- goto error;
+ } else {
+ fd = -3;
}
- return -3;
+ goto error;
}
}
virReportError(VIR_ERR_OPERATION_FAILED, "%s", msg);
goto error;
}
- if (header.version > QEMU_SAVE_VERSION) {
+ if (header->version > QEMU_SAVE_VERSION) {
/* convert endianess and try again */
- bswap_header(&header);
+ bswap_header(header);
}
- if (header.version > QEMU_SAVE_VERSION) {
+ if (header->version > QEMU_SAVE_VERSION) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("image version is not supported (%d > %d)"),
- header.version, QEMU_SAVE_VERSION);
+ header->version, QEMU_SAVE_VERSION);
goto error;
}
- if (header.data_len <= 0) {
+ if (header->data_len <= 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
- _("invalid XML length: %d"), header.data_len);
+ _("invalid header data length: %d"),
header->data_len);
goto error;
}
- if (VIR_ALLOC_N(xml, header.data_len) < 0)
+ if (VIR_ALLOC_N(data->xml, header->data_len) < 0)
goto error;
- if (saferead(fd, xml, header.data_len) != header.data_len) {
+ if (saferead(fd, data->xml, header->data_len) != header->data_len) {
virReportError(VIR_ERR_OPERATION_FAILED,
- "%s", _("failed to read XML"));
+ "%s", _("failed to read domain XML"));
goto error;
}
/* Create a domain from this XML */
- if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt, NULL,
+ if (!(def = virDomainDefParseString(data->xml, caps, driver->xmlopt, NULL,
VIR_DOMAIN_DEF_PARSE_INACTIVE |
VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
goto error;
- if (xmlout)
- *xmlout = xml;
- else
- VIR_FREE(xml);
-
*ret_def = def;
- *ret_header = header;
+ *ret_data = data;
virObjectUnref(caps);
@@ -6311,11 +6387,11 @@ qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
error:
virDomainDefFree(def);
- VIR_FREE(xml);
+ virQEMUSaveDataFree(data);
VIR_FORCE_CLOSE(fd);
virObjectUnref(caps);
- return -1;
+ return fd;
}
static int ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6)
@@ -6323,7 +6399,7 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
virQEMUDriverPtr driver,
virDomainObjPtr vm,
int *fd,
- const virQEMUSaveHeader *header,
+ virQEMUSaveDataPtr data,
const char *path,
bool start_paused,
qemuDomainAsyncJob asyncJob)
@@ -6335,6 +6411,7 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
virCommandPtr cmd = NULL;
char *errbuf = NULL;
virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+ virQEMUSaveHeaderPtr header = &data->header;
if ((header->version == 2) &&
(header->compressed != QEMU_SAVE_FORMAT_RAW)) {
@@ -6444,12 +6521,11 @@ qemuDomainRestoreFlags(virConnectPtr conn,
qemuDomainObjPrivatePtr priv = NULL;
virDomainDefPtr def = NULL;
virDomainObjPtr vm = NULL;
- char *xml = NULL;
char *xmlout = NULL;
const char *newxml = dxml;
int fd = -1;
int ret = -1;
- virQEMUSaveHeader header;
+ virQEMUSaveDataPtr data = NULL;
virFileWrapperFdPtr wrapperFd = NULL;
bool hook_taint = false;
@@ -6460,7 +6536,7 @@ qemuDomainRestoreFlags(virConnectPtr conn,
virNWFilterReadLockFilterUpdates();
- fd = qemuDomainSaveImageOpen(driver, path, &def, &header, &xml,
+ fd = qemuDomainSaveImageOpen(driver, path, &def, &data,
(flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
&wrapperFd, false, false);
if (fd < 0)
@@ -6476,7 +6552,7 @@ qemuDomainRestoreFlags(virConnectPtr conn,
VIR_HOOK_QEMU_OP_RESTORE,
VIR_HOOK_SUBOP_BEGIN,
NULL,
- dxml ? dxml : xml,
+ dxml ? dxml : data->xml,
&xmlout)) < 0)
goto cleanup;
@@ -6506,9 +6582,9 @@ qemuDomainRestoreFlags(virConnectPtr conn,
def = NULL;
if (flags & VIR_DOMAIN_SAVE_RUNNING)
- header.was_running = 1;
+ data->header.was_running = 1;
else if (flags & VIR_DOMAIN_SAVE_PAUSED)
- header.was_running = 0;
+ data->header.was_running = 0;
if (hook_taint) {
priv = vm->privateData;
@@ -6518,7 +6594,7 @@ qemuDomainRestoreFlags(virConnectPtr conn,
if (qemuProcessBeginJob(driver, vm, VIR_DOMAIN_JOB_OPERATION_RESTORE) < 0)
goto cleanup;
- ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
+ ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, data, path,
false, QEMU_ASYNC_JOB_START);
if (virFileWrapperFdClose(wrapperFd) < 0)
VIR_WARN("Failed to close %s", path);
@@ -6528,7 +6604,7 @@ qemuDomainRestoreFlags(virConnectPtr conn,
cleanup:
virDomainDefFree(def);
VIR_FORCE_CLOSE(fd);
- VIR_FREE(xml);
+ virQEMUSaveDataFree(data);
VIR_FREE(xmlout);
virFileWrapperFdFree(wrapperFd);
if (vm && ret < 0)
@@ -6553,12 +6629,12 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char
*path,
char *ret = NULL;
virDomainDefPtr def = NULL;
int fd = -1;
- virQEMUSaveHeader header;
+ virQEMUSaveDataPtr data = NULL;
/* We only take subset of virDomainDefFormat flags. */
virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
- fd = qemuDomainSaveImageOpen(driver, path, &def, &header, NULL,
+ fd = qemuDomainSaveImageOpen(driver, path, &def, &data,
false, NULL, false, false);
if (fd < 0)
@@ -6570,6 +6646,7 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
ret = qemuDomainDefFormatXML(driver, def, flags);
cleanup:
+ virQEMUSaveDataFree(data);
virDomainDefFree(def);
VIR_FORCE_CLOSE(fd);
return ret;
@@ -6584,9 +6661,7 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
virDomainDefPtr def = NULL;
virDomainDefPtr newdef = NULL;
int fd = -1;
- virQEMUSaveHeader header;
- char *xml = NULL;
- size_t len;
+ virQEMUSaveDataPtr data = NULL;
int state = -1;
virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
@@ -6597,7 +6672,7 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
else if (flags & VIR_DOMAIN_SAVE_PAUSED)
state = 0;
- fd = qemuDomainSaveImageOpen(driver, path, &def, &header, &xml,
+ fd = qemuDomainSaveImageOpen(driver, path, &def, &data,
false, NULL, true, false);
if (fd < 0)
@@ -6606,45 +6681,37 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, const char
*path,
if (virDomainSaveImageDefineXMLEnsureACL(conn, def) < 0)
goto cleanup;
- if (STREQ(xml, dxml) &&
- (state < 0 || state == header.was_running)) {
+ if (STREQ(data->xml, dxml) &&
+ (state < 0 || state == data->header.was_running)) {
/* no change to the XML */
ret = 0;
goto cleanup;
}
if (state >= 0)
- header.was_running = state;
+ data->header.was_running = state;
if (!(newdef = qemuDomainSaveImageUpdateDef(driver, def, dxml)))
goto cleanup;
- VIR_FREE(xml);
+ VIR_FREE(data->xml);
- xml = qemuDomainDefFormatXML(driver, newdef,
- VIR_DOMAIN_XML_INACTIVE |
- VIR_DOMAIN_XML_SECURE |
- VIR_DOMAIN_XML_MIGRATABLE);
- if (!xml)
- goto cleanup;
- len = strlen(xml) + 1;
-
- if (len > header.data_len) {
- virReportError(VIR_ERR_OPERATION_FAILED, "%s",
- _("new xml too large to fit in file"));
- goto cleanup;
- }
- if (VIR_EXPAND_N(xml, len, header.data_len - len) < 0)
+ if (!(data->xml = qemuDomainDefFormatXML(driver, newdef,
+ VIR_DOMAIN_XML_INACTIVE |
+ VIR_DOMAIN_XML_SECURE |
+ VIR_DOMAIN_XML_MIGRATABLE)))
goto cleanup;
if (lseek(fd, 0, SEEK_SET) != 0) {
virReportSystemError(errno, _("cannot seek in '%s'"), path);
goto cleanup;
}
- if (safewrite(fd, &header, sizeof(header)) != sizeof(header) ||
- safewrite(fd, xml, len) != len ||
- VIR_CLOSE(fd) < 0) {
- virReportSystemError(errno, _("failed to write xml to '%s'"),
path);
+
+ if (virQEMUSaveDataWrite(data, fd, path) < 0)
+ goto cleanup;
+
+ if (VIR_CLOSE(fd) < 0) {
+ virReportSystemError(errno, _("failed to write header data to
'%s'"), path);
goto cleanup;
}
@@ -6654,7 +6721,7 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
virDomainDefFree(def);
virDomainDefFree(newdef);
VIR_FORCE_CLOSE(fd);
- VIR_FREE(xml);
+ virQEMUSaveDataFree(data);
return ret;
}
@@ -6673,12 +6740,11 @@ qemuDomainObjRestore(virConnectPtr conn,
qemuDomainObjPrivatePtr priv = vm->privateData;
int fd = -1;
int ret = -1;
- char *xml = NULL;
char *xmlout = NULL;
- virQEMUSaveHeader header;
+ virQEMUSaveDataPtr data = NULL;
virFileWrapperFdPtr wrapperFd = NULL;
- fd = qemuDomainSaveImageOpen(driver, path, &def, &header, &xml,
+ fd = qemuDomainSaveImageOpen(driver, path, &def, &data,
bypass_cache, &wrapperFd, false, true);
if (fd < 0) {
if (fd == -3)
@@ -6692,7 +6758,7 @@ qemuDomainObjRestore(virConnectPtr conn,
if ((hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, def->name,
VIR_HOOK_QEMU_OP_RESTORE,
VIR_HOOK_SUBOP_BEGIN,
- NULL, xml, &xmlout)) < 0)
+ NULL, data->xml, &xmlout)) < 0)
goto cleanup;
if (hookret == 0 && !virStringIsEmpty(xmlout)) {
@@ -6726,13 +6792,13 @@ qemuDomainObjRestore(virConnectPtr conn,
virDomainObjAssignDef(vm, def, true, NULL);
def = NULL;
- ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
+ ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, data, path,
start_paused, asyncJob);
if (virFileWrapperFdClose(wrapperFd) < 0)
VIR_WARN("Failed to close %s", path);
cleanup:
- VIR_FREE(xml);
+ virQEMUSaveDataFree(data);
VIR_FREE(xmlout);
virDomainDefFree(def);
VIR_FORCE_CLOSE(fd);
@@ -14298,6 +14364,7 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
virQEMUDriverConfigPtr cfg = NULL;
int compressed;
char *compressedpath = NULL;
+ virQEMUSaveDataPtr data = NULL;
/* If quiesce was requested, then issue a freeze command, and a
* counterpart thaw command when it is actually sent to agent.
@@ -14369,9 +14436,13 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)))
goto cleanup;
- if ((ret = qemuDomainSaveMemory(driver, vm, snap->def->file, xml,
- compressed, compressedpath, resume,
- 0, QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
+ if (!(data = virQEMUSaveDataNew(xml, resume, compressed)))
+ goto cleanup;
+ xml = NULL;
+
+ if ((ret = qemuDomainSaveMemory(driver, vm, snap->def->file, data,
+ compressedpath, 0,
+ QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
goto cleanup;
/* the memory image was created, remove it on errors */
@@ -14439,6 +14510,7 @@ qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
ret = -1;
}
+ virQEMUSaveDataFree(data);
VIR_FREE(xml);
VIR_FREE(compressedpath);
virObjectUnref(cfg);
--
2.13.0