|
|
a41c76 |
From eeb1315a8015aeda4d2fb7ce590c85c40ffb567d Mon Sep 17 00:00:00 2001
|
|
|
a41c76 |
Message-Id: <eeb1315a8015aeda4d2fb7ce590c85c40ffb567d@dist-git>
|
|
|
a41c76 |
From: Peter Krempa <pkrempa@redhat.com>
|
|
|
a41c76 |
Date: Tue, 4 Feb 2020 15:08:23 +0100
|
|
|
a41c76 |
Subject: [PATCH] qemu: block: Add validator for bitmap chains accross backing
|
|
|
a41c76 |
chains
|
|
|
a41c76 |
MIME-Version: 1.0
|
|
|
a41c76 |
Content-Type: text/plain; charset=UTF-8
|
|
|
a41c76 |
Content-Transfer-Encoding: 8bit
|
|
|
a41c76 |
|
|
|
a41c76 |
Add a validator which checks that a bitmap spanning multiple backing
|
|
|
a41c76 |
chain members doesn't look broken. The current rules are that no
|
|
|
a41c76 |
intermediate birmaps are missing (unfortunately it's hard to know
|
|
|
a41c76 |
whether the topmost or bottommost bitmap is missing) and none of the
|
|
|
a41c76 |
components is inconsistent.
|
|
|
a41c76 |
|
|
|
a41c76 |
We can obviously improve it over time.
|
|
|
a41c76 |
|
|
|
a41c76 |
The validator is also tested against the existing bitmap data we have
|
|
|
a41c76 |
for the backup merging test as well as some of the existing broken
|
|
|
a41c76 |
bitmap synthetic test cases.
|
|
|
a41c76 |
|
|
|
a41c76 |
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
|
|
|
a41c76 |
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
|
|
a41c76 |
(cherry picked from commit 41c7e5c2a689a4ad091cec40b61beeeb3dde49b8)
|
|
|
a41c76 |
|
|
|
a41c76 |
https://bugzilla.redhat.com/show_bug.cgi?id=1207659
|
|
|
a41c76 |
Message-Id: <a1020495b33e99b2c1bb847dff26565d4def1e20.1580824112.git.pkrempa@redhat.com>
|
|
|
a41c76 |
Reviewed-by: Ján Tomko <jtomko@redhat.com>
|
|
|
a41c76 |
---
|
|
|
a41c76 |
src/qemu/qemu_block.c | 41 +++++++++++++++++++++++++
|
|
|
a41c76 |
src/qemu/qemu_block.h | 5 ++++
|
|
|
a41c76 |
tests/qemublocktest.c | 70 +++++++++++++++++++++++++++++++++++++++++++
|
|
|
a41c76 |
3 files changed, 116 insertions(+)
|
|
|
a41c76 |
|
|
|
a41c76 |
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
|
|
|
a41c76 |
index 03f029368e..b19290e677 100644
|
|
|
a41c76 |
--- a/src/qemu/qemu_block.c
|
|
|
a41c76 |
+++ b/src/qemu/qemu_block.c
|
|
|
a41c76 |
@@ -2687,3 +2687,44 @@ qemuBlockGetNamedNodeData(virDomainObjPtr vm,
|
|
|
a41c76 |
|
|
|
a41c76 |
return g_steal_pointer(&blockNamedNodeData);
|
|
|
a41c76 |
}
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+/**
|
|
|
a41c76 |
+ * qemuBlockBitmapChainIsValid:
|
|
|
a41c76 |
+ *
|
|
|
a41c76 |
+ * Validates that the backing chain of @src contains proper consistent bitmap
|
|
|
a41c76 |
+ * data for a chain of bitmaps named @bitmapname.
|
|
|
a41c76 |
+ *
|
|
|
a41c76 |
+ * A valid chain:
|
|
|
a41c76 |
+ * 1) bitmaps of same name are in a consecutive subset of images without gap
|
|
|
a41c76 |
+ * 2) don't have any inconsistent bitmaps
|
|
|
a41c76 |
+ */
|
|
|
a41c76 |
+bool
|
|
|
a41c76 |
+qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
|
|
|
a41c76 |
+ const char *bitmapname,
|
|
|
a41c76 |
+ virHashTablePtr blockNamedNodeData)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ qemuBlockNamedNodeDataBitmapPtr bitmap;
|
|
|
a41c76 |
+ virStorageSourcePtr n;
|
|
|
a41c76 |
+ bool chain_started = false;
|
|
|
a41c76 |
+ bool chain_ended = false;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ for (n = src; n; n = n->backingStore) {
|
|
|
a41c76 |
+ if (!(bitmap = qemuBlockNamedNodeDataGetBitmapByName(blockNamedNodeData, n, bitmapname))) {
|
|
|
a41c76 |
+ if (chain_started)
|
|
|
a41c76 |
+ chain_ended = true;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ continue;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (chain_ended)
|
|
|
a41c76 |
+ return false;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ chain_started = true;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (bitmap->inconsistent)
|
|
|
a41c76 |
+ return false;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ return chain_started;
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
|
|
|
a41c76 |
index 68646cbf2e..cf51b9bf4e 100644
|
|
|
a41c76 |
--- a/src/qemu/qemu_block.h
|
|
|
a41c76 |
+++ b/src/qemu/qemu_block.h
|
|
|
a41c76 |
@@ -212,3 +212,8 @@ qemuBlockNamedNodeDataGetBitmapByName(virHashTablePtr blockNamedNodeData,
|
|
|
a41c76 |
virHashTablePtr
|
|
|
a41c76 |
qemuBlockGetNamedNodeData(virDomainObjPtr vm,
|
|
|
a41c76 |
qemuDomainAsyncJob asyncJob);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+bool
|
|
|
a41c76 |
+qemuBlockBitmapChainIsValid(virStorageSourcePtr src,
|
|
|
a41c76 |
+ const char *bitmapname,
|
|
|
a41c76 |
+ virHashTablePtr blockNamedNodeData);
|
|
|
a41c76 |
diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c
|
|
|
a41c76 |
index 5946cd6c6b..6a7b07cfee 100644
|
|
|
a41c76 |
--- a/tests/qemublocktest.c
|
|
|
a41c76 |
+++ b/tests/qemublocktest.c
|
|
|
a41c76 |
@@ -764,6 +764,41 @@ testQemuCheckpointDeleteMerge(const void *opaque)
|
|
|
a41c76 |
}
|
|
|
a41c76 |
|
|
|
a41c76 |
|
|
|
a41c76 |
+struct testQemuBlockBitmapValidateData {
|
|
|
a41c76 |
+ const char *name;
|
|
|
a41c76 |
+ const char *bitmapname;
|
|
|
a41c76 |
+ virStorageSourcePtr chain;
|
|
|
a41c76 |
+ bool expect;
|
|
|
a41c76 |
+};
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+static int
|
|
|
a41c76 |
+testQemuBlockBitmapValidate(const void *opaque)
|
|
|
a41c76 |
+{
|
|
|
a41c76 |
+ const struct testQemuBlockBitmapValidateData *data = opaque;
|
|
|
a41c76 |
+ g_autoptr(virJSONValue) nodedatajson = NULL;
|
|
|
a41c76 |
+ g_autoptr(virHashTable) nodedata = NULL;
|
|
|
a41c76 |
+ bool actual;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (!(nodedatajson = virTestLoadFileJSON(bitmapDetectPrefix, data->name,
|
|
|
a41c76 |
+ ".json", NULL)))
|
|
|
a41c76 |
+ return -1;
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (!(nodedata = qemuMonitorJSONBlockGetNamedNodeDataJSON(nodedatajson))) {
|
|
|
a41c76 |
+ VIR_TEST_VERBOSE("failed to load nodedata JSON\n");
|
|
|
a41c76 |
+ return -1;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ actual = qemuBlockBitmapChainIsValid(data->chain, data->bitmapname, nodedata);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ if (actual != data->expect) {
|
|
|
a41c76 |
+ VIR_TEST_VERBOSE("expected rv:'%d' actual rv:'%d'\n", data->expect, actual);
|
|
|
a41c76 |
+ return -1;
|
|
|
a41c76 |
+ }
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ return 0;
|
|
|
a41c76 |
+}
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+
|
|
|
a41c76 |
static int
|
|
|
a41c76 |
mymain(void)
|
|
|
a41c76 |
{
|
|
|
a41c76 |
@@ -774,6 +809,7 @@ mymain(void)
|
|
|
a41c76 |
struct testQemuImageCreateData imagecreatedata;
|
|
|
a41c76 |
struct testQemuBackupIncrementalBitmapCalculateData backupbitmapcalcdata;
|
|
|
a41c76 |
struct testQemuCheckpointDeleteMergeData checkpointdeletedata;
|
|
|
a41c76 |
+ struct testQemuBlockBitmapValidateData blockbitmapvalidatedata;
|
|
|
a41c76 |
char *capslatest_x86_64 = NULL;
|
|
|
a41c76 |
virQEMUCapsPtr caps_x86_64 = NULL;
|
|
|
a41c76 |
g_autoptr(virStorageSource) bitmapSourceChain = NULL;
|
|
|
a41c76 |
@@ -1041,7 +1077,41 @@ mymain(void)
|
|
|
a41c76 |
TEST_CHECKPOINT_DELETE_MERGE("snapshots-synthetic-checkpoint-intermediate3", "d", "c", "snapshots-synthetic-checkpoint");
|
|
|
a41c76 |
TEST_CHECKPOINT_DELETE_MERGE("snapshots-synthetic-checkpoint-current", "current", "d", "snapshots-synthetic-checkpoint");
|
|
|
a41c76 |
|
|
|
a41c76 |
+#define TEST_BITMAP_VALIDATE(testname, bitmap, rc) \
|
|
|
a41c76 |
+ do { \
|
|
|
a41c76 |
+ blockbitmapvalidatedata.name = testname; \
|
|
|
a41c76 |
+ blockbitmapvalidatedata.chain = bitmapSourceChain; \
|
|
|
a41c76 |
+ blockbitmapvalidatedata.bitmapname = bitmap; \
|
|
|
a41c76 |
+ blockbitmapvalidatedata.expect = rc; \
|
|
|
a41c76 |
+ if (virTestRun("bitmap validate " testname " " bitmap, \
|
|
|
a41c76 |
+ testQemuBlockBitmapValidate, \
|
|
|
a41c76 |
+ &blockbitmapvalidatedata) < 0) \
|
|
|
a41c76 |
+ ret = -1; \
|
|
|
a41c76 |
+ } while (0)
|
|
|
a41c76 |
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("basic", "a", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("basic", "b", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("basic", "c", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("basic", "d", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("basic", "current", true);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("snapshots", "a", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("snapshots", "b", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("snapshots", "c", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("snapshots", "d", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("snapshots", "current", true);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("synthetic", "a", false);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("synthetic", "b", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("synthetic", "c", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("synthetic", "d", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("synthetic", "current", true);
|
|
|
a41c76 |
+
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "a", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "b", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "c", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "d", true);
|
|
|
a41c76 |
+ TEST_BITMAP_VALIDATE("snapshots-synthetic-checkpoint", "current", true);
|
|
|
a41c76 |
cleanup:
|
|
|
a41c76 |
virHashFree(diskxmljsondata.schema);
|
|
|
a41c76 |
qemuTestDriverFree(&driver);
|
|
|
a41c76 |
--
|
|
|
a41c76 |
2.25.0
|
|
|
a41c76 |
|