From ad1c17c8d56b71f7d23e18dd68642f337b2278aa Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 5 Jun 2019 21:25:05 -0500 Subject: [PATCH] backup: Add new qemu monitor bitmap The upcoming virDomainBackup() API needs to take advantage of various qcow2 bitmap manipulations as the basis to virDomainCheckpoints and incremental backups. Add four functions to expose block-dirty-bitmap-{add,enable,disable,merge} (this is the recently-added QEMU_CAPS_BITMAP_MERGE capability). Signed-off-by: Eric Blake Acked-by: Peter Krempa --- src/qemu/qemu_monitor.c | 51 +++++++++++++++ src/qemu/qemu_monitor.h | 19 ++++++ src/qemu/qemu_monitor_json.c | 119 +++++++++++++++++++++++++++++++++++ src/qemu/qemu_monitor_json.h | 17 +++++ tests/qemumonitorjsontest.c | 41 ++++++++++++ 5 files changed, 247 insertions(+) diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 187513a986..a371f7d425 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -4488,3 +4488,54 @@ qemuMonitorGetCurrentMachineInfo(qemuMonitorPtr mon, return qemuMonitorJSONGetCurrentMachineInfo(mon, info); } + + +int +qemuMonitorAddBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap, + bool persistent) +{ + VIR_DEBUG("node=%s bitmap=%s persistent=%d", node, bitmap, persistent); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONAddBitmap(mon, node, bitmap, persistent); +} + +int +qemuMonitorEnableBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap) +{ + VIR_DEBUG("node=%s bitmap=%s", node, bitmap); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONEnableBitmap(mon, node, bitmap); +} + +int +qemuMonitorMergeBitmaps(qemuMonitorPtr mon, + const char *node, + const char *dst, + virJSONValuePtr *src) +{ + VIR_DEBUG("node=%s dst=%s", node, dst); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONMergeBitmaps(mon, node, dst, src); +} + +int +qemuMonitorDeleteBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap) +{ + VIR_DEBUG("node=%s bitmap=%s", node, bitmap); + + QEMU_CHECK_MONITOR(mon); + + return qemuMonitorJSONDeleteBitmap(mon, node, bitmap); +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index fa84ff821e..30474c325d 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -646,6 +646,25 @@ int qemuMonitorSetBalloon(qemuMonitorPtr mon, unsigned long long newmem); int qemuMonitorSetCPU(qemuMonitorPtr mon, int cpu, bool online); +int qemuMonitorAddBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap, + bool persistent) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +int qemuMonitorEnableBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); +int qemuMonitorMergeBitmaps(qemuMonitorPtr mon, + const char *node, + const char *dst, + virJSONValuePtr *src) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); +int qemuMonitorDeleteBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + /* XXX should we pass the virDomainDiskDefPtr instead * and hide dev_name details inside monitor. Reconsider diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 93113d4e8a..41eef0c38c 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -8510,3 +8510,122 @@ qemuMonitorJSONGetCurrentMachineInfo(qemuMonitorPtr mon, virJSONValueFree(reply); return ret; } + + +int +qemuMonitorJSONAddBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap, + bool persistent) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("block-dirty-bitmap-add", + "s:node", node, + "s:name", bitmap, + "b:persistent", persistent, + NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + ret = 0; + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + +int +qemuMonitorJSONEnableBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("block-dirty-bitmap-enable", + "s:node", node, + "s:name", bitmap, + NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + ret = 0; + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + +int +qemuMonitorJSONMergeBitmaps(qemuMonitorPtr mon, + const char *node, + const char *dst, + virJSONValuePtr *src) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("block-dirty-bitmap-merge", + "s:node", node, + "s:target", dst, + "a:bitmaps", src, + NULL))) + goto cleanup; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + ret = 0; + cleanup: + virJSONValueFree(*src); + *src = NULL; + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + +int +qemuMonitorJSONDeleteBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap) +{ + int ret = -1; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("block-dirty-bitmap-remove", + "s:node", node, + "s:name", bitmap, + NULL))) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + if (qemuMonitorJSONCheckError(cmd, reply) < 0) + goto cleanup; + + ret = 0; + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index e41bdc8c4f..8f92e6de35 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -580,5 +580,22 @@ int qemuMonitorJSONGetCurrentMachineInfo(qemuMonitorPtr mon, qemuMonitorCurrentMachineInfoPtr info) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int qemuMonitorJSONAddBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap, + bool persistent); + +int qemuMonitorJSONEnableBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap); + +int qemuMonitorJSONMergeBitmaps(qemuMonitorPtr mon, + const char *node, + const char *dst, + virJSONValuePtr *src); + +int qemuMonitorJSONDeleteBitmap(qemuMonitorPtr mon, + const char *node, + const char *bitmap); #endif /* LIBVIRT_QEMU_MONITOR_JSON_H */ diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index d29ce855cf..c585479e62 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -1337,6 +1337,9 @@ GEN_TEST_FUNC(qemuMonitorJSONBlockdevTrayOpen, "foodev", true) GEN_TEST_FUNC(qemuMonitorJSONBlockdevTrayClose, "foodev") GEN_TEST_FUNC(qemuMonitorJSONBlockdevMediumRemove, "foodev") GEN_TEST_FUNC(qemuMonitorJSONBlockdevMediumInsert, "foodev", "newnode") +GEN_TEST_FUNC(qemuMonitorJSONAddBitmap, "node", "bitmap", true) +GEN_TEST_FUNC(qemuMonitorJSONEnableBitmap, "node", "bitmap") +GEN_TEST_FUNC(qemuMonitorJSONDeleteBitmap, "node", "bitmap") static int testQemuMonitorJSONqemuMonitorJSONNBDServerStart(const void *opaque) @@ -1376,6 +1379,40 @@ testQemuMonitorJSONqemuMonitorJSONNBDServerStart(const void *opaque) return 0; } +static int +testQemuMonitorJSONqemuMonitorJSONMergeBitmaps(const void *opaque) +{ + const testGenericData *data = opaque; + virDomainXMLOptionPtr xmlopt = data->xmlopt; + VIR_AUTOPTR(qemuMonitorTest) test = NULL; + VIR_AUTOPTR(virJSONValue) arr = NULL; + + if (!(test = qemuMonitorTestNewSchema(xmlopt, data->schema))) + return -1; + + if (!(arr = virJSONValueNewArray())) + return -1; + + if (virJSONValueArrayAppendString(arr, "b1") < 0 || + virJSONValueArrayAppendString(arr, "b2") < 0) + return -1; + + if (qemuMonitorTestAddItem(test, "block-dirty-bitmap-merge", + "{\"return\":{}}") < 0) + return -1; + + if (qemuMonitorJSONMergeBitmaps(qemuMonitorTestGetMonitor(test), + "node", "dst", &arr) < 0) + return -1; + + if (arr) { + virReportError(VIR_ERR_INTERNAL_ERROR, "arr should have been cleared"); + return -1; + } + + return 0; +} + static bool testQemuMonitorJSONqemuMonitorJSONQueryCPUsEqual(struct qemuMonitorQueryCpusEntry *a, struct qemuMonitorQueryCpusEntry *b) @@ -3019,6 +3056,9 @@ mymain(void) DO_TEST_GEN(qemuMonitorJSONBlockdevTrayClose); DO_TEST_GEN(qemuMonitorJSONBlockdevMediumRemove); DO_TEST_GEN(qemuMonitorJSONBlockdevMediumInsert); + DO_TEST_GEN(qemuMonitorJSONAddBitmap); + DO_TEST_GEN(qemuMonitorJSONEnableBitmap); + DO_TEST_GEN(qemuMonitorJSONDeleteBitmap); DO_TEST(qemuMonitorJSONGetBalloonInfo); DO_TEST(qemuMonitorJSONGetBlockInfo); DO_TEST(qemuMonitorJSONGetAllBlockStatsInfo); @@ -3035,6 +3075,7 @@ mymain(void) DO_TEST(qemuMonitorJSONSendKeyHoldtime); DO_TEST(qemuMonitorSupportsActiveCommit); DO_TEST(qemuMonitorJSONNBDServerStart); + DO_TEST(qemuMonitorJSONMergeBitmaps); DO_TEST_CPU_DATA("host"); DO_TEST_CPU_DATA("full");