[libvirt] [PATCH v3 15/20] backup: Add new qemu monitor interactions

Eric Blake eblake at redhat.com
Thu Oct 25 19:20:16 UTC 2018


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




More information about the libvir-list mailing list