[libvirt] [PATCH 0/4] Fix regression in migration with custom XML

When making ABI stability checks for an active domain, we need to make sure we use the same migratable definition which virDomainGetXMLDesc with the MIGRATABLE flag provides, otherwise the ABI check will fail. https://bugzilla.redhat.com/show_bug.cgi?id=1460952 Jiri Denemark (4): qemu: Introduce qemuDomainDefFromXML helper qemu: Add qemuDomainMigratableDefCheckABIStability qemu: Add qemuDomainCheckABIStability qemu: Use qemuDomainCheckABIStability where needed src/qemu/qemu_domain.c | 108 ++++++++++++++++++++++++++++++++++------------ src/qemu/qemu_domain.h | 4 ++ src/qemu/qemu_driver.c | 71 +++++++++++++++++------------- src/qemu/qemu_migration.c | 2 +- 4 files changed, 126 insertions(+), 59 deletions(-) -- 2.13.1

The main goal of this function is to enable reusing the parsing code from qemuDomainDefCopy. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_domain.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 9b13241f9..2f8afd1d9 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -4179,6 +4179,25 @@ void qemuDomainObjExitRemote(virDomainObjPtr obj) } +static virDomainDefPtr +qemuDomainDefFromXML(virQEMUDriverPtr driver, + const char *xml) +{ + virCapsPtr caps; + virDomainDefPtr def; + + if (!(caps = virQEMUDriverGetCapabilities(driver, false))) + return NULL; + + def = virDomainDefParseString(xml, caps, driver->xmlopt, NULL, + VIR_DOMAIN_DEF_PARSE_INACTIVE | + VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE); + + virObjectUnref(caps); + return def; +} + + virDomainDefPtr qemuDomainDefCopy(virQEMUDriverPtr driver, virDomainDefPtr src, @@ -4186,25 +4205,15 @@ qemuDomainDefCopy(virQEMUDriverPtr driver, { virBuffer buf = VIR_BUFFER_INITIALIZER; virDomainDefPtr ret = NULL; - virCapsPtr caps = NULL; char *xml = NULL; if (qemuDomainDefFormatBuf(driver, src, flags, &buf) < 0) - goto cleanup; + return NULL; xml = virBufferContentAndReset(&buf); + ret = qemuDomainDefFromXML(driver, xml); - if (!(caps = virQEMUDriverGetCapabilities(driver, false))) - goto cleanup; - - if (!(ret = virDomainDefParseString(xml, caps, driver->xmlopt, NULL, - VIR_DOMAIN_DEF_PARSE_INACTIVE | - VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE))) - goto cleanup; - - cleanup: VIR_FREE(xml); - virObjectUnref(caps); return ret; } -- 2.13.1

On Wed, Jun 14, 2017 at 04:16:37PM +0200, Jiri Denemark wrote:
The main goal of this function is to enable reusing the parsing code from qemuDomainDefCopy.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_domain.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-)
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

This patch separates the actual ABI checks from getting migratable defs in qemuDomainDefCheckABIStability so that we can create another wrapper which will use different methods to get the migratable defs. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_domain.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 2f8afd1d9..01644694b 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -5899,6 +5899,26 @@ virDomainABIStability virQEMUDriverDomainABIStability = { }; +static bool +qemuDomainMigratableDefCheckABIStability(virQEMUDriverPtr driver, + virDomainDefPtr src, + virDomainDefPtr migratableSrc, + virDomainDefPtr dst, + virDomainDefPtr migratableDst) +{ + if (!virDomainDefCheckABIStabilityFlags(migratableSrc, + migratableDst, + driver->xmlopt, + VIR_DOMAIN_DEF_ABI_CHECK_SKIP_VOLATILE)) + return false; + + /* Force update any skipped values from the volatile flag */ + dst->mem.cur_balloon = src->mem.cur_balloon; + + return true; +} + + bool qemuDomainDefCheckABIStability(virQEMUDriverPtr driver, virDomainDefPtr src, @@ -5909,23 +5929,15 @@ qemuDomainDefCheckABIStability(virQEMUDriverPtr driver, const unsigned int flags = VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_UPDATE_CPU | VIR_DOMAIN_XML_MIGRATABLE; - const unsigned int check_flags = VIR_DOMAIN_DEF_ABI_CHECK_SKIP_VOLATILE; bool ret = false; if (!(migratableDefSrc = qemuDomainDefCopy(driver, src, flags)) || !(migratableDefDst = qemuDomainDefCopy(driver, dst, flags))) goto cleanup; - if (!virDomainDefCheckABIStabilityFlags(migratableDefSrc, - migratableDefDst, - driver->xmlopt, - check_flags)) - goto cleanup; - - /* Force update any skipped values from the volatile flag */ - dst->mem.cur_balloon = src->mem.cur_balloon; - - ret = true; + ret = qemuDomainMigratableDefCheckABIStability(driver, + src, migratableDefSrc, + dst, migratableDefDst); cleanup: virDomainDefFree(migratableDefSrc); -- 2.13.1

On Wed, Jun 14, 2017 at 04:16:38PM +0200, Jiri Denemark wrote:
This patch separates the actual ABI checks from getting migratable defs in qemuDomainDefCheckABIStability so that we can create another wrapper which will use different methods to get the migratable defs.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_domain.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-)
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

When making ABI stability checks for an active domain, we need to make sure we use the same migratable definition which virDomainGetXMLDesc with the MIGRATABLE flag provides, otherwise the ABI check will fail. This is implemented in the new qemuDomainCheckABIStability which takes a domain object and generates the right migratable definition from it. Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_domain.c | 41 ++++++++++++++++++++++++++++++++++++----- src/qemu/qemu_domain.h | 4 ++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 01644694b..6838d2eaa 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -5919,6 +5919,10 @@ qemuDomainMigratableDefCheckABIStability(virQEMUDriverPtr driver, } +#define COPY_FLAGS (VIR_DOMAIN_XML_SECURE | \ + VIR_DOMAIN_XML_UPDATE_CPU | \ + VIR_DOMAIN_XML_MIGRATABLE) + bool qemuDomainDefCheckABIStability(virQEMUDriverPtr driver, virDomainDefPtr src, @@ -5926,13 +5930,10 @@ qemuDomainDefCheckABIStability(virQEMUDriverPtr driver, { virDomainDefPtr migratableDefSrc = NULL; virDomainDefPtr migratableDefDst = NULL; - const unsigned int flags = VIR_DOMAIN_XML_SECURE | - VIR_DOMAIN_XML_UPDATE_CPU | - VIR_DOMAIN_XML_MIGRATABLE; bool ret = false; - if (!(migratableDefSrc = qemuDomainDefCopy(driver, src, flags)) || - !(migratableDefDst = qemuDomainDefCopy(driver, dst, flags))) + if (!(migratableDefSrc = qemuDomainDefCopy(driver, src, COPY_FLAGS)) || + !(migratableDefDst = qemuDomainDefCopy(driver, dst, COPY_FLAGS))) goto cleanup; ret = qemuDomainMigratableDefCheckABIStability(driver, @@ -5945,6 +5946,36 @@ qemuDomainDefCheckABIStability(virQEMUDriverPtr driver, return ret; } + +bool +qemuDomainCheckABIStability(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDefPtr dst) +{ + virDomainDefPtr migratableSrc = NULL; + virDomainDefPtr migratableDst = NULL; + char *xml = NULL; + bool ret = false; + + if (!(xml = qemuDomainFormatXML(driver, vm, COPY_FLAGS)) || + !(migratableSrc = qemuDomainDefFromXML(driver, xml)) || + !(migratableDst = qemuDomainDefCopy(driver, dst, COPY_FLAGS))) + goto cleanup; + + ret = qemuDomainMigratableDefCheckABIStability(driver, + vm->def, migratableSrc, + dst, migratableDst); + + cleanup: + VIR_FREE(xml); + virDomainDefFree(migratableSrc); + virDomainDefFree(migratableDst); + return ret; +} + +#undef COPY_FLAGS + + bool qemuDomainAgentAvailable(virDomainObjPtr vm, bool reportError) diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index ef3a33076..a2cd155c3 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -666,6 +666,10 @@ bool qemuDomainDefCheckABIStability(virQEMUDriverPtr driver, virDomainDefPtr src, virDomainDefPtr dst); +bool qemuDomainCheckABIStability(virQEMUDriverPtr driver, + virDomainObjPtr vm, + virDomainDefPtr dst); + bool qemuDomainAgentAvailable(virDomainObjPtr vm, bool reportError); -- 2.13.1

On Wed, Jun 14, 2017 at 04:16:39PM +0200, Jiri Denemark wrote:
When making ABI stability checks for an active domain, we need to make sure we use the same migratable definition which virDomainGetXMLDesc with the MIGRATABLE flag provides, otherwise the ABI check will fail. This is implemented in the new qemuDomainCheckABIStability which takes a domain object and generates the right migratable definition from it.
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- src/qemu/qemu_domain.c | 41 ++++++++++++++++++++++++++++++++++++----- src/qemu/qemu_domain.h | 4 ++++ 2 files changed, 40 insertions(+), 5 deletions(-)
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>

Most places which want to check ABI stability for an active domain need to call this API rather than the original qemuDomainDefCheckABIStability. The only exception is in snapshots where we need to decide what to do depending on the saved image data. https://bugzilla.redhat.com/show_bug.cgi?id=1460952 Signed-off-by: Jiri Denemark <jdenemar@redhat.com> --- Notes: Best viewed with -b :-) src/qemu/qemu_driver.c | 71 +++++++++++++++++++++++++++-------------------- src/qemu/qemu_migration.c | 2 +- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ba1dba5b7..d3526da8c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -3340,7 +3340,7 @@ qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom, VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE))) { goto endjob; } - if (!qemuDomainDefCheckABIStability(driver, vm->def, def)) { + if (!qemuDomainCheckABIStability(driver, vm, def)) { virDomainDefFree(def); goto endjob; } @@ -15412,39 +15412,50 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, * to have finer control. */ if (virDomainObjIsActive(vm)) { /* Transitions 5, 6, 8, 9 */ - /* Replace the CPU in config and put the original one in priv - * once we're done. - */ - if (cookie && cookie->cpu && config->cpu) { - origCPU = config->cpu; - if (!(config->cpu = virCPUDefCopy(cookie->cpu))) - goto endjob; - } - /* Check for ABI compatibility. We need to do this check against * the migratable XML or it will always fail otherwise */ - if (config && - !qemuDomainDefCheckABIStability(driver, vm->def, config)) { - virErrorPtr err = virGetLastError(); + if (config) { + bool compatible; - if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) { - /* Re-spawn error using correct category. */ - if (err->code == VIR_ERR_CONFIG_UNSUPPORTED) - virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s", - err->str2); - goto endjob; + /* Replace the CPU in config and put the original one in priv + * once we're done. When we have the updated CPU def in the + * cookie, we don't want to replace the CPU in migratable def + * when doing ABI checks to make sure the current CPU exactly + * matches the one used at the time the snapshot was taken. + */ + if (cookie && cookie->cpu && config->cpu) { + origCPU = config->cpu; + if (!(config->cpu = virCPUDefCopy(cookie->cpu))) + goto endjob; + + compatible = qemuDomainDefCheckABIStability(driver, vm->def, + config); + } else { + compatible = qemuDomainCheckABIStability(driver, vm, config); + } + + if (!compatible) { + virErrorPtr err = virGetLastError(); + + if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) { + /* Re-spawn error using correct category. */ + if (err->code == VIR_ERR_CONFIG_UNSUPPORTED) + virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s", + err->str2); + goto endjob; + } + virResetError(err); + qemuProcessStop(driver, vm, + VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, + QEMU_ASYNC_JOB_START, 0); + virDomainAuditStop(vm, "from-snapshot"); + detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT; + event = virDomainEventLifecycleNewFromObj(vm, + VIR_DOMAIN_EVENT_STOPPED, + detail); + qemuDomainEventQueue(driver, event); + goto load; } - virResetError(err); - qemuProcessStop(driver, vm, - VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, - QEMU_ASYNC_JOB_START, 0); - virDomainAuditStop(vm, "from-snapshot"); - detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT; - event = virDomainEventLifecycleNewFromObj(vm, - VIR_DOMAIN_EVENT_STOPPED, - detail); - qemuDomainEventQueue(driver, event); - goto load; } priv = vm->privateData; diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index dce2504a3..8129dcd40 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -2059,7 +2059,7 @@ qemuMigrationBeginPhase(virQEMUDriverPtr driver, VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE))) goto cleanup; - if (!qemuDomainDefCheckABIStability(driver, vm->def, def)) + if (!qemuDomainCheckABIStability(driver, vm, def)) goto cleanup; rv = qemuDomainDefFormatLive(driver, def, NULL, false, true); -- 2.13.1

On Wed, Jun 14, 2017 at 04:16:40PM +0200, Jiri Denemark wrote:
Most places which want to check ABI stability for an active domain need to call this API rather than the original qemuDomainDefCheckABIStability. The only exception is in snapshots where we need to decide what to do depending on the saved image data.
https://bugzilla.redhat.com/show_bug.cgi?id=1460952
Signed-off-by: Jiri Denemark <jdenemar@redhat.com> ---
Notes: Best viewed with -b :-)
src/qemu/qemu_driver.c | 71 +++++++++++++++++++++++++++-------------------- src/qemu/qemu_migration.c | 2 +- 2 files changed, 42 insertions(+), 31 deletions(-)
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
participants (2)
-
Jiri Denemark
-
Pavel Hrdina