From b3f8ad07ddb779542e7a6b2d19b3a1eaf272e0d3 Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Tue, 19 Mar 2019 07:54:12 +0100 Subject: [PATCH] qemu: blockjob: Track orphaned backing chains in blockjob status XML MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When the guest unplugs the disk frontend libvirt is responsible for deleting the backend. Since a blockjob may still have a reference to the backing chain when it is running we'll have to store the metadata for the unplugged disk for future reference. This patch adds 'chain' and 'mirrorChain' fields to 'qemuBlockJobData' to keep them around with the job along with status XML machinery and tests. Later patches will then add code to change the ownership of the chain when unplugging the disk backend. Signed-off-by: Peter Krempa Reviewed-by: Ján Tomko --- src/qemu/qemu_blockjob.c | 5 + src/qemu/qemu_blockjob.h | 2 + src/qemu/qemu_domain.c | 124 ++++++++++++++++-- .../blockjob-blockdev-in.xml | 37 ++++++ 4 files changed, 160 insertions(+), 8 deletions(-) diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index 722074bb8d..d55eb48605 100644 --- a/src/qemu/qemu_blockjob.c +++ b/src/qemu/qemu_blockjob.c @@ -72,6 +72,9 @@ qemuBlockJobDataDispose(void *obj) { qemuBlockJobDataPtr job = obj; + virObjectUnref(job->chain); + virObjectUnref(job->mirrorChain); + VIR_FREE(job->name); VIR_FREE(job->errmsg); } @@ -127,6 +130,8 @@ qemuBlockJobRegister(qemuBlockJobDataPtr job, if (disk) { job->disk = disk; + job->chain = virObjectRef(disk->src); + job->mirrorChain = virObjectRef(disk->mirror); QEMU_DOMAIN_DISK_PRIVATE(disk)->blockjob = virObjectRef(job); } diff --git a/src/qemu/qemu_blockjob.h b/src/qemu/qemu_blockjob.h index 2d8ecdd4c3..d07ab75c8b 100644 --- a/src/qemu/qemu_blockjob.h +++ b/src/qemu/qemu_blockjob.h @@ -75,6 +75,8 @@ struct _qemuBlockJobData { char *name; virDomainDiskDefPtr disk; /* may be NULL, if blockjob does not correspond to any disk */ + virStorageSourcePtr chain; /* Reference to the chain the job operates on. */ + virStorageSourcePtr mirrorChain; /* reference to 'mirror' part of the job */ int type; /* qemuBlockJobType */ int state; /* qemuBlockjobState */ diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 1a0e6aac6e..fc8deb7084 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2306,22 +2306,59 @@ qemuDomainObjPrivateXMLFormatAutomaticPlacement(virBufferPtr buf, } +typedef struct qemuDomainPrivateBlockJobFormatData { + virDomainXMLOptionPtr xmlopt; + virBufferPtr buf; +} qemuDomainPrivateBlockJobFormatData; + + +static int +qemuDomainObjPrivateXMLFormatBlockjobFormatChain(virBufferPtr buf, + const char *chainname, + virStorageSourcePtr src, + virDomainXMLOptionPtr xmlopt) +{ + VIR_AUTOCLEAN(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER; + VIR_AUTOCLEAN(virBuffer) childBuf = VIR_BUFFER_INITIALIZER; + unsigned int xmlflags = VIR_DOMAIN_DEF_FORMAT_STATUS; + + virBufferSetChildIndent(&childBuf, buf); + + virBufferAsprintf(&attrBuf, " type='%s' format='%s'", + virStorageTypeToString(src->type), + virStorageFileFormatTypeToString(src->format)); + + if (virDomainDiskSourceFormat(&childBuf, src, "source", 0, true, xmlflags, xmlopt) < 0) + return -1; + + if (virDomainDiskBackingStoreFormat(&childBuf, src, xmlopt, xmlflags) < 0) + return -1; + + if (virXMLFormatElement(buf, chainname, &attrBuf, &childBuf) < 0) + return -1; + + return 0; +} + + static int qemuDomainObjPrivateXMLFormatBlockjobIterator(void *payload, const void *name ATTRIBUTE_UNUSED, - void *data) + void *opaque) { VIR_AUTOCLEAN(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER; VIR_AUTOCLEAN(virBuffer) childBuf = VIR_BUFFER_INITIALIZER; + VIR_AUTOCLEAN(virBuffer) chainsBuf = VIR_BUFFER_INITIALIZER; qemuBlockJobDataPtr job = payload; - virBufferPtr buf = data; const char *state = qemuBlockjobStateTypeToString(job->state); const char *newstate = NULL; + struct qemuDomainPrivateBlockJobFormatData *data = opaque; if (job->newstate != -1) newstate = qemuBlockjobStateTypeToString(job->newstate); - virBufferSetChildIndent(&childBuf, buf); + virBufferSetChildIndent(&childBuf, data->buf); + virBufferSetChildIndent(&chainsBuf, &childBuf); virBufferEscapeString(&attrBuf, " name='%s'", job->name); virBufferEscapeString(&attrBuf, " type='%s'", qemuBlockjobTypeToString(job->type)); @@ -2329,10 +2366,28 @@ qemuDomainObjPrivateXMLFormatBlockjobIterator(void *payload, virBufferEscapeString(&attrBuf, " newstate='%s'", newstate); virBufferEscapeString(&childBuf, "%s", job->errmsg); - if (job->disk) + if (job->disk) { virBufferEscapeString(&childBuf, "\n", job->disk->dst); + } else { + if (job->chain && + qemuDomainObjPrivateXMLFormatBlockjobFormatChain(&chainsBuf, + "disk", + job->chain, + data->xmlopt) < 0) + return -1; + + if (job->mirrorChain && + qemuDomainObjPrivateXMLFormatBlockjobFormatChain(&chainsBuf, + "mirror", + job->mirrorChain, + data->xmlopt) < 0) + return -1; + + if (virXMLFormatElement(&childBuf, "chains", NULL, &chainsBuf) < 0) + return -1; + } - return virXMLFormatElement(buf, "blockjob", &attrBuf, &childBuf); + return virXMLFormatElement(data->buf, "blockjob", &attrBuf, &childBuf); } @@ -2344,6 +2399,8 @@ qemuDomainObjPrivateXMLFormatBlockjobs(virBufferPtr buf, VIR_AUTOCLEAN(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER; VIR_AUTOCLEAN(virBuffer) childBuf = VIR_BUFFER_INITIALIZER; bool bj = qemuDomainHasBlockjob(vm, false); + struct qemuDomainPrivateBlockJobFormatData iterdata = { priv->driver->xmlopt, + &childBuf }; virBufferAsprintf(&attrBuf, " active='%s'", virTristateBoolTypeToString(virTristateBoolFromBool(bj))); @@ -2353,7 +2410,7 @@ qemuDomainObjPrivateXMLFormatBlockjobs(virBufferPtr buf, if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV) && virHashForEach(priv->blockjobs, qemuDomainObjPrivateXMLFormatBlockjobIterator, - &childBuf) < 0) + &iterdata) < 0) return -1; return virXMLFormatElement(buf, "blockjobs", &attrBuf, &childBuf); @@ -2695,10 +2752,49 @@ qemuDomainObjPrivateXMLParseAutomaticPlacement(xmlXPathContextPtr ctxt, } +static virStorageSourcePtr +qemuDomainObjPrivateXMLParseBlockjobChain(xmlNodePtr node, + xmlXPathContextPtr ctxt, + virDomainXMLOptionPtr xmlopt) + +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt); + VIR_AUTOFREE(char *) format = NULL; + VIR_AUTOFREE(char *) type = NULL; + VIR_AUTOFREE(char *) index = NULL; + VIR_AUTOUNREF(virStorageSourcePtr) src = NULL; + xmlNodePtr sourceNode; + unsigned int xmlflags = VIR_DOMAIN_DEF_PARSE_STATUS; + + ctxt->node = node; + + if (!(type = virXMLPropString(ctxt->node, "type")) || + !(format = virXMLPropString(ctxt->node, "format")) || + !(index = virXPathString("string(./source/@index)", ctxt)) || + !(sourceNode = virXPathNode("./source", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing job chain data")); + return NULL; + } + + if (!(src = virDomainStorageSourceParseBase(type, format, index))) + return NULL; + + if (virDomainStorageSourceParse(sourceNode, ctxt, src, xmlflags, xmlopt) < 0) + return NULL; + + if (virDomainDiskBackingStoreParse(ctxt, src, xmlflags, xmlopt) < 0) + return NULL; + + VIR_RETURN_PTR(src); +} + + static int qemuDomainObjPrivateXMLParseBlockjobData(virDomainObjPtr vm, xmlNodePtr node, - xmlXPathContextPtr ctxt) + xmlXPathContextPtr ctxt, + virDomainXMLOptionPtr xmlopt) { VIR_XPATH_NODE_AUTORESTORE(ctxt); virDomainDiskDefPtr disk = NULL; @@ -2712,6 +2808,7 @@ qemuDomainObjPrivateXMLParseBlockjobData(virDomainObjPtr vm, VIR_AUTOFREE(char *) newstatestr = NULL; int newstate = -1; bool invalidData = false; + xmlNodePtr tmp; ctxt->node = node; @@ -2743,6 +2840,16 @@ qemuDomainObjPrivateXMLParseBlockjobData(virDomainObjPtr vm, !(disk = virDomainDiskByName(vm->def, diskdst, false))) invalidData = true; + if (!disk && !invalidData) { + if ((tmp = virXPathNode("./chains/disk", ctxt)) && + !(job->chain = qemuDomainObjPrivateXMLParseBlockjobChain(tmp, ctxt, xmlopt))) + invalidData = true; + + if ((tmp = virXPathNode("./chains/mirror", ctxt)) && + !(job->mirrorChain = qemuDomainObjPrivateXMLParseBlockjobChain(tmp, ctxt, xmlopt))) + invalidData = true; + } + job->state = state; job->newstate = newstate; job->errmsg = virXPathString("string(./errmsg)", ctxt); @@ -2775,7 +2882,8 @@ qemuDomainObjPrivateXMLParseBlockjobs(virDomainObjPtr vm, return -1; for (i = 0; i < nnodes; i++) { - if (qemuDomainObjPrivateXMLParseBlockjobData(vm, nodes[i], ctxt) < 0) + if (qemuDomainObjPrivateXMLParseBlockjobData(vm, nodes[i], ctxt, + priv->driver->xmlopt) < 0) return -1; } } diff --git a/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml b/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml index dce9f44466..43fe02137b 100644 --- a/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml +++ b/tests/qemustatusxml2xmldata/blockjob-blockdev-in.xml @@ -237,6 +237,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + copy -- 2.47.2