qemu: checkpoint: Implement VIR_DOMAIN_CHECKPOINT_XML_SIZE

Introduce code which merges the appropriate bitmaps and queries the
final size of the backup, so that we can print the XML with size
information.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Peter Krempa 2020-07-01 16:58:37 +02:00
parent a94997c476
commit b9c24236fa

View File

@ -567,6 +567,142 @@ qemuCheckpointCreateXML(virDomainPtr domain,
}
struct qemuCheckpointDiskMap {
virDomainCheckpointDiskDefPtr chkdisk;
virDomainDiskDefPtr domdisk;
};
static int
qemuCheckpointGetXMLDescUpdateSize(virDomainObjPtr vm,
virDomainCheckpointDefPtr chkdef)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
virQEMUDriverPtr driver = priv->driver;
g_autoptr(virHashTable) blockNamedNodeData = NULL;
g_autofree struct qemuCheckpointDiskMap *diskmap = NULL;
g_autoptr(virJSONValue) recoveractions = NULL;
g_autoptr(virJSONValue) mergeactions = virJSONValueNewArray();
g_autoptr(virJSONValue) cleanupactions = virJSONValueNewArray();
int rc = 0;
size_t ndisks = 0;
size_t i;
int ret = -1;
if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
return -1;
if (virDomainObjCheckActive(vm) < 0)
goto endjob;
if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
goto endjob;
/* enumerate disks relevant for the checkpoint which are also present in the
* domain */
diskmap = g_new0(struct qemuCheckpointDiskMap, chkdef->ndisks);
for (i = 0; i < chkdef->ndisks; i++) {
virDomainCheckpointDiskDefPtr chkdisk = chkdef->disks + i;
virDomainDiskDefPtr domdisk;
chkdisk->size = 0;
chkdisk->sizeValid = false;
if (chkdisk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
continue;
if (!(domdisk = virDomainDiskByTarget(vm->def, chkdisk->name)))
continue;
if (!qemuBlockBitmapChainIsValid(domdisk->src, chkdef->parent.name, blockNamedNodeData))
continue;
diskmap[ndisks].chkdisk = chkdisk;
diskmap[ndisks].domdisk = domdisk;
ndisks++;
}
if (ndisks == 0) {
ret = 0;
goto endjob;
}
/* we need to calculate the merged bitmap to obtain accurate data */
for (i = 0; i < ndisks; i++) {
virDomainDiskDefPtr domdisk = diskmap[i].domdisk;
g_autoptr(virJSONValue) actions = NULL;
/* possibly delete leftovers from previous cases */
if (qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData, domdisk->src,
"libvirt-tmp-size-xml")) {
if (!recoveractions)
recoveractions = virJSONValueNewArray();
if (qemuMonitorTransactionBitmapRemove(recoveractions,
domdisk->src->nodeformat,
"libvirt-tmp-size-xml") < 0)
goto endjob;
}
if (qemuBlockGetBitmapMergeActions(domdisk->src, NULL, domdisk->src,
chkdef->parent.name, "libvirt-tmp-size-xml",
NULL, &actions, blockNamedNodeData) < 0)
goto endjob;
if (virJSONValueArrayConcat(mergeactions, actions) < 0)
goto endjob;
if (qemuMonitorTransactionBitmapRemove(cleanupactions,
domdisk->src->nodeformat,
"libvirt-tmp-size-xml") < 0)
goto endjob;
}
qemuDomainObjEnterMonitor(driver, vm);
if (rc == 0 && recoveractions)
rc = qemuMonitorTransaction(priv->mon, &recoveractions);
if (rc == 0)
rc = qemuMonitorTransaction(priv->mon, &mergeactions);
if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
goto endjob;
/* now do a final refresh */
virHashFree(blockNamedNodeData);
if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
goto endjob;
qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorTransaction(priv->mon, &cleanupactions);
if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
goto endjob;
/* update disks */
for (i = 0; i < ndisks; i++) {
virDomainCheckpointDiskDefPtr chkdisk = diskmap[i].chkdisk;
virDomainDiskDefPtr domdisk = diskmap[i].domdisk;
qemuBlockNamedNodeDataBitmapPtr bitmap;
if ((bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData, domdisk->src,
"libvirt-tmp-size-xml"))) {
chkdisk->size = bitmap->dirtybytes;
chkdisk->sizeValid = true;
}
}
ret = 0;
endjob:
qemuDomainObjEndJob(driver, vm);
return ret;
}
char *
qemuCheckpointGetXMLDesc(virDomainObjPtr vm,
virDomainCheckpointPtr checkpoint,
@ -579,13 +715,18 @@ qemuCheckpointGetXMLDesc(virDomainObjPtr vm,
unsigned int format_flags;
virCheckFlags(VIR_DOMAIN_CHECKPOINT_XML_SECURE |
VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN, NULL);
VIR_DOMAIN_CHECKPOINT_XML_NO_DOMAIN |
VIR_DOMAIN_CHECKPOINT_XML_SIZE, NULL);
if (!(chk = qemuCheckpointObjFromCheckpoint(vm, checkpoint)))
return NULL;
chkdef = virDomainCheckpointObjGetDef(chk);
if (flags & VIR_DOMAIN_CHECKPOINT_XML_SIZE &&
qemuCheckpointGetXMLDescUpdateSize(vm, chkdef) < 0)
return NULL;
format_flags = virDomainCheckpointFormatConvertXMLFlags(flags);
return virDomainCheckpointDefFormat(chkdef, driver->xmlopt,
format_flags);