|
|
a41c76 |
From 8d813e074a1bbe7636c487487e661a5e1a713fd1 Mon Sep 17 00:00:00 2001
|
|
|
a41c76 |
Message-Id: <8d813e074a1bbe7636c487487e661a5e1a713fd1@dist-git>
|
|
|
a41c76 |
From: Peter Krempa <pkrempa@redhat.com>
|
|
|
a41c76 |
Date: Tue, 23 Jun 2020 12:24:04 +0200
|
|
|
a41c76 |
Subject: [PATCH] qemu: Rewrite bitmap handling for block copy
|
|
|
a41c76 |
MIME-Version: 1.0
|
|
|
a41c76 |
Content-Type: text/plain; charset=UTF-8
|
|
|
a41c76 |
Content-Transfer-Encoding: 8bit
|
|
|
a41c76 |
|
|
|
a41c76 |
Reuse qemuBlockGetBitmapMergeActions which allows the removal of the
|
|
|
a41c76 |
ad-hoc implementation of bitmap merging for block copy.
|
|
|
a41c76 |
|
|
|
a41c76 |
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
|
|
|
a41c76 |
Reviewed-by: Eric Blake <eblake@redhat.com>
|
|
|
a41c76 |
(cherry picked from commit 7bfff40fdfe5410c446c1cd8ec413e00530faf7d)
|
|
|
a41c76 |
https://bugzilla.redhat.com/show_bug.cgi?id=1804593
|
|
|
a41c76 |
Message-Id: <6a254120769a0071ef6867e4c15aca7d3760cf3c.1592906423.git.pkrempa@redhat.com>
|
|
|
a41c76 |
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
|
|
a41c76 |
---
|
|
|
a41c76 |
src/qemu/qemu_block.c | 113 ++-------------------------------------
|
|
|
a41c76 |
src/qemu/qemu_blockjob.c | 40 ++++++++++++++
|
|
|
a41c76 |
src/qemu/qemu_driver.c | 13 ++---
|
|
|
a41c76 |
tests/qemublocktest.c | 6 ++-
|
|
|
a41c76 |
4 files changed, 57 insertions(+), 115 deletions(-)
|
|
|
a41c76 |
|
|
|
a41c76 |
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
|
|
|
a41c76 |
index ff9e000461..18c3861a2e 100644
|
|
|
a41c76 |
--- a/src/qemu/qemu_block.c
|
|
|
a41c76 |
+++ b/src/qemu/qemu_block.c
|
|
|
a41c76 |
@@ -3053,38 +3053,6 @@ qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
|
|
|
a41c76 |
}
|
|
|
a41c76 |
|
|
|
a41c76 |
|
|
|
a41c76 |
-struct qemuBlockBitmapsHandleBlockcopyConcatData {
|
|
|
a41c76 |
- virHashTablePtr bitmaps_merge;
|
|
|
a41c76 |
- virJSONValuePtr actions;
|
|
|
a41c76 |
- const char *mirrornodeformat;
|
|
|
a41c76 |
- bool has_bitmaps;
|
|
|
a41c76 |
-};
|
|
|
a41c76 |
-
|
|
|
a41c76 |
-
|
|
|
a41c76 |
-static int
|
|
|
a41c76 |
-qemuBlockBitmapsHandleBlockcopyConcatActions(void *payload,
|
|
|
a41c76 |
- const void *name,
|
|
|
a41c76 |
- void *opaque)
|
|
|
a41c76 |
-{
|
|
|
a41c76 |
- struct qemuBlockBitmapsHandleBlockcopyConcatData *data = opaque;
|
|
|
a41c76 |
- virJSONValuePtr createactions = payload;
|
|
|
a41c76 |
- const char *bitmapname = name;
|
|
|
a41c76 |
- g_autoptr(virJSONValue) mergebitmaps = virHashSteal(data->bitmaps_merge, bitmapname);
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- data->has_bitmaps = true;
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- virJSONValueArrayConcat(data->actions, createactions);
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- if (qemuMonitorTransactionBitmapMerge(data->actions,
|
|
|
a41c76 |
- data->mirrornodeformat,
|
|
|
a41c76 |
- bitmapname,
|
|
|
a41c76 |
- &mergebitmaps) < 0)
|
|
|
a41c76 |
- return -1;
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- return 0;
|
|
|
a41c76 |
-}
|
|
|
a41c76 |
-
|
|
|
a41c76 |
-
|
|
|
a41c76 |
/**
|
|
|
a41c76 |
* qemuBlockBitmapsHandleBlockcopy:
|
|
|
a41c76 |
* @src: disk source
|
|
|
a41c76 |
@@ -3107,86 +3075,15 @@ qemuBlockBitmapsHandleBlockcopy(virStorageSourcePtr src,
|
|
|
a41c76 |
bool shallow,
|
|
|
a41c76 |
virJSONValuePtr *actions)
|
|
|
a41c76 |
{
|
|
|
a41c76 |
- g_autoptr(virHashTable) bitmaps = virHashNew(virJSONValueHashFree);
|
|
|
a41c76 |
- g_autoptr(virHashTable) bitmaps_merge = virHashNew(virJSONValueHashFree);
|
|
|
a41c76 |
- g_autoptr(virHashTable) bitmaps_skip = virHashNew(NULL);
|
|
|
a41c76 |
- g_autoptr(virJSONValue) tmpactions = virJSONValueNewArray();
|
|
|
a41c76 |
- qemuBlockNamedNodeDataPtr entry;
|
|
|
a41c76 |
- virStorageSourcePtr n;
|
|
|
a41c76 |
- size_t i;
|
|
|
a41c76 |
- struct qemuBlockBitmapsHandleBlockcopyConcatData data = { .bitmaps_merge = bitmaps_merge,
|
|
|
a41c76 |
- .actions = tmpactions,
|
|
|
a41c76 |
- .mirrornodeformat = mirror->nodeformat,
|
|
|
a41c76 |
- .has_bitmaps = false, };
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- for (n = src; n; 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 |
- virJSONValuePtr bitmap_merge;
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- if (virHashHasEntry(bitmaps_skip, bitmap->name))
|
|
|
a41c76 |
- continue;
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- if (!(bitmap_merge = virHashLookup(bitmaps_merge, bitmap->name))) {
|
|
|
a41c76 |
- g_autoptr(virJSONValue) tmp = NULL;
|
|
|
a41c76 |
- bool disabled = !bitmap->recording;
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- /* disable any non top-layer bitmaps */
|
|
|
a41c76 |
- if (n != src)
|
|
|
a41c76 |
- disabled = true;
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- if (!bitmap->persistent ||
|
|
|
a41c76 |
- !(qemuBlockBitmapChainIsValid(n, bitmap->name,
|
|
|
a41c76 |
- blockNamedNodeData))) {
|
|
|
a41c76 |
- ignore_value(virHashAddEntry(bitmaps_skip, bitmap->name, NULL));
|
|
|
a41c76 |
- continue;
|
|
|
a41c76 |
- }
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- /* prepare the data for adding the bitmap to the mirror */
|
|
|
a41c76 |
- tmp = virJSONValueNewArray();
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- if (qemuMonitorTransactionBitmapAdd(tmp,
|
|
|
a41c76 |
- mirror->nodeformat,
|
|
|
a41c76 |
- bitmap->name,
|
|
|
a41c76 |
- true,
|
|
|
a41c76 |
- disabled,
|
|
|
a41c76 |
- bitmap->granularity) < 0)
|
|
|
a41c76 |
- return -1;
|
|
|
a41c76 |
+ virStorageSourcePtr base = NULL;
|
|
|
a41c76 |
|
|
|
a41c76 |
- if (virHashAddEntry(bitmaps, bitmap->name, tmp) < 0)
|
|
|
a41c76 |
- return -1;
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- tmp = NULL;
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- /* prepare array for merging all the bitmaps from the original chain */
|
|
|
a41c76 |
- tmp = virJSONValueNewArray();
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- if (virHashAddEntry(bitmaps_merge, bitmap->name, tmp) < 0)
|
|
|
a41c76 |
- return -1;
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- bitmap_merge = g_steal_pointer(&tmp);
|
|
|
a41c76 |
- }
|
|
|
a41c76 |
+ if (shallow)
|
|
|
a41c76 |
+ base = src->backingStore;
|
|
|
a41c76 |
|
|
|
a41c76 |
- if (qemuMonitorTransactionBitmapMergeSourceAddBitmap(bitmap_merge,
|
|
|
a41c76 |
- n->nodeformat,
|
|
|
a41c76 |
- bitmap->name) < 0)
|
|
|
a41c76 |
- return -1;
|
|
|
a41c76 |
- }
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- if (shallow)
|
|
|
a41c76 |
- break;
|
|
|
a41c76 |
- }
|
|
|
a41c76 |
-
|
|
|
a41c76 |
- if (virHashForEach(bitmaps, qemuBlockBitmapsHandleBlockcopyConcatActions,
|
|
|
a41c76 |
- &data) < 0)
|
|
|
a41c76 |
+ if (qemuBlockGetBitmapMergeActions(src, base, mirror, NULL, NULL, mirror, actions,
|
|
|
a41c76 |
+ blockNamedNodeData) < 0)
|
|
|
a41c76 |
return -1;
|
|
|
a41c76 |
|
|
|
a41c76 |
- if (data.has_bitmaps)
|
|
|
a41c76 |
- *actions = g_steal_pointer(&tmpactions);
|
|
|
a41c76 |
-
|
|
|
a41c76 |
return 0;
|
|
|
a41c76 |
}
|
|
|
a41c76 |
|
|
|
a41c76 |
diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
|
|
|
a41c76 |
index d106165175..6e33f8666c 100644
|
|
|
a41c76 |
--- a/src/qemu/qemu_blockjob.c
|
|
|
a41c76 |
+++ b/src/qemu/qemu_blockjob.c
|
|
|
a41c76 |
@@ -1281,6 +1281,43 @@ qemuBlockJobProcessEventCompletedActiveCommit(virQEMUDriverPtr driver,
|
|
|
a41c76 |
}
|
|
|
a41c76 |
|
|
|
a41c76 |
|
|
|
a41c76 |
+static int
|
|
|
a41c76 |
+qemuBlockJobProcessEventCompletedCopyBitmaps(virDomainObjPtr vm,
|
|
|
a41c76 |
+ qemuBlockJobDataPtr job,
|
|
|
a41c76 |
+ qemuDomainAsyncJob asyncJob)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
a41c76 |
+ g_autoptr(virHashTable) blockNamedNodeData = NULL;
|
|
|
a41c76 |
+ g_autoptr(virJSONValue) actions = NULL;
|
|
|
a41c76 |
+ bool shallow = job->jobflags & VIR_DOMAIN_BLOCK_COPY_SHALLOW;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN))
|
|
|
a41c76 |
+ return 0;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, asyncJob)))
|
|
|
a41c76 |
+ return -1;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (qemuBlockBitmapsHandleBlockcopy(job->disk->src,
|
|
|
a41c76 |
+ job->disk->mirror,
|
|
|
a41c76 |
+ blockNamedNodeData,
|
|
|
a41c76 |
+ shallow,
|
|
|
a41c76 |
+ &actions) < 0)
|
|
|
a41c76 |
+ return 0;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (!actions)
|
|
|
a41c76 |
+ return 0;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (qemuDomainObjEnterMonitorAsync(priv->driver, vm, asyncJob) < 0)
|
|
|
a41c76 |
+ return -1;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ qemuMonitorTransaction(priv->mon, &actions);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (qemuDomainObjExitMonitor(priv->driver, vm) < 0)
|
|
|
a41c76 |
+ return -1;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ return 0;
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
+
|
|
|
a41c76 |
static void
|
|
|
a41c76 |
qemuBlockJobProcessEventConcludedCopyPivot(virQEMUDriverPtr driver,
|
|
|
a41c76 |
virDomainObjPtr vm,
|
|
|
a41c76 |
@@ -1295,6 +1332,8 @@ qemuBlockJobProcessEventConcludedCopyPivot(virQEMUDriverPtr driver,
|
|
|
a41c76 |
!job->disk->mirror)
|
|
|
a41c76 |
return;
|
|
|
a41c76 |
|
|
|
a41c76 |
+ qemuBlockJobProcessEventCompletedCopyBitmaps(vm, job, asyncJob);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
/* for shallow copy without reusing external image the user can either not
|
|
|
a41c76 |
* specify the backing chain in which case libvirt will open and use the
|
|
|
a41c76 |
* chain the user provided or not specify a chain in which case we'll
|
|
|
a41c76 |
@@ -1328,6 +1367,7 @@ qemuBlockJobProcessEventConcludedCopyAbort(virQEMUDriverPtr driver,
|
|
|
a41c76 |
!job->disk->mirror)
|
|
|
a41c76 |
return;
|
|
|
a41c76 |
|
|
|
a41c76 |
+ /* activeWrite bitmap is removed automatically here */
|
|
|
a41c76 |
qemuBlockJobEventProcessConcludedRemoveChain(driver, vm, asyncJob, job->disk->mirror);
|
|
|
a41c76 |
virObjectUnref(job->disk->mirror);
|
|
|
a41c76 |
job->disk->mirror = NULL;
|
|
|
a41c76 |
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
|
|
a41c76 |
index ed5498d2bc..9e3a455814 100644
|
|
|
a41c76 |
--- a/src/qemu/qemu_driver.c
|
|
|
a41c76 |
+++ b/src/qemu/qemu_driver.c
|
|
|
a41c76 |
@@ -17596,14 +17596,15 @@ qemuDomainBlockPivot(virQEMUDriverPtr driver,
|
|
|
a41c76 |
if (blockdev && !job->jobflagsmissing) {
|
|
|
a41c76 |
bool shallow = job->jobflags & VIR_DOMAIN_BLOCK_COPY_SHALLOW;
|
|
|
a41c76 |
bool reuse = job->jobflags & VIR_DOMAIN_BLOCK_COPY_REUSE_EXT;
|
|
|
a41c76 |
- g_autoptr(virHashTable) blockNamedNodeData = NULL;
|
|
|
a41c76 |
|
|
|
a41c76 |
- if (!(blockNamedNodeData = qemuBlockGetNamedNodeData(vm, QEMU_ASYNC_JOB_NONE)))
|
|
|
a41c76 |
- return -1;
|
|
|
a41c76 |
+ actions = virJSONValueNewArray();
|
|
|
a41c76 |
|
|
|
a41c76 |
- if (qemuBlockBitmapsHandleBlockcopy(disk->src, disk->mirror,
|
|
|
a41c76 |
- blockNamedNodeData,
|
|
|
a41c76 |
- shallow, &actions) < 0)
|
|
|
a41c76 |
+ if (qemuMonitorTransactionBitmapAdd(actions,
|
|
|
a41c76 |
+ disk->mirror->nodeformat,
|
|
|
a41c76 |
+ "libvirt-tmp-activewrite",
|
|
|
a41c76 |
+ false,
|
|
|
a41c76 |
+ false,
|
|
|
a41c76 |
+ 0) < 0)
|
|
|
a41c76 |
return -1;
|
|
|
a41c76 |
|
|
|
a41c76 |
/* Open and install the backing chain of 'mirror' late if we can use
|
|
|
a41c76 |
diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c
|
|
|
a41c76 |
index e1468f13fa..193b4aaed0 100644
|
|
|
a41c76 |
--- a/tests/qemublocktest.c
|
|
|
a41c76 |
+++ b/tests/qemublocktest.c
|
|
|
a41c76 |
@@ -881,6 +881,7 @@ testQemuBlockBitmapBlockcopy(const void *opaque)
|
|
|
a41c76 |
g_autoptr(virJSONValue) nodedatajson = NULL;
|
|
|
a41c76 |
g_autoptr(virHashTable) nodedata = NULL;
|
|
|
a41c76 |
g_autoptr(virStorageSource) fakemirror = virStorageSourceNew();
|
|
|
a41c76 |
+ g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
|
|
a41c76 |
|
|
|
a41c76 |
if (!fakemirror)
|
|
|
a41c76 |
return -1;
|
|
|
a41c76 |
@@ -903,10 +904,13 @@ testQemuBlockBitmapBlockcopy(const void *opaque)
|
|
|
a41c76 |
data->shallow, &actions) < 0)
|
|
|
a41c76 |
return -1;
|
|
|
a41c76 |
|
|
|
a41c76 |
+
|
|
|
a41c76 |
if (actions &&
|
|
|
a41c76 |
- !(actual = virJSONValueToString(actions, true)))
|
|
|
a41c76 |
+ virJSONValueToBuffer(actions, &buf, true) < 0)
|
|
|
a41c76 |
return -1;
|
|
|
a41c76 |
|
|
|
a41c76 |
+ actual = virBufferContentAndReset(&buf;;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
return virTestCompareToFile(actual, expectpath);
|
|
|
a41c76 |
}
|
|
|
a41c76 |
|
|
|
a41c76 |
--
|
|
|
a41c76 |
2.27.0
|
|
|
a41c76 |
|