提交 b3f8ad07 编写于 作者: P Peter Krempa

qemu: blockjob: Track orphaned backing chains in blockjob status XML

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: NPeter Krempa <pkrempa@redhat.com>
Reviewed-by: NJán Tomko <jtomko@redhat.com>
上级 7a264536
......@@ -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);
}
......
......@@ -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 */
......
......@@ -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, "<errmsg>%s</errmsg>", job->errmsg);
if (job->disk)
if (job->disk) {
virBufferEscapeString(&childBuf, "<disk dst='%s'/>\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;
}
}
......
......@@ -237,6 +237,43 @@
<blockjob name='drive-virtio-disk0' type='copy' state='ready'>
<disk dst='vda'/>
</blockjob>
<blockjob name='test-orphan-job0' type='copy' state='ready'>
<chains>
<disk type='file' format='qcow2'>
<source file='/orphan/source/top.qcow2' index='123'>
<privateData>
<nodenames>
<nodename type='storage' name='orphan-source-top-storage'/>
<nodename type='format' name='orphan-source-top-format'/>
</nodenames>
</privateData>
</source>
<backingStore type='file' index='321'>
<format type='qcow2'/>
<source file='/orphan/source/base.qcow2'>
<privateData>
<nodenames>
<nodename type='storage' name='orphan-source-base-storage'/>
<nodename type='format' name='orphan-source-base-format'/>
</nodenames>
</privateData>
</source>
<backingStore/>
</backingStore>
</disk>
<mirror type='file' format='raw'>
<source file='/orphan/mirror/raw' index='42'>
<privateData>
<nodenames>
<nodename type='storage' name='orphan-mirror-raw-storage'/>
<nodename type='format' name='orphan-mirror-raw-format'/>
</nodenames>
</privateData>
</source>
<backingStore/>
</mirror>
</chains>
</blockjob>
</blockjobs>
<domain type='kvm' id='4'>
<name>copy</name>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册