mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-09 14:35:25 +00:00
save: support qemu modifying xml on domain save/restore
With this, it is possible to update the path to a disk backing image on either the save or restore action, without having to binary edit the XML embedded in the state file. This also modifies virDomainSave to output a smaller xml (only the inactive xml, which is all the more virDomainRestore parses), while still guaranteeing padding for most typical abi-compatible xml replacements, necessary so that the next patch for virDomainSaveImageDefineXML will not cause unnecessary modifications to the save image file. * src/qemu/qemu_driver.c (qemuDomainSaveInternal): Add parameter, only use inactive state, and guarantee padding. (qemuDomainSaveImageOpen): Add parameter. (qemuDomainSaveFlags, qemuDomainManagedSave) (qemuDomainRestoreFlags, qemuDomainObjRestore): Update callers.
This commit is contained in:
parent
ff81956ac6
commit
0ea479f8f6
@ -2194,7 +2194,7 @@ qemuCompressProgramName(int compress)
|
|||||||
static int
|
static int
|
||||||
qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
|
qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
|
||||||
virDomainObjPtr vm, const char *path,
|
virDomainObjPtr vm, const char *path,
|
||||||
int compressed, bool bypass_cache)
|
int compressed, bool bypass_cache, const char *xmlin)
|
||||||
{
|
{
|
||||||
char *xml = NULL;
|
char *xml = NULL;
|
||||||
struct qemud_save_header header;
|
struct qemud_save_header header;
|
||||||
@ -2205,7 +2205,9 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
|
|||||||
qemuDomainObjPrivatePtr priv;
|
qemuDomainObjPrivatePtr priv;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
bool is_reg = false;
|
bool is_reg = false;
|
||||||
|
size_t len;
|
||||||
unsigned long long offset;
|
unsigned long long offset;
|
||||||
|
unsigned long long pad;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
uid_t uid = getuid();
|
uid_t uid = getuid();
|
||||||
gid_t gid = getgid();
|
gid_t gid = getgid();
|
||||||
@ -2240,15 +2242,55 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get XML for the domain */
|
/* Get XML for the domain. Restore needs only the inactive xml,
|
||||||
xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
|
* including secure. We should get the same result whether xmlin
|
||||||
|
* is NULL or whether it was the live xml of the domain moments
|
||||||
|
* before. */
|
||||||
|
if (xmlin) {
|
||||||
|
virDomainDefPtr def = NULL;
|
||||||
|
|
||||||
|
if (!(def = virDomainDefParseString(driver->caps, xmlin,
|
||||||
|
QEMU_EXPECTED_VIRT_TYPES,
|
||||||
|
VIR_DOMAIN_XML_INACTIVE))) {
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
if (!virDomainDefCheckABIStability(vm->def, def)) {
|
||||||
|
virDomainDefFree(def);
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
xml = virDomainDefFormat(def, (VIR_DOMAIN_XML_INACTIVE |
|
||||||
|
VIR_DOMAIN_XML_SECURE));
|
||||||
|
} else {
|
||||||
|
xml = virDomainDefFormat(vm->def, (VIR_DOMAIN_XML_INACTIVE |
|
||||||
|
VIR_DOMAIN_XML_SECURE));
|
||||||
|
}
|
||||||
if (!xml) {
|
if (!xml) {
|
||||||
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
qemuReportError(VIR_ERR_OPERATION_FAILED,
|
||||||
"%s", _("failed to get domain xml"));
|
"%s", _("failed to get domain xml"));
|
||||||
goto endjob;
|
goto endjob;
|
||||||
}
|
}
|
||||||
header.xml_len = strlen(xml) + 1;
|
len = strlen(xml) + 1;
|
||||||
|
offset = sizeof(header) + len;
|
||||||
|
|
||||||
|
/* Due to way we append QEMU state on our header with dd,
|
||||||
|
* we need to ensure there's a 512 byte boundary. Unfortunately
|
||||||
|
* we don't have an explicit offset in the header, so we fake
|
||||||
|
* it by padding the XML string with NUL bytes. Additionally,
|
||||||
|
* we want to ensure that virDomainSaveImageDefineXML can supply
|
||||||
|
* slightly larger XML, so we add a miminum padding prior to
|
||||||
|
* rounding out to page boundaries.
|
||||||
|
*/
|
||||||
|
pad = 1024;
|
||||||
|
pad += (QEMU_MONITOR_MIGRATE_TO_FILE_BS -
|
||||||
|
((offset + pad) % QEMU_MONITOR_MIGRATE_TO_FILE_BS));
|
||||||
|
if (VIR_EXPAND_N(xml, len, pad) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
offset += pad;
|
||||||
|
header.xml_len = len;
|
||||||
|
|
||||||
|
/* Obtain the file handle. */
|
||||||
/* path might be a pre-existing block dev, in which case
|
/* path might be a pre-existing block dev, in which case
|
||||||
* we need to skip the create step, and also avoid unlink
|
* we need to skip the create step, and also avoid unlink
|
||||||
* in the failure case */
|
* in the failure case */
|
||||||
@ -2269,29 +2311,6 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = sizeof(header) + header.xml_len;
|
|
||||||
|
|
||||||
/* Due to way we append QEMU state on our header with dd,
|
|
||||||
* we need to ensure there's a 512 byte boundary. Unfortunately
|
|
||||||
* we don't have an explicit offset in the header, so we fake
|
|
||||||
* it by padding the XML string with NULLs.
|
|
||||||
*/
|
|
||||||
if (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS) {
|
|
||||||
unsigned long long pad =
|
|
||||||
QEMU_MONITOR_MIGRATE_TO_FILE_BS -
|
|
||||||
(offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS);
|
|
||||||
|
|
||||||
if (VIR_REALLOC_N(xml, header.xml_len + pad) < 0) {
|
|
||||||
virReportOOMError();
|
|
||||||
goto endjob;
|
|
||||||
}
|
|
||||||
memset(xml + header.xml_len, 0, pad);
|
|
||||||
offset += pad;
|
|
||||||
header.xml_len += pad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Obtain the file handle. */
|
|
||||||
|
|
||||||
/* First try creating the file as root */
|
/* First try creating the file as root */
|
||||||
if (bypass_cache) {
|
if (bypass_cache) {
|
||||||
directFlag = virFileDirectFdFlag();
|
directFlag = virFileDirectFdFlag();
|
||||||
@ -2462,11 +2481,6 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
|
|||||||
virDomainObjPtr vm = NULL;
|
virDomainObjPtr vm = NULL;
|
||||||
|
|
||||||
virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE, -1);
|
virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE, -1);
|
||||||
if (dxml) {
|
|
||||||
qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
|
|
||||||
_("xml modification unsupported"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
|
|
||||||
@ -2504,7 +2518,8 @@ qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
|
ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
|
||||||
(flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0);
|
(flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
|
||||||
|
dxml);
|
||||||
vm = NULL;
|
vm = NULL;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -2568,7 +2583,8 @@ qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
|
|||||||
|
|
||||||
compressed = QEMUD_SAVE_FORMAT_RAW;
|
compressed = QEMUD_SAVE_FORMAT_RAW;
|
||||||
ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
|
ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
|
||||||
(flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0);
|
(flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
|
||||||
|
NULL);
|
||||||
vm = NULL;
|
vm = NULL;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@ -3711,7 +3727,8 @@ qemuDomainSaveImageOpen(struct qemud_driver *driver,
|
|||||||
const char *path,
|
const char *path,
|
||||||
virDomainDefPtr *ret_def,
|
virDomainDefPtr *ret_def,
|
||||||
struct qemud_save_header *ret_header,
|
struct qemud_save_header *ret_header,
|
||||||
bool bypass_cache, virFileDirectFdPtr *directFd)
|
bool bypass_cache, virFileDirectFdPtr *directFd,
|
||||||
|
const char *xmlin)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
struct qemud_save_header header;
|
struct qemud_save_header header;
|
||||||
@ -3795,6 +3812,20 @@ qemuDomainSaveImageOpen(struct qemud_driver *driver,
|
|||||||
QEMU_EXPECTED_VIRT_TYPES,
|
QEMU_EXPECTED_VIRT_TYPES,
|
||||||
VIR_DOMAIN_XML_INACTIVE)))
|
VIR_DOMAIN_XML_INACTIVE)))
|
||||||
goto error;
|
goto error;
|
||||||
|
if (xmlin) {
|
||||||
|
virDomainDefPtr def2 = NULL;
|
||||||
|
|
||||||
|
if (!(def2 = virDomainDefParseString(driver->caps, xmlin,
|
||||||
|
QEMU_EXPECTED_VIRT_TYPES,
|
||||||
|
VIR_DOMAIN_XML_INACTIVE)))
|
||||||
|
goto error;
|
||||||
|
if (!virDomainDefCheckABIStability(def, def2)) {
|
||||||
|
virDomainDefFree(def2);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
virDomainDefFree(def);
|
||||||
|
def = def2;
|
||||||
|
}
|
||||||
|
|
||||||
VIR_FREE(xml);
|
VIR_FREE(xml);
|
||||||
|
|
||||||
@ -3929,17 +3960,12 @@ qemuDomainRestoreFlags(virConnectPtr conn,
|
|||||||
virFileDirectFdPtr directFd = NULL;
|
virFileDirectFdPtr directFd = NULL;
|
||||||
|
|
||||||
virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE, -1);
|
virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE, -1);
|
||||||
if (dxml) {
|
|
||||||
qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
|
|
||||||
_("xml modification unsupported"));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
|
|
||||||
fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
|
fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
|
||||||
(flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
|
(flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
|
||||||
&directFd);
|
&directFd, dxml);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -3999,7 +4025,7 @@ qemuDomainObjRestore(virConnectPtr conn,
|
|||||||
virFileDirectFdPtr directFd = NULL;
|
virFileDirectFdPtr directFd = NULL;
|
||||||
|
|
||||||
fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
|
fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
|
||||||
bypass_cache, &directFd);
|
bypass_cache, &directFd, NULL);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user