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