Blame SOURCES/libvirt-qemu-block-Implement-helpers-for-dealing-with-bitmaps-during-block-commit.patch

a41c76
From 3e71c9c766a0452e0bae3b4593f3cba3d1caec60 Mon Sep 17 00:00:00 2001
a41c76
Message-Id: <3e71c9c766a0452e0bae3b4593f3cba3d1caec60@dist-git>
a41c76
From: Peter Krempa <pkrempa@redhat.com>
a41c76
Date: Mon, 16 Mar 2020 22:12:24 +0100
a41c76
Subject: [PATCH] qemu: block: Implement helpers for dealing with bitmaps
a41c76
 during block commit
a41c76
MIME-Version: 1.0
a41c76
Content-Type: text/plain; charset=UTF-8
a41c76
Content-Transfer-Encoding: 8bit
a41c76
a41c76
qemuBlockBitmapsHandleCommitStart prepares for disabling the bitmaps in
a41c76
the 'base' of the commit job so that the bitmaps are not dirtied by the
a41c76
commit job. This needs to be done prior to start of the commit job.
a41c76
a41c76
qemuBlockBitmapsHandleCommitFinish then calculates the necessary merges
a41c76
that agregate all the bitmaps between the commited images and write them
a41c76
into the base bitmap.
a41c76
a41c76
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
a41c76
Reviewed-by: Eric Blake <eblake@redhat.com>
a41c76
(cherry picked from commit 1753f605506e28eb42bc5bb6fa9abe8fcbe6fb9b)
a41c76
https://bugzilla.redhat.com/show_bug.cgi?id=1799013
a41c76
Message-Id: <c0624f94e802043ca10819aaaa9111ae230cfb7f.1584391727.git.pkrempa@redhat.com>
a41c76
Reviewed-by: Ján Tomko <jtomko@redhat.com>
a41c76
---
a41c76
 src/qemu/qemu_block.c | 219 ++++++++++++++++++++++++++++++++++++++++++
a41c76
 src/qemu/qemu_block.h |  14 +++
a41c76
 2 files changed, 233 insertions(+)
a41c76
a41c76
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
a41c76
index b4da323610..21c1ad9618 100644
a41c76
--- a/src/qemu/qemu_block.c
a41c76
+++ b/src/qemu/qemu_block.c
a41c76
@@ -2988,6 +2988,225 @@ qemuBlockBitmapsHandleBlockcopy(virStorageSourcePtr src,
a41c76
 }
a41c76
 
a41c76
 
a41c76
+/**
a41c76
+ * @topsrc: virStorageSource representing 'top' of the job
a41c76
+ * @basesrc: virStorageSource representing 'base' of the job
a41c76
+ * @blockNamedNodeData: hash table containing data about bitmaps
a41c76
+ * @actions: filled with arguments for a 'transaction' command
a41c76
+ * @disabledBitmapsBase: filled with a list of bitmap names which must be disabled
a41c76
+ *
a41c76
+ * Prepares data for correctly handling bitmaps during the start of a commit
a41c76
+ * job. The bitmaps in the 'base' image must be disabled, so that the writes
a41c76
+ * done by the blockjob don't dirty the enabled bitmaps.
a41c76
+ *
a41c76
+ * @actions and @disabledBitmapsBase are untouched if no bitmaps need
a41c76
+ * to be disabled.
a41c76
+ */
a41c76
+int
a41c76
+qemuBlockBitmapsHandleCommitStart(virStorageSourcePtr topsrc,
a41c76
+                                  virStorageSourcePtr basesrc,
a41c76
+                                  virHashTablePtr blockNamedNodeData,
a41c76
+                                  virJSONValuePtr *actions,
a41c76
+                                  char ***disabledBitmapsBase)
a41c76
+{
a41c76
+    g_autoptr(virJSONValue) act = virJSONValueNewArray();
a41c76
+    VIR_AUTOSTRINGLIST bitmaplist = NULL;
a41c76
+    size_t curbitmapstr = 0;
a41c76
+    qemuBlockNamedNodeDataPtr entry;
a41c76
+    bool disable_bitmaps = false;
a41c76
+    size_t i;
a41c76
+
a41c76
+    if (!(entry = virHashLookup(blockNamedNodeData, basesrc->nodeformat)))
a41c76
+        return 0;
a41c76
+
a41c76
+    bitmaplist = g_new0(char *, entry->nbitmaps);
a41c76
+
a41c76
+    for (i = 0; i < entry->nbitmaps; i++) {
a41c76
+        qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
a41c76
+
a41c76
+        if (!bitmap->recording || bitmap->inconsistent ||
a41c76
+            !qemuBlockBitmapChainIsValid(topsrc, bitmap->name, blockNamedNodeData))
a41c76
+            continue;
a41c76
+
a41c76
+        disable_bitmaps = true;
a41c76
+
a41c76
+        if (qemuMonitorTransactionBitmapDisable(act, basesrc->nodeformat,
a41c76
+                                                bitmap->name) < 0)
a41c76
+            return -1;
a41c76
+
a41c76
+        bitmaplist[curbitmapstr++] = g_strdup(bitmap->name);
a41c76
+    }
a41c76
+
a41c76
+    if (disable_bitmaps) {
a41c76
+        *actions = g_steal_pointer(&act;;
a41c76
+        *disabledBitmapsBase = g_steal_pointer(&bitmaplist);
a41c76
+    }
a41c76
+
a41c76
+    return 0;
a41c76
+}
a41c76
+
a41c76
+
a41c76
+struct qemuBlockBitmapsHandleCommitData {
a41c76
+    bool skip;
a41c76
+    bool create;
a41c76
+    bool enable;
a41c76
+    const char *basenode;
a41c76
+    virJSONValuePtr merge;
a41c76
+    unsigned long long granularity;
a41c76
+    bool persistent;
a41c76
+};
a41c76
+
a41c76
+
a41c76
+static void
a41c76
+qemuBlockBitmapsHandleCommitDataFree(void *opaque)
a41c76
+{
a41c76
+    struct qemuBlockBitmapsHandleCommitData *data = opaque;
a41c76
+
a41c76
+    virJSONValueFree(data->merge);
a41c76
+    g_free(data);
a41c76
+}
a41c76
+
a41c76
+
a41c76
+static int
a41c76
+qemuBlockBitmapsHandleCommitFinishIterate(void *payload,
a41c76
+                                          const void *entryname,
a41c76
+                                          void *opaque)
a41c76
+{
a41c76
+    struct qemuBlockBitmapsHandleCommitData *data = payload;
a41c76
+    const char *bitmapname = entryname;
a41c76
+    virJSONValuePtr actions = opaque;
a41c76
+
a41c76
+    if (data->skip)
a41c76
+        return 0;
a41c76
+
a41c76
+    if (data->create) {
a41c76
+        if (qemuMonitorTransactionBitmapAdd(actions, data->basenode, bitmapname,
a41c76
+                                            data->persistent, !data->enable,
a41c76
+                                            data->granularity) < 0)
a41c76
+            return -1;
a41c76
+    } else {
a41c76
+        if (data->enable &&
a41c76
+            qemuMonitorTransactionBitmapEnable(actions, data->basenode, bitmapname) < 0)
a41c76
+            return -1;
a41c76
+    }
a41c76
+
a41c76
+    if (data->merge &&
a41c76
+        qemuMonitorTransactionBitmapMerge(actions, data->basenode, bitmapname,
a41c76
+                                          &data->merge) < 0)
a41c76
+        return -1;
a41c76
+
a41c76
+    return 0;
a41c76
+}
a41c76
+
a41c76
+
a41c76
+/**
a41c76
+ * @topsrc: virStorageSource representing 'top' of the job
a41c76
+ * @basesrc: virStorageSource representing 'base' of the job
a41c76
+ * @blockNamedNodeData: hash table containing data about bitmaps
a41c76
+ * @actions: filled with arguments for a 'transaction' command
a41c76
+ * @disabledBitmapsBase: bitmap names which were disabled
a41c76
+ *
a41c76
+ * Calculates the necessary bitmap merges/additions/enablements to properly
a41c76
+ * handle commit of images from 'top' into 'base'. The necessary operations
a41c76
+ * in the form of arguments of the 'transaction' command are filled into
a41c76
+ * 'actions' if there is anything to do. Otherwise NULL is returned.
a41c76
+ */
a41c76
+int
a41c76
+qemuBlockBitmapsHandleCommitFinish(virStorageSourcePtr topsrc,
a41c76
+                                   virStorageSourcePtr basesrc,
a41c76
+                                   virHashTablePtr blockNamedNodeData,
a41c76
+                                   virJSONValuePtr *actions,
a41c76
+                                   char **disabledBitmapsBase)
a41c76
+{
a41c76
+    g_autoptr(virJSONValue) act = virJSONValueNewArray();
a41c76
+    virStorageSourcePtr n;
a41c76
+    qemuBlockNamedNodeDataPtr entry;
a41c76
+    g_autoptr(virHashTable) commitdata = NULL;
a41c76
+    struct qemuBlockBitmapsHandleCommitData *bitmapdata;
a41c76
+    size_t i;
a41c76
+
a41c76
+    commitdata = virHashNew(qemuBlockBitmapsHandleCommitDataFree);
a41c76
+
a41c76
+    for (n = topsrc; n != basesrc; n = n->backingStore) {
a41c76
+        if (!(entry = virHashLookup(blockNamedNodeData, n->nodeformat)))
a41c76
+            continue;
a41c76
+
a41c76
+        for (i = 0; i < entry->nbitmaps; i++) {
a41c76
+            qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
a41c76
+
a41c76
+            if (!(bitmapdata = virHashLookup(commitdata, bitmap->name))) {
a41c76
+                bitmapdata = g_new0(struct qemuBlockBitmapsHandleCommitData, 1);
a41c76
+
a41c76
+                /* we must mirror the state of the topmost bitmap and merge
a41c76
+                 * everything else */
a41c76
+                bitmapdata->create = true;
a41c76
+                bitmapdata->enable = bitmap->recording;
a41c76
+                bitmapdata->basenode = basesrc->nodeformat;
a41c76
+                bitmapdata->merge = virJSONValueNewArray();
a41c76
+                bitmapdata->granularity = bitmap->granularity;
a41c76
+                bitmapdata->persistent = bitmap->persistent;
a41c76
+
a41c76
+                if (virHashAddEntry(commitdata, bitmap->name, bitmapdata) < 0) {
a41c76
+                    qemuBlockBitmapsHandleCommitDataFree(bitmapdata);
a41c76
+                    return -1;
a41c76
+                }
a41c76
+            }
a41c76
+
a41c76
+            if (bitmap->inconsistent ||
a41c76
+                !qemuBlockBitmapChainIsValid(topsrc, bitmap->name, blockNamedNodeData))
a41c76
+                bitmapdata->skip = true;
a41c76
+
a41c76
+            if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(bitmapdata->merge,
a41c76
+                                                                 n->nodeformat,
a41c76
+                                                                 bitmap->name) < 0)
a41c76
+                return -1;
a41c76
+        }
a41c76
+    }
a41c76
+
a41c76
+    if ((entry = virHashLookup(blockNamedNodeData, basesrc->nodeformat))) {
a41c76
+        /* note that all bitmaps in 'base' were disabled when commit was started */
a41c76
+        for (i = 0; i < entry->nbitmaps; i++) {
a41c76
+            qemuBlockNamedNodeDataBitmapPtr bitmap = entry->bitmaps[i];
a41c76
+
a41c76
+            if ((bitmapdata = virHashLookup(commitdata, bitmap->name))) {
a41c76
+                bitmapdata->create = false;
a41c76
+            } else {
a41c76
+                if (disabledBitmapsBase) {
a41c76
+                    char **disabledbitmaps;
a41c76
+
a41c76
+                    for (disabledbitmaps = disabledBitmapsBase; *disabledbitmaps; disabledbitmaps++) {
a41c76
+                        if (STREQ(*disabledBitmapsBase, bitmap->name)) {
a41c76
+                            bitmapdata = g_new0(struct qemuBlockBitmapsHandleCommitData, 1);
a41c76
+
a41c76
+                            bitmapdata->create = false;
a41c76
+                            bitmapdata->enable = true;
a41c76
+                            bitmapdata->basenode = basesrc->nodeformat;
a41c76
+                            bitmapdata->granularity = bitmap->granularity;
a41c76
+                            bitmapdata->persistent = bitmap->persistent;
a41c76
+
a41c76
+                            if (virHashAddEntry(commitdata, bitmap->name, bitmapdata) < 0) {
a41c76
+                                qemuBlockBitmapsHandleCommitDataFree(bitmapdata);
a41c76
+                                return -1;
a41c76
+                            }
a41c76
+
a41c76
+                            break;
a41c76
+                        }
a41c76
+                    }
a41c76
+                }
a41c76
+            }
a41c76
+        }
a41c76
+    }
a41c76
+
a41c76
+    if (virHashForEach(commitdata, qemuBlockBitmapsHandleCommitFinishIterate, act) < 0)
a41c76
+        return -1;
a41c76
+
a41c76
+    if (virJSONValueArraySize(act) > 0)
a41c76
+        *actions = g_steal_pointer(&act;;
a41c76
+
a41c76
+    return 0;
a41c76
+}
a41c76
+
a41c76
+
a41c76
 /**
a41c76
  * qemuBlockReopenFormat:
a41c76
  * @vm: domain object
a41c76
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
a41c76
index e012052352..75b25bfea5 100644
a41c76
--- a/src/qemu/qemu_block.h
a41c76
+++ b/src/qemu/qemu_block.h
a41c76
@@ -232,6 +232,20 @@ qemuBlockBitmapsHandleBlockcopy(virStorageSourcePtr src,
a41c76
                                 bool shallow,
a41c76
                                 virJSONValuePtr *actions);
a41c76
 
a41c76
+int
a41c76
+qemuBlockBitmapsHandleCommitStart(virStorageSourcePtr topsrc,
a41c76
+                                  virStorageSourcePtr basesrc,
a41c76
+                                  virHashTablePtr blockNamedNodeData,
a41c76
+                                  virJSONValuePtr *actions,
a41c76
+                                  char ***disabledBitmapsBase);
a41c76
+
a41c76
+int
a41c76
+qemuBlockBitmapsHandleCommitFinish(virStorageSourcePtr topsrc,
a41c76
+                                   virStorageSourcePtr basesrc,
a41c76
+                                   virHashTablePtr blockNamedNodeData,
a41c76
+                                   virJSONValuePtr *actions,
a41c76
+                                   char **disabledBitmapsBase);
a41c76
+
a41c76
 int
a41c76
 qemuBlockReopenReadWrite(virDomainObjPtr vm,
a41c76
                          virStorageSourcePtr src,
a41c76
-- 
a41c76
2.25.1
a41c76