[libvirt] [PATCH v2 0/4] qemu: track presence of blockjobs in status XML (blockdev-add saga)

V2: Patches 1/4 and 3/4 are new. Patch 2/4 and 4/4 were fixed to use virTristateBool. Peter Krempa (4): util: Add functions to simplify bool->virTristate(Bool|Switch) assignment qemu: domain: Mark if no blockjobs are active in the status XML qemu: process: Simplify acces to individual disk when reconnecting qemu: process: Don't redetect backing chain on reconnect src/libvirt_private.syms | 2 ++ src/qemu/qemu_domain.c | 38 ++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_domain.h | 3 +++ src/qemu/qemu_process.c | 22 +++++++++++++--------- src/util/virutil.c | 20 ++++++++++++++++++++ src/util/virutil.h | 3 +++ tests/qemuxml2xmltest.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 123 insertions(+), 9 deletions(-) -- 2.14.1

virTristateBoolFromBool and virTristateSwitchFromBool convert a boolean to the correct enum value. --- src/libvirt_private.syms | 2 ++ src/util/virutil.c | 20 ++++++++++++++++++++ src/util/virutil.h | 3 +++ 3 files changed, 25 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7a12d6a14..9243c5591 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2950,8 +2950,10 @@ virSetNonBlock; virSetSockReuseAddr; virSetUIDGID; virSetUIDGIDWithCaps; +virTristateBoolFromBool; virTristateBoolTypeFromString; virTristateBoolTypeToString; +virTristateSwitchFromBool; virTristateSwitchTypeFromString; virTristateSwitchTypeToString; virUpdateSelfLastChanged; diff --git a/src/util/virutil.c b/src/util/virutil.c index e08f9fa4a..170e92192 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -100,6 +100,26 @@ VIR_ENUM_IMPL(virTristateSwitch, VIR_TRISTATE_SWITCH_LAST, "off") +virTristateBool +virTristateBoolFromBool(bool val) +{ + if (val) + return VIR_TRISTATE_BOOL_YES; + else + return VIR_TRISTATE_BOOL_NO; +} + + +virTristateSwitch +virTristateSwitchFromBool(bool val) +{ + if (val) + return VIR_TRISTATE_SWITCH_ON; + else + return VIR_TRISTATE_SWITCH_OFF; +} + + #ifndef WIN32 int virSetInherit(int fd, bool inherit) diff --git a/src/util/virutil.h b/src/util/virutil.h index 49382557f..a862a8a63 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -193,6 +193,9 @@ typedef enum { VIR_ENUM_DECL(virTristateBool) VIR_ENUM_DECL(virTristateSwitch) +virTristateBool virTristateBoolFromBool(bool val); +virTristateSwitch virTristateSwitchFromBool(bool val); + /* the two enums must be in sync to be able to use helpers interchangeably in * some special cases */ verify((int)VIR_TRISTATE_BOOL_YES == (int)VIR_TRISTATE_SWITCH_ON); -- 2.14.1

Note when no blockjobs are running in the status XML so that we know that the backing chain will not change until we reconnect. --- src/qemu/qemu_domain.c | 38 ++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_domain.h | 3 +++ tests/qemuxml2xmltest.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index a8c718f62..6958ed736 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1759,6 +1759,8 @@ qemuDomainObjPrivateDataClear(qemuDomainObjPrivatePtr priv) /* clear previously used namespaces */ virBitmapFree(priv->namespaces); priv->namespaces = NULL; + + priv->reconnectBlockjobs = VIR_TRISTATE_BOOL_ABSENT; } @@ -1854,6 +1856,20 @@ qemuDomainObjPrivateXMLFormatAutomaticPlacement(virBufferPtr buf, } +static int +qemuDomainObjPrivateXMLFormatBlockjobs(virBufferPtr buf, + virDomainObjPtr vm) +{ + virBuffer attrBuf = VIR_BUFFER_INITIALIZER; + bool bj = qemuDomainHasBlockjob(vm, false); + + virBufferAsprintf(&attrBuf, " active='%s'", + virTristateBoolTypeToString(virTristateBoolFromBool(bj))); + + return virXMLFormatElement(buf, "blockjobs", &attrBuf, NULL); +} + + static int qemuDomainObjPrivateXMLFormat(virBufferPtr buf, virDomainObjPtr vm) @@ -1976,6 +1992,9 @@ qemuDomainObjPrivateXMLFormat(virBufferPtr buf, if (priv->chardevStdioLogd) virBufferAddLit(buf, "<chardevStdioLogd/>\n"); + if (qemuDomainObjPrivateXMLFormatBlockjobs(buf, vm) < 0) + return -1; + return 0; } @@ -2067,6 +2086,22 @@ qemuDomainObjPrivateXMLParseAutomaticPlacement(xmlXPathContextPtr ctxt, } +static int +qemuDomainObjPrivateXMLParseBlockjobs(qemuDomainObjPrivatePtr priv, + xmlXPathContextPtr ctxt) +{ + char *active; + int tmp; + + if ((active = virXPathString("string(./blockjobs/@active)", ctxt)) && + (tmp = virTristateBoolTypeFromString(active)) > 0) + priv->reconnectBlockjobs = tmp; + + VIR_FREE(active); + return 0; +} + + static int qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, virDomainObjPtr vm, @@ -2282,6 +2317,9 @@ qemuDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt, priv->chardevStdioLogd = virXPathBoolean("boolean(./chardevStdioLogd)", ctxt) == 1; + if (qemuDomainObjPrivateXMLParseBlockjobs(priv, ctxt) < 0) + goto error; + return 0; error: diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index f92841ceb..c34cd37fc 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -320,6 +320,9 @@ struct _qemuDomainObjPrivate { /* If true virtlogd is used as stdio handler for character devices. */ bool chardevStdioLogd; + + /* Tracks blockjob state for vm. Valid only while reconnecting to qemu. */ + virTristateBool reconnectBlockjobs; }; # define QEMU_DOMAIN_PRIVATE(vm) \ diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 7d7a5f1e4..14f5b58fe 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -34,6 +34,7 @@ struct testInfo { char *outInactiveName; virBitmapPtr activeVcpus; + bool blockjobs; virQEMUCapsPtr qemuCaps; }; @@ -43,11 +44,22 @@ qemuXML2XMLActivePreFormatCallback(virDomainDefPtr def, const void *opaque) { struct testInfo *info = (struct testInfo *) opaque; + size_t i; /* store vCPU bitmap so that the status XML can be created faithfully */ if (!info->activeVcpus) info->activeVcpus = virDomainDefGetOnlineVcpumap(def); + info->blockjobs = false; + + /* remember whether we have mirror jobs */ + for (i = 0; i < def->ndisks; i++) { + if (def->disks[i]->mirror) { + info->blockjobs = true; + break; + } + } + return 0; } @@ -124,6 +136,15 @@ testGetStatuXMLPrefixVcpus(virBufferPtr buf, } +static void +testGetStatusXMLAddBlockjobs(virBufferPtr buf, + const struct testInfo *data) +{ + virBufferAsprintf(buf, "<blockjobs active='%s'/>\n", + virTristateBoolTypeToString(virTristateBoolFromBool(data->blockjobs))); +} + + static char * testGetStatusXMLPrefix(const struct testInfo *data) { @@ -136,12 +157,31 @@ testGetStatusXMLPrefix(const struct testInfo *data) virBufferAddStr(&buf, testStatusXMLPrefixBodyStatic); + testGetStatusXMLAddBlockjobs(&buf, data); + virBufferAdjustIndent(&buf, -2); return virBufferContentAndReset(&buf); } +static int +testProcessStatusXML(virDomainObjPtr vm) +{ + size_t i; + + /* fix the private 'blockjob' flag for disks */ + for (i = 0; i < vm->def->ndisks; i++) { + virDomainDiskDefPtr disk = vm->def->disks[i]; + qemuDomainDiskPrivatePtr diskPriv = QEMU_DOMAIN_DISK_PRIVATE(disk); + + diskPriv->blockjob = !!disk->mirror; + } + + return 0; +} + + static int testCompareStatusXMLToXMLFiles(const void *opaque) { @@ -200,6 +240,10 @@ testCompareStatusXMLToXMLFiles(const void *opaque) goto cleanup; } + /* process the definition if necessary */ + if (testProcessStatusXML(obj) < 0) + goto cleanup; + /* format it back */ if (!(actual = virDomainObjFormat(driver.xmlopt, obj, NULL, VIR_DOMAIN_DEF_FORMAT_SECURE))) { -- 2.14.1

Add a helper variable so that we don't have to access the disk via 3 indirections. --- src/qemu/qemu_process.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index f29228bc1..4353ad5ec 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -6969,21 +6969,21 @@ qemuProcessReconnect(void *opaque) * qemu_driver->sharedDevices. */ for (i = 0; i < obj->def->ndisks; i++) { + virDomainDiskDefPtr disk = obj->def->disks[i]; virDomainDeviceDef dev; - if (virStorageTranslateDiskSourcePool(conn, obj->def->disks[i]) < 0) + if (virStorageTranslateDiskSourcePool(conn, disk) < 0) goto error; /* XXX we should be able to restore all data from XML in the future. * This should be the only place that calls qemuDomainDetermineDiskChain * with @report_broken == false to guarantee best-effort domain * reconnect */ - if (qemuDomainDetermineDiskChain(driver, obj, obj->def->disks[i], - true, false) < 0) + if (qemuDomainDetermineDiskChain(driver, obj, disk, true, false) < 0) goto error; dev.type = VIR_DOMAIN_DEVICE_DISK; - dev.data.disk = obj->def->disks[i]; + dev.data.disk = disk; if (qemuAddSharedDevice(driver, &dev, obj->def->name) < 0) goto error; } -- 2.14.1

Skip purging the backing chain and redetecting it when it was not going to change during the time we were not present. The decision is based on the new flag which records whether there were blockjobs running to the status XML. --- src/qemu/qemu_process.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 4353ad5ec..9f26dfccf 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -6975,12 +6975,16 @@ qemuProcessReconnect(void *opaque) if (virStorageTranslateDiskSourcePool(conn, disk) < 0) goto error; - /* XXX we should be able to restore all data from XML in the future. - * This should be the only place that calls qemuDomainDetermineDiskChain - * with @report_broken == false to guarantee best-effort domain - * reconnect */ - if (qemuDomainDetermineDiskChain(driver, obj, disk, true, false) < 0) - goto error; + /* backing chains need to be refreshed only if they could change */ + if (priv->reconnectBlockjobs != VIR_TRISTATE_BOOL_NO) { + /* This should be the only place that calls + * qemuDomainDetermineDiskChain with @report_broken == false + * to guarantee best-effort domain reconnect */ + if (qemuDomainDetermineDiskChain(driver, obj, disk, true, false) < 0) + goto error; + } else { + VIR_DEBUG("skipping backing chain detection for '%s'", disk->dst); + } dev.type = VIR_DOMAIN_DEVICE_DISK; dev.data.disk = disk; -- 2.14.1

On 10/05/2017 08:06 AM, Peter Krempa wrote:
V2:
Patches 1/4 and 3/4 are new. Patch 2/4 and 4/4 were fixed to use virTristateBool.
Peter Krempa (4): util: Add functions to simplify bool->virTristate(Bool|Switch) assignment qemu: domain: Mark if no blockjobs are active in the status XML qemu: process: Simplify acces to individual disk when reconnecting
^^ s/acces/access
qemu: process: Don't redetect backing chain on reconnect
src/libvirt_private.syms | 2 ++ src/qemu/qemu_domain.c | 38 ++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_domain.h | 3 +++ src/qemu/qemu_process.c | 22 +++++++++++++--------- src/util/virutil.c | 20 ++++++++++++++++++++ src/util/virutil.h | 3 +++ tests/qemuxml2xmltest.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 123 insertions(+), 9 deletions(-)
Reviewed-by: John Ferlan <jferlan@redhat.com> (series) John
participants (2)
-
John Ferlan
-
Peter Krempa