[PATCH 18/24] qemu: checkpoint: Implement VIR_DOMAIN_CHECKPOINT_XML_SIZE

Peter Krempa pkrempa at redhat.com
Thu Jul 2 14:40:04 UTC 2020


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 at redhat.com>
---
 src/qemu/qemu_checkpoint.c | 143 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 142 insertions(+), 1 deletion(-)

diff --git a/src/qemu/qemu_checkpoint.c b/src/qemu/qemu_checkpoint.c
index c24d97443c..f45ab29d4c 100644
--- a/src/qemu/qemu_checkpoint.c
+++ b/src/qemu/qemu_checkpoint.c
@@ -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);
-- 
2.26.2




More information about the libvir-list mailing list