mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-01 17:35:17 +00:00
qemu: Decompose qemuSaveImageOpen
Split the reading of libvirt's save image metadata from the opening of the fd that will be passed to QEMU. This allows improved error handling and provides more flexibility users of qemu_saveimage. Signed-off-by: Jim Fehlig <jfehlig@suse.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
50d65b94ef
commit
517248e239
@ -5775,7 +5775,10 @@ qemuDomainRestoreInternal(virConnectPtr conn,
|
||||
if (flags & VIR_DOMAIN_SAVE_RESET_NVRAM)
|
||||
reset_nvram = true;
|
||||
|
||||
fd = qemuSaveImageOpen(driver, NULL, path, &def, &data,
|
||||
if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0)
|
||||
goto cleanup;
|
||||
|
||||
fd = qemuSaveImageOpen(driver, path,
|
||||
(flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
|
||||
&wrapperFd, false);
|
||||
if (fd < 0)
|
||||
@ -5906,15 +5909,11 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
|
||||
virQEMUDriver *driver = conn->privateData;
|
||||
char *ret = NULL;
|
||||
g_autoptr(virDomainDef) def = NULL;
|
||||
int fd = -1;
|
||||
virQEMUSaveData *data = NULL;
|
||||
|
||||
virCheckFlags(VIR_DOMAIN_SAVE_IMAGE_XML_SECURE, NULL);
|
||||
|
||||
fd = qemuSaveImageOpen(driver, NULL, path, &def, &data,
|
||||
false, NULL, false);
|
||||
|
||||
if (fd < 0)
|
||||
if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virDomainSaveImageGetXMLDescEnsureACL(conn, def) < 0)
|
||||
@ -5924,7 +5923,6 @@ qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
|
||||
|
||||
cleanup:
|
||||
virQEMUSaveDataFree(data);
|
||||
VIR_FORCE_CLOSE(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -5948,9 +5946,10 @@ qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
|
||||
else if (flags & VIR_DOMAIN_SAVE_PAUSED)
|
||||
state = 0;
|
||||
|
||||
fd = qemuSaveImageOpen(driver, NULL, path, &def, &data,
|
||||
false, NULL, true);
|
||||
if (qemuSaveImageGetMetadata(driver, NULL, path, &def, &data) < 0)
|
||||
goto cleanup;
|
||||
|
||||
fd = qemuSaveImageOpen(driver, path, 0, NULL, false);
|
||||
if (fd < 0)
|
||||
goto cleanup;
|
||||
|
||||
@ -6007,7 +6006,6 @@ qemuDomainManagedSaveGetXMLDesc(virDomainPtr dom, unsigned int flags)
|
||||
g_autofree char *path = NULL;
|
||||
char *ret = NULL;
|
||||
g_autoptr(virDomainDef) def = NULL;
|
||||
int fd = -1;
|
||||
virQEMUSaveData *data = NULL;
|
||||
qemuDomainObjPrivate *priv;
|
||||
|
||||
@ -6029,15 +6027,13 @@ qemuDomainManagedSaveGetXMLDesc(virDomainPtr dom, unsigned int flags)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((fd = qemuSaveImageOpen(driver, priv->qemuCaps, path, &def, &data,
|
||||
false, NULL, false)) < 0)
|
||||
if (qemuSaveImageGetMetadata(driver, priv->qemuCaps, path, &def, &data) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = qemuDomainDefFormatXML(driver, priv->qemuCaps, def, flags);
|
||||
|
||||
cleanup:
|
||||
virQEMUSaveDataFree(data);
|
||||
VIR_FORCE_CLOSE(fd);
|
||||
virDomainObjEndAPI(&vm);
|
||||
return ret;
|
||||
}
|
||||
@ -6093,9 +6089,8 @@ qemuDomainObjRestore(virConnectPtr conn,
|
||||
virQEMUSaveData *data = NULL;
|
||||
virFileWrapperFd *wrapperFd = NULL;
|
||||
|
||||
fd = qemuSaveImageOpen(driver, NULL, path, &def, &data,
|
||||
bypass_cache, &wrapperFd, false);
|
||||
if (fd < 0) {
|
||||
ret = qemuSaveImageGetMetadata(driver, NULL, path, &def, &data);
|
||||
if (ret < 0) {
|
||||
if (qemuSaveImageIsCorrupt(driver, path)) {
|
||||
if (unlink(path) < 0) {
|
||||
virReportSystemError(errno,
|
||||
@ -6110,6 +6105,10 @@ qemuDomainObjRestore(virConnectPtr conn,
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
fd = qemuSaveImageOpen(driver, path, bypass_cache, &wrapperFd, false);
|
||||
if (fd < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
|
||||
int hookret;
|
||||
|
||||
|
@ -249,6 +249,84 @@ qemuSaveImageGetCompressionCommand(virQEMUSaveFormat format)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuSaveImageReadHeader(int fd, virQEMUSaveData **ret_data)
|
||||
{
|
||||
g_autoptr(virQEMUSaveData) data = NULL;
|
||||
virQEMUSaveHeader *header;
|
||||
size_t xml_len;
|
||||
size_t cookie_len;
|
||||
|
||||
data = g_new0(virQEMUSaveData, 1);
|
||||
header = &data->header;
|
||||
if (saferead(fd, header, sizeof(*header)) != sizeof(*header)) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
"%s", _("failed to read qemu header"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(header->magic, QEMU_SAVE_MAGIC, sizeof(header->magic)) != 0) {
|
||||
if (memcmp(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic)) == 0) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||
_("save image is incomplete"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||
_("image magic is incorrect"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->version > QEMU_SAVE_VERSION) {
|
||||
/* convert endianness and try again */
|
||||
qemuSaveImageBswapHeader(header);
|
||||
}
|
||||
|
||||
if (header->version > QEMU_SAVE_VERSION) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("image version is not supported (%1$d > %2$d)"),
|
||||
header->version, QEMU_SAVE_VERSION);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->data_len <= 0) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("invalid header data length: %1$d"), header->data_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->cookieOffset)
|
||||
xml_len = header->cookieOffset;
|
||||
else
|
||||
xml_len = header->data_len;
|
||||
|
||||
cookie_len = header->data_len - xml_len;
|
||||
|
||||
data->xml = g_new0(char, xml_len);
|
||||
|
||||
if (saferead(fd, data->xml, xml_len) != xml_len) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
"%s", _("failed to read domain XML"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cookie_len > 0) {
|
||||
data->cookie = g_new0(char, cookie_len);
|
||||
|
||||
if (saferead(fd, data->cookie, cookie_len) != cookie_len) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||
_("failed to read cookie"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_data)
|
||||
*ret_data = g_steal_pointer(&data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qemuSaveImageDecompressionStart:
|
||||
* @data: data from memory state file
|
||||
@ -520,6 +598,7 @@ qemuSaveImageGetCompressionProgram(const char *imageFormat,
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qemuSaveImageIsCorrupt:
|
||||
* @driver: qemu driver data
|
||||
@ -551,26 +630,61 @@ qemuSaveImageIsCorrupt(virQEMUDriver *driver, const char *path)
|
||||
|
||||
|
||||
/**
|
||||
* qemuSaveImageOpen:
|
||||
* qemuSaveImageGetMetadata:
|
||||
* @driver: qemu driver data
|
||||
* @qemuCaps: pointer to qemuCaps if the domain is running or NULL
|
||||
* @path: path of the save image
|
||||
* @ret_def: returns domain definition created from the XML stored in the image
|
||||
* @ret_data: returns structure filled with data from the image header
|
||||
*
|
||||
* Open the save image file, read libvirt's save image metadata, and populate
|
||||
* the @ret_def and @ret_data structures. Returns 0 on success and -1 on failure.
|
||||
*/
|
||||
int
|
||||
qemuSaveImageGetMetadata(virQEMUDriver *driver,
|
||||
virQEMUCaps *qemuCaps,
|
||||
const char *path,
|
||||
virDomainDef **ret_def,
|
||||
virQEMUSaveData **ret_data)
|
||||
{
|
||||
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
|
||||
VIR_AUTOCLOSE fd = -1;
|
||||
virQEMUSaveData *data;
|
||||
g_autoptr(virDomainDef) def = NULL;
|
||||
int rc;
|
||||
|
||||
if ((fd = qemuDomainOpenFile(cfg, NULL, path, O_RDONLY, NULL)) < 0)
|
||||
return -1;
|
||||
|
||||
if ((rc = qemuSaveImageReadHeader(fd, ret_data)) < 0)
|
||||
return rc;
|
||||
|
||||
data = *ret_data;
|
||||
/* Create a domain from this XML */
|
||||
if (!(def = virDomainDefParseString(data->xml, driver->xmlopt, qemuCaps,
|
||||
VIR_DOMAIN_DEF_PARSE_INACTIVE |
|
||||
VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
|
||||
return -1;
|
||||
|
||||
*ret_def = g_steal_pointer(&def);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* qemuSaveImageOpen:
|
||||
* @driver: qemu driver data
|
||||
* @path: path of the save image
|
||||
* @bypass_cache: bypass cache when opening the file
|
||||
* @wrapperFd: returns the file wrapper structure
|
||||
* @open_write: open the file for writing (for updates)
|
||||
*
|
||||
* Returns the opened fd of the save image file and fills the appropriate fields
|
||||
* on success. On error returns -1 on most failures, -3 if a corrupt image was
|
||||
* detected.
|
||||
* Returns the opened fd of the save image file on success, -1 on failure.
|
||||
*/
|
||||
int
|
||||
qemuSaveImageOpen(virQEMUDriver *driver,
|
||||
virQEMUCaps *qemuCaps,
|
||||
const char *path,
|
||||
virDomainDef **ret_def,
|
||||
virQEMUSaveData **ret_data,
|
||||
bool bypass_cache,
|
||||
virFileWrapperFd **wrapperFd,
|
||||
bool open_write)
|
||||
@ -578,12 +692,7 @@ qemuSaveImageOpen(virQEMUDriver *driver,
|
||||
g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
|
||||
VIR_AUTOCLOSE fd = -1;
|
||||
int ret = -1;
|
||||
g_autoptr(virQEMUSaveData) data = NULL;
|
||||
virQEMUSaveHeader *header;
|
||||
g_autoptr(virDomainDef) def = NULL;
|
||||
int oflags = open_write ? O_RDWR : O_RDONLY;
|
||||
size_t xml_len;
|
||||
size_t cookie_len;
|
||||
|
||||
if (bypass_cache) {
|
||||
int directFlag = virFileDirectFdFlag();
|
||||
@ -603,78 +712,10 @@ qemuSaveImageOpen(virQEMUDriver *driver,
|
||||
VIR_FILE_WRAPPER_BYPASS_CACHE)))
|
||||
return -1;
|
||||
|
||||
data = g_new0(virQEMUSaveData, 1);
|
||||
|
||||
header = &data->header;
|
||||
if (saferead(fd, header, sizeof(*header)) != sizeof(*header)) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
"%s", _("failed to read qemu header"));
|
||||
/* Read the header to position the file pointer for QEMU. Unfortunately we
|
||||
* can't use lseek with virFileWrapperFD. */
|
||||
if (qemuSaveImageReadHeader(fd, NULL) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(header->magic, QEMU_SAVE_MAGIC, sizeof(header->magic)) != 0) {
|
||||
if (memcmp(header->magic, QEMU_SAVE_PARTIAL, sizeof(header->magic)) == 0) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||
_("save image is incomplete"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||
_("image magic is incorrect"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->version > QEMU_SAVE_VERSION) {
|
||||
/* convert endianness and try again */
|
||||
qemuSaveImageBswapHeader(header);
|
||||
}
|
||||
|
||||
if (header->version > QEMU_SAVE_VERSION) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("image version is not supported (%1$d > %2$d)"),
|
||||
header->version, QEMU_SAVE_VERSION);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->data_len <= 0) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
_("invalid header data length: %1$d"), header->data_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->cookieOffset)
|
||||
xml_len = header->cookieOffset;
|
||||
else
|
||||
xml_len = header->data_len;
|
||||
|
||||
cookie_len = header->data_len - xml_len;
|
||||
|
||||
data->xml = g_new0(char, xml_len);
|
||||
|
||||
if (saferead(fd, data->xml, xml_len) != xml_len) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED,
|
||||
"%s", _("failed to read domain XML"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cookie_len > 0) {
|
||||
data->cookie = g_new0(char, cookie_len);
|
||||
|
||||
if (saferead(fd, data->cookie, cookie_len) != cookie_len) {
|
||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
||||
_("failed to read cookie"));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a domain from this XML */
|
||||
if (!(def = virDomainDefParseString(data->xml, driver->xmlopt, qemuCaps,
|
||||
VIR_DOMAIN_DEF_PARSE_INACTIVE |
|
||||
VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
|
||||
return -1;
|
||||
|
||||
*ret_def = g_steal_pointer(&def);
|
||||
*ret_data = g_steal_pointer(&data);
|
||||
|
||||
ret = fd;
|
||||
fd = -1;
|
||||
|
@ -74,16 +74,21 @@ qemuSaveImageIsCorrupt(virQEMUDriver *driver,
|
||||
const char *path)
|
||||
ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int
|
||||
qemuSaveImageGetMetadata(virQEMUDriver *driver,
|
||||
virQEMUCaps *qemuCaps,
|
||||
const char *path,
|
||||
virDomainDef **ret_def,
|
||||
virQEMUSaveData **ret_data)
|
||||
ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5);
|
||||
|
||||
int
|
||||
qemuSaveImageOpen(virQEMUDriver *driver,
|
||||
virQEMUCaps *qemuCaps,
|
||||
const char *path,
|
||||
virDomainDef **ret_def,
|
||||
virQEMUSaveData **ret_data,
|
||||
bool bypass_cache,
|
||||
virFileWrapperFd **wrapperFd,
|
||||
bool open_write)
|
||||
ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4);
|
||||
ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4);
|
||||
|
||||
int
|
||||
qemuSaveImageGetCompressionProgram(const char *imageFormat,
|
||||
|
@ -2377,10 +2377,12 @@ qemuSnapshotRevertExternalPrepare(virDomainObj *vm,
|
||||
g_autoptr(virDomainDef) savedef = NULL;
|
||||
|
||||
memdata->path = snapdef->memorysnapshotfile;
|
||||
memdata->fd = qemuSaveImageOpen(driver, NULL, memdata->path,
|
||||
&savedef, &memdata->data,
|
||||
false, NULL, false);
|
||||
if (qemuSaveImageGetMetadata(driver, NULL, memdata->path, &savedef,
|
||||
&memdata->data) < 0)
|
||||
return -1;
|
||||
|
||||
memdata->fd = qemuSaveImageOpen(driver, memdata->path,
|
||||
false, NULL, false);
|
||||
if (memdata->fd < 0)
|
||||
return -1;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user