Add some monitor commands to be used during backup/checkpoint
operations: another facet to query-block for learning bitmap
size; x-block-dirty-bitmap-enable,
x-block-dirty-bitmap-merge, and block-dirty-bitmap-remove
used when deleting a checkpoint; block-dirty-bitmap-add for
performing incremental backup, and x-nbd-server-add-bitmap
for exposing incremental backups over NBD.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
src/qemu/qemu_monitor.h | 16 +++
src/qemu/qemu_monitor_json.h | 18 +++
src/qemu/qemu_monitor.c | 68 +++++++++++
src/qemu/qemu_monitor_json.c | 215 +++++++++++++++++++++++++++++++++++
4 files changed, 317 insertions(+)
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index b683d0f100..d321c8633f 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -28,6 +28,7 @@
# include "internal.h"
# include "domain_conf.h"
+# include "checkpoint_conf.h"
# include "virbitmap.h"
# include "virhash.h"
# include "virjson.h"
@@ -605,6 +606,9 @@ int qemuMonitorBlockStatsUpdateCapacity(qemuMonitorPtr mon,
int qemuMonitorBlockStatsUpdateCapacityBlockdev(qemuMonitorPtr mon,
virHashTablePtr stats)
ATTRIBUTE_NONNULL(2);
+int qemuMonitorUpdateCheckpointSize(qemuMonitorPtr mon,
+ virDomainCheckpointDefPtr chk)
+ ATTRIBUTE_NONNULL(2);
int qemuMonitorBlockResize(qemuMonitorPtr mon,
const char *device,
@@ -623,6 +627,15 @@ 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);
+int qemuMonitorEnableBitmap(qemuMonitorPtr mon, const char *node,
+ const char *bitmap);
+int qemuMonitorMergeBitmaps(qemuMonitorPtr mon, const char *node,
+ const char *dst, const char *src);
+int qemuMonitorDeleteBitmap(qemuMonitorPtr mon, const char *node,
+ const char *bitmap);
+
/* XXX should we pass the virDomainDiskDefPtr instead
* and hide dev_name details inside monitor. Reconsider
@@ -1076,6 +1089,9 @@ int qemuMonitorNBDServerAdd(qemuMonitorPtr mon,
const char *deviceID,
const char *export,
bool writable);
+int qemuMonitorNBDServerAddBitmap(qemuMonitorPtr mon,
+ const char *export,
+ const char *bitmap);
int qemuMonitorNBDServerStop(qemuMonitorPtr);
int qemuMonitorGetTPMModels(qemuMonitorPtr mon,
char ***tpmmodels);
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index ac08bc21e0..8cf36b42cb 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -101,6 +101,9 @@ int qemuMonitorJSONBlockResize(qemuMonitorPtr mon,
const char *nodename,
unsigned long long size);
+int qemuMonitorJSONUpdateCheckpointSize(qemuMonitorPtr mon,
+ virDomainCheckpointDefPtr chk);
+
int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon,
const char *password);
int qemuMonitorJSONSetPassword(qemuMonitorPtr mon,
@@ -470,6 +473,9 @@ int qemuMonitorJSONNBDServerAdd(qemuMonitorPtr mon,
const char *deviceID,
const char *export,
bool writable);
+int qemuMonitorJSONNBDServerAddBitmap(qemuMonitorPtr mon,
+ const char *export,
+ const char *bitmap);
int qemuMonitorJSONNBDServerStop(qemuMonitorPtr mon);
int qemuMonitorJSONGetTPMModels(qemuMonitorPtr mon,
char ***tpmmodels)
@@ -578,4 +584,16 @@ int qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon,
virHashTablePtr info)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int qemuMonitorJSONAddBitmap(qemuMonitorPtr mon, const char *node,
+ const char *bitmap);
+
+int qemuMonitorJSONEnableBitmap(qemuMonitorPtr mon, const char *node,
+ const char *bitmap);
+
+int qemuMonitorJSONMergeBitmaps(qemuMonitorPtr mon, const char *node,
+ const char *dst, const char *src);
+
+int qemuMonitorJSONDeleteBitmap(qemuMonitorPtr mon, const char *node,
+ const char *bitmap);
+
#endif /* QEMU_MONITOR_JSON_H */
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 0c2e043fc9..2ed6762db8 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2322,6 +2322,17 @@ qemuMonitorBlockStatsUpdateCapacityBlockdev(qemuMonitorPtr mon,
return qemuMonitorJSONBlockStatsUpdateCapacityBlockdev(mon, stats);
}
+/* Updates "chk" to fill in size of the associated bitmap */
+int qemuMonitorUpdateCheckpointSize(qemuMonitorPtr mon,
+ virDomainCheckpointDefPtr chk)
+{
+ VIR_DEBUG("chk=%p", chk);
+
+ QEMU_CHECK_MONITOR(mon);
+
+ return qemuMonitorJSONUpdateCheckpointSize(mon, chk);
+}
+
int
qemuMonitorBlockResize(qemuMonitorPtr mon,
const char *device,
@@ -3936,6 +3947,19 @@ qemuMonitorNBDServerAdd(qemuMonitorPtr mon,
}
+int
+qemuMonitorNBDServerAddBitmap(qemuMonitorPtr mon,
+ const char *export,
+ const char *bitmap)
+{
+ VIR_DEBUG("export=%s, bitmap=%s", export, bitmap);
+
+ QEMU_CHECK_MONITOR(mon);
+
+ return qemuMonitorJSONNBDServerAddBitmap(mon, export, bitmap);
+}
+
+
int
qemuMonitorNBDServerStop(qemuMonitorPtr mon)
{
@@ -4429,3 +4453,47 @@ qemuMonitorGetPRManagerInfo(qemuMonitorPtr mon,
virHashFree(info);
return ret;
}
+
+int
+qemuMonitorAddBitmap(qemuMonitorPtr mon, const char *node,
+ const char *bitmap)
+{
+ VIR_DEBUG("node=%s bitmap=%s", node, bitmap);
+
+ QEMU_CHECK_MONITOR(mon);
+
+ return qemuMonitorJSONAddBitmap(mon, node, bitmap);
+}
+
+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, const char *src)
+{
+ VIR_DEBUG("node=%s dst=%s src=%s", node, dst, src);
+
+ 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_json.c b/src/qemu/qemu_monitor_json.c
index 29d0395979..a700585243 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1008,6 +1008,8 @@ qemuMonitorJSONHandleBlockJobImpl(qemuMonitorPtr mon,
type = VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT;
else if (STREQ(type_str, "mirror"))
type = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
+ else if (STREQ(type_str, "backup"))
+ type = VIR_DOMAIN_BLOCK_JOB_TYPE_BACKUP;
switch ((virConnectDomainEventBlockJobStatus) event) {
case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
@@ -2718,6 +2720,82 @@ int qemuMonitorJSONBlockResize(qemuMonitorPtr mon,
return ret;
}
+int qemuMonitorJSONUpdateCheckpointSize(qemuMonitorPtr mon,
+ virDomainCheckpointDefPtr chk)
+{
+ int ret = -1;
+ size_t i, j;
+ virJSONValuePtr devices;
+
+ if (!(devices = qemuMonitorJSONQueryBlock(mon)))
+ return -1;
+
+ for (i = 0; i < virJSONValueArraySize(devices); i++) {
+ virJSONValuePtr dev = virJSONValueArrayGet(devices, i);
+ virJSONValuePtr inserted;
+ virJSONValuePtr bitmaps = NULL;
+ const char *node;
+ virDomainCheckpointDiskDefPtr disk;
+
+ if (!(dev = qemuMonitorJSONGetBlockDev(devices, i)))
+ goto cleanup;
+
+ if (!(inserted = virJSONValueObjectGetObject(dev, "inserted")))
+ continue;
+ if (!(node = virJSONValueObjectGetString(inserted, "node-name"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("query-block device entry was not in expected
format"));
+ goto cleanup;
+ }
+
+ for (j = 0; j < chk->ndisks; j++) {
+ disk = &chk->disks[j];
+ if (disk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
+ continue;
+ if (STREQ(disk->node, node))
+ break;
+ }
+ if (j == chk->ndisks) {
+ VIR_DEBUG("query-block did not find node %s", node);
+ continue;
+ }
+ if (!(bitmaps = virJSONValueObjectGetArray(dev, "dirty-bitmaps"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("disk %s dirty bitmaps missing"), disk->name);
+ goto cleanup;
+ }
+ for (j = 0; j < virJSONValueArraySize(bitmaps); j++) {
+ virJSONValuePtr map = virJSONValueArrayGet(bitmaps, j);
+ const char *name;
+
+ if (!(name = virJSONValueObjectGetString(map, "name"))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("dirty bitmaps entry was not in expected
format"));
+ goto cleanup;
+ }
+ if (STRNEQ(name, disk->bitmap))
+ continue;
+ if (virJSONValueObjectGetNumberUlong(map, "count",
&disk->size) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("invalid bitmap count"));
+ goto cleanup;
+ }
+ break;
+ }
+ if (j == virJSONValueArraySize(bitmaps)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("disk %s dirty bitmap info missing"),
disk->name);
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ virJSONValueFree(devices);
+ return ret;
+}
+
int qemuMonitorJSONSetVNCPassword(qemuMonitorPtr mon,
const char *password)
{
@@ -6754,6 +6832,34 @@ qemuMonitorJSONNBDServerAdd(qemuMonitorPtr mon,
return ret;
}
+int
+qemuMonitorJSONNBDServerAddBitmap(qemuMonitorPtr mon,
+ const char *export,
+ const char *bitmap)
+{
+ int ret = -1;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ if (!(cmd = qemuMonitorJSONMakeCommand("x-nbd-server-add-bitmap",
+ "s:name", export,
+ "s:bitmap", bitmap,
+ NULL)))
+ return ret;
+
+ 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
qemuMonitorJSONNBDServerStop(qemuMonitorPtr mon)
{
@@ -8396,3 +8502,112 @@ qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon,
return ret;
}
+
+int
+qemuMonitorJSONAddBitmap(qemuMonitorPtr mon, const char *node,
+ const char *bitmap)
+{
+ int ret = -1;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ if (!(cmd = qemuMonitorJSONMakeCommand("block-dirty-bitmap-add",
+ "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
+qemuMonitorJSONEnableBitmap(qemuMonitorPtr mon, const char *node,
+ const char *bitmap)
+{
+ int ret = -1;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ if (!(cmd = qemuMonitorJSONMakeCommand("x-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, const char *src)
+{
+ int ret = -1;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ if (!(cmd = qemuMonitorJSONMakeCommand("x-block-dirty-bitmap-merge",
+ "s:node", node,
+ "s:dst_name", dst,
+ "s:src_name", src,
+ 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
+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;
+}
--
2.17.2