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