[RFC PATCH 32/41] qemu: block: Add universal helper for merging dirty bitmaps for all scenarios

Peter Krempa pkrempa at redhat.com
Tue Jun 9 15:00:39 UTC 2020


Add a function which allows to merge bitmaps according to the new
semantics and will allow to replace all the specific ad-hoc functions
currently in use for 'backup', 'block commit', 'block copy' and will
also be usable in the future for 'block pull' and non-shared storage
migration.

The semantics are a bit quirky for the 'backup' case but these quirks
are documented and will prevent us from having two slightly different
algorithms.

Signed-off-by: Peter Krempa <pkrempa at redhat.com>
---
 src/qemu/qemu_block.c | 151 ++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_block.h |  11 +++
 2 files changed, 162 insertions(+)

diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
index 69578e861c..6eab9cb4e2 100644
--- a/src/qemu/qemu_block.c
+++ b/src/qemu/qemu_block.c
@@ -2847,6 +2847,157 @@ qemuBlockGetNamedNodeData(virDomainObjPtr vm,
 }


+/**
+ * qemuBlockGetBitmapMergeActions:
+ * @topsrc: top of the chain to merge bitmaps in
+ * @basesrc: bottom of the chain to merge bitmaps in (NULL for full chain)
+ * @target: destination storage source of the merge (may be part of original chain)
+ * @bitmapname: name of bitmap to perform the merge (NULL for all bitmaps)
+ * @dstbitmapname: name of destination bitmap of the merge (see below for caveats)
+ * @writebitmapsrc: storage source corresponding to the node containing the write temporary bitmap
+ * @actions: returns actions for a 'transaction' QMP command for executing the merge
+ * @allocationbitmapnodes: list of storage sources which will require an allocation bitmap
+ * @blockNamedNodeData: hash table filled with qemuBlockNamedNodeData
+ *
+ * Calculate handling of dirty block bitmaps between @topsrc and @basesrc. If
+ * @basesrc is NULL the end of the chain is considered. @target is the destination
+ * storage source definition of the merge and may or may not be part of the
+ * merged chain.
+ *
+ * Specifically the merging algorithm ensures that each considered bitmap is
+ * merged with the appropriate allocation bitmaps so that it properly describes
+ * the state of dirty blocks when looked at from @topsrc based on the depth
+ * of the backing chain where the bitmap is placed.
+ *
+ * If @bitmapname is non-NULL only bitmaps with that name are handled, otherwise
+ * all bitmaps are considered.
+ *
+ * If @dstbitmap is non-NULL everything is merged into a bitmap with that name,
+ * otherwise each bitmap is merged into a bitmap with the same name into @target.
+ * Additionally if @dstbitmap is non-NULL the target bitmap is created as 'inactive'
+ * and 'transient' as a special case for the backup operation.
+ *
+ * If @writebitmapsrc is non-NULL, the 'libvirt-tmp-activewrite' bitmap from
+ * given node is merged along with others. This bitmap corresponds to the writes
+ * which occured between an active layer job finished and the rest of the bitmap
+ * merging.
+ *
+ * If the bitmap is not valid somehow (see qemuBlockBitmapChainIsValid) given
+ * bitmap is silently skipped, so callers must ensure that given bitmap is valid
+ * if they care about it.
+ *
+ * The resulting 'transacion' QMP command actions are filled in and returned via
+ * @actions. In cases when the merging requires use of bitmap created from the
+ * allocation map of certain parts of the chain the @allocationbitmapnodes list
+ * is filled with pointers to the virStorageSource structure of the backing
+ * chain members where the allocation bitmap must be added prior to the merge.
+ *
+ * Note that @actions and @allocationbitmapnodes may be NULL if no merging is
+ * required.
+ */
+int
+qemuBlockGetBitmapMergeActions(virStorageSourcePtr topsrc,
+                               virStorageSourcePtr basesrc,
+                               virStorageSourcePtr target,
+                               const char *bitmapname,
+                               const char *dstbitmapname,
+                               virStorageSourcePtr writebitmapsrc,
+                               virJSONValuePtr *actions,
+                               GSList **allocationbitmapnodes,
+                               virHashTablePtr blockNamedNodeData)
+{
+    g_autoptr(virJSONValue) act = virJSONValueNewArray();
+    virStorageSourcePtr n;
+    qemuBlockNamedNodeDataPtr entry;
+    g_autoptr(virJSONValue) tmpbitmaps = virJSONValueNewArray();
+    g_autoptr(GSList) tmpbitmapnodes = NULL;
+    g_autoptr(GSList) tmpbitmapnodesused = NULL;
+    size_t i;
+
+    for (n = topsrc; virStorageSourceIsBacking(n) && n != basesrc; n = n->backingStore) {
+        bool copytmpbitmapnodes = false;
+
+        if (!(entry = virHashLookup(blockNamedNodeData, n->nodeformat)))
+            continue;
+
+        for (i = 0; i < entry->nbitmaps; i++) {
+            qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
+            g_autoptr(virJSONValue) merge = NULL;
+            const char *mergebitmapname = dstbitmapname;
+            bool mergebitmappersistent = false;
+            bool mergebitmapdisabled = true;
+
+            if (bitmapname &&
+                STRNEQ(bitmapname, bitmap->name))
+                continue;
+
+            if (!qemuBlockBitmapChainIsValid(topsrc, bitmap->name, blockNamedNodeData))
+                continue;
+
+            /* explicitly named destinations mean that we want a temporary
+             * disabled bitmap only, so undo the default for non-explicit cases  */
+            if (!mergebitmapname) {
+                mergebitmapname = bitmap->name;
+                mergebitmappersistent = true;
+                mergebitmapdisabled = false;
+            }
+
+            if (qemuMonitorTransactionBitmapAdd(act, target->nodeformat,
+                                                mergebitmapname,
+                                                mergebitmappersistent,
+                                                mergebitmapdisabled,
+                                                bitmap->granularity) < 0)
+                return -1;
+
+            if (!(merge = virJSONValueCopy(tmpbitmaps)))
+                return -1;
+
+            copytmpbitmapnodes = true;
+
+            if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(merge,
+                                                                 n->nodeformat,
+                                                                 bitmap->name) < 0)
+                return -1;
+
+            if (writebitmapsrc &&
+                qemuMonitorTransactionBitmapMergeSourceAddBitmap(merge,
+                                                                 writebitmapsrc->nodeformat,
+                                                                 "libvirt-tmp-activewrite") < 0)
+                return -1;
+
+            if (qemuMonitorTransactionBitmapMerge(act, target->nodeformat,
+                                                  mergebitmapname, &merge) < 0)
+                return -1;
+        }
+
+        if (copytmpbitmapnodes && tmpbitmapnodes) {
+            g_slist_free(tmpbitmapnodesused);
+            tmpbitmapnodesused = g_slist_copy(tmpbitmapnodes);
+        }
+
+        tmpbitmapnodes = g_slist_prepend(tmpbitmapnodes, n);
+
+        if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(tmpbitmaps,
+                                                             n->nodeformat,
+                                                             "libvirt-tmp-allocation") < 0)
+            return -1;
+    }
+
+    if (virJSONValueArraySize(act) > 0) {
+        if (writebitmapsrc &&
+            qemuMonitorTransactionBitmapRemove(act, writebitmapsrc->nodeformat,
+                                               "libvirt-tmp-activewrite") < 0)
+            return -1;
+
+        *actions = g_steal_pointer(&act);
+    }
+
+    *allocationbitmapnodes = g_steal_pointer(&tmpbitmapnodesused);
+
+    return 0;
+}
+
+
 /**
  * qemuBlockBitmapChainIsValid:
  *
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
index ccd6f57440..6bec1e2e29 100644
--- a/src/qemu/qemu_block.h
+++ b/src/qemu/qemu_block.h
@@ -221,6 +221,17 @@ virHashTablePtr
 qemuBlockGetNamedNodeData(virDomainObjPtr vm,
                           qemuDomainAsyncJob asyncJob);

+int
+qemuBlockGetBitmapMergeActions(virStorageSourcePtr topsrc,
+                               virStorageSourcePtr basesrc,
+                               virStorageSourcePtr target,
+                               const char *bitmapname,
+                               const char *dstbitmapname,
+                               virStorageSourcePtr writebitmapsrc,
+                               virJSONValuePtr *actions,
+                               GSList **allocationbitmapnodes,
+                               virHashTablePtr blockNamedNodeData);
+
 bool
 qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
                             const char *bitmapname,
-- 
2.26.2




More information about the libvir-list mailing list