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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list