|
|
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 |
|