Add some monitor commands to be used during backup/checkpoint
operations:
- another facet to query-block for learning bitmap size
- new export and bitmap parameters to nbd-server-add
- new block-dirty-bitmap-{add,enable,disable,merge} functions
Also add two capabilities for testing that they are supported;
using block-dirty-bitmap-merge as the generic witness of checkpoint
support (since all of the functionalities were added in the same
qemu 4.0 release), and the bitmap parameter to nbd-server-add for
pull-mode backup support. Even though both capabilities are
likely to be present or absent together (that is, it is unlikely
to encounter a qemu that backports only one of the two), it still
makes sense to keep two capabilities as the two uses are
orthogonal (full backups don't require checkpoints, push mode
backups don't require NBD bitmap support, and checkpoints can
be used for more than just incremental backups).
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
src/qemu/qemu_capabilities.h | 4 +
src/qemu/qemu_monitor.h | 21 +-
src/qemu/qemu_monitor_json.h | 19 +-
src/qemu/qemu_capabilities.c | 6 +
src/qemu/qemu_migration.c | 2 +-
src/qemu/qemu_monitor.c | 65 +++++-
src/qemu/qemu_monitor_json.c | 199 +++++++++++++++++-
.../caps_4.0.0.riscv32.xml | 2 +
.../caps_4.0.0.riscv64.xml | 2 +
tests/qemumonitorjsontest.c | 2 +-
10 files changed, 314 insertions(+), 8 deletions(-)
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 1d677f6a06..144088ecec 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -506,6 +506,10 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check
*/
QEMU_CAPS_DEVICE_NVDIMM_UNARMED, /* -device nvdimm,unarmed= */
QEMU_CAPS_SCSI_DISK_DEVICE_ID, /* 'device_id' property of scsi disk */
QEMU_CAPS_VIRTIO_PCI_TRANSITIONAL, /* virtio *-pci-{non-}transitional devices */
+ QEMU_CAPS_BITMAP_MERGE, /* block-dirty-bitmap-merge */
+
+ /* 330 */
+ QEMU_CAPS_NBD_BITMAP, /* nbd-server-add supports bitmap */
QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags;
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index fd7dcc9196..7eb0d067b9 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -25,6 +25,7 @@
# include "internal.h"
# include "domain_conf.h"
+# include "checkpoint_conf.h"
# include "virbitmap.h"
# include "virhash.h"
# include "virjson.h"
@@ -629,6 +630,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,
@@ -647,6 +651,19 @@ 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
@@ -1099,7 +1116,9 @@ int qemuMonitorNBDServerStart(qemuMonitorPtr mon,
const char *tls_alias);
int qemuMonitorNBDServerAdd(qemuMonitorPtr mon,
const char *deviceID,
- bool writable);
+ const char *export,
+ bool writable,
+ 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 62772228fe..076f7b6dde 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -98,6 +98,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,
@@ -465,7 +468,9 @@ int qemuMonitorJSONNBDServerStart(qemuMonitorPtr mon,
const char *tls_alias);
int qemuMonitorJSONNBDServerAdd(qemuMonitorPtr mon,
const char *deviceID,
- bool writable);
+ const char *export,
+ bool writable,
+ const char *bitmap);
int qemuMonitorJSONNBDServerStop(qemuMonitorPtr mon);
int qemuMonitorJSONGetTPMModels(qemuMonitorPtr mon,
char ***tpmmodels)
@@ -578,4 +583,16 @@ int qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon,
virHashTablePtr 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/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index c9700193fd..e5b4daf6ee 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -523,6 +523,10 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
"nvdimm.unarmed",
"scsi-disk.device_id",
"virtio-pci-non-transitional",
+ "bitmap-merge",
+
+ /* 330 */
+ "nbd-bitmap",
);
@@ -978,6 +982,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = {
{ "query-cpus-fast", QEMU_CAPS_QUERY_CPUS_FAST },
{ "qom-list-properties", QEMU_CAPS_QOM_LIST_PROPERTIES },
{ "blockdev-del", QEMU_CAPS_BLOCKDEV_DEL },
+ { "block-dirty-bitmap-merge", QEMU_CAPS_BITMAP_MERGE },
};
struct virQEMUCapsStringFlags virQEMUCapsMigration[] = {
@@ -1272,6 +1277,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] =
{
{ "block-commit/arg-type/*top", QEMU_CAPS_ACTIVE_COMMIT },
{ "query-iothreads/ret-type/poll-max-ns", QEMU_CAPS_IOTHREAD_POLLING },
{ "query-display-options/ret-type/+egl-headless/rendernode",
QEMU_CAPS_EGL_HEADLESS_RENDERNODE },
+ { "nbd-server-add/arg-type/bitmap", QEMU_CAPS_NBD_BITMAP },
};
typedef struct _virQEMUCapsObjectTypeProps virQEMUCapsObjectTypeProps;
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 362b79e567..d1f6692835 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -417,7 +417,7 @@ qemuMigrationDstStartNBDServer(virQEMUDriverPtr driver,
goto exit_monitor;
}
- if (qemuMonitorNBDServerAdd(priv->mon, diskAlias, true) < 0)
+ if (qemuMonitorNBDServerAdd(priv->mon, diskAlias, NULL, true, NULL) < 0)
goto exit_monitor;
if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 8bd4d4d761..906ed50466 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2342,6 +2342,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,
@@ -3945,13 +3956,17 @@ qemuMonitorNBDServerStart(qemuMonitorPtr mon,
int
qemuMonitorNBDServerAdd(qemuMonitorPtr mon,
const char *deviceID,
- bool writable)
+ const char *export,
+ bool writable,
+ const char *bitmap)
{
- VIR_DEBUG("deviceID=%s", deviceID);
+ VIR_DEBUG("deviceID=%s, export=%s, bitmap=%s", deviceID, NULLSTR(export),
+ NULLSTR(bitmap));
QEMU_CHECK_MONITOR(mon);
- return qemuMonitorJSONNBDServerAdd(mon, deviceID, writable);
+ return qemuMonitorJSONNBDServerAdd(mon, deviceID, export, writable,
+ bitmap);
}
@@ -4478,3 +4493,47 @@ qemuMonitorGetPRManagerInfo(qemuMonitorPtr mon,
virHashFree(info);
return ret;
}
+
+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 src=%p", 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 cf474eb6c8..09f37cc37b 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1011,6 +1011,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:
@@ -2755,6 +2757,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(chk->dom->disks[disk->idx]->src->nodeformat, 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)
{
@@ -4738,6 +4816,8 @@ qemuMonitorJSONParseBlockJobInfo(virHashTablePtr blockJobs,
info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT;
else if (STREQ(type, "mirror"))
info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
+ else if (STREQ(type, "backup"))
+ info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_BACKUP;
else
info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
@@ -6767,15 +6847,20 @@ qemuMonitorJSONNBDServerStart(qemuMonitorPtr mon,
int
qemuMonitorJSONNBDServerAdd(qemuMonitorPtr mon,
const char *deviceID,
- bool writable)
+ const char *export,
+ bool writable,
+ const char *bitmap)
{
int ret = -1;
virJSONValuePtr cmd;
virJSONValuePtr reply = NULL;
+ /* Note: bitmap must be NULL if QEMU_CAPS_NBD_BITMAP is lacking */
if (!(cmd = qemuMonitorJSONMakeCommand("nbd-server-add",
"s:device", deviceID,
+ "S:name", export,
"b:writable", writable,
+ "S:bitmap", bitmap,
NULL)))
return ret;
@@ -8484,3 +8569,115 @@ qemuMonitorJSONGetPRManagerInfo(qemuMonitorPtr mon,
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/tests/qemucapabilitiesdata/caps_4.0.0.riscv32.xml
b/tests/qemucapabilitiesdata/caps_4.0.0.riscv32.xml
index 396e3019a0..d7e51e5106 100644
--- a/tests/qemucapabilitiesdata/caps_4.0.0.riscv32.xml
+++ b/tests/qemucapabilitiesdata/caps_4.0.0.riscv32.xml
@@ -161,6 +161,8 @@
<flag name='memory-backend-file.align'/>
<flag name='memory-backend-file.pmem'/>
<flag name='virtio-pci-non-transitional'/>
+ <flag name='bitmap-merge'/>
+ <flag name='nbd-bitmap'/>
<version>3001050</version>
<kvmVersion>0</kvmVersion>
<microcodeVersion>0</microcodeVersion>
diff --git a/tests/qemucapabilitiesdata/caps_4.0.0.riscv64.xml
b/tests/qemucapabilitiesdata/caps_4.0.0.riscv64.xml
index addc6ae4d3..4a16a1981d 100644
--- a/tests/qemucapabilitiesdata/caps_4.0.0.riscv64.xml
+++ b/tests/qemucapabilitiesdata/caps_4.0.0.riscv64.xml
@@ -161,6 +161,8 @@
<flag name='memory-backend-file.align'/>
<flag name='memory-backend-file.pmem'/>
<flag name='virtio-pci-non-transitional'/>
+ <flag name='bitmap-merge'/>
+ <flag name='nbd-bitmap'/>
<version>3001050</version>
<kvmVersion>0</kvmVersion>
<microcodeVersion>0</microcodeVersion>
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index 1a8a31717f..c5eac06cc1 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -1354,7 +1354,7 @@ GEN_TEST_FUNC(qemuMonitorJSONDrivePivot, "vdb")
GEN_TEST_FUNC(qemuMonitorJSONScreendump, "devicename", 1,
"/foo/bar")
GEN_TEST_FUNC(qemuMonitorJSONOpenGraphics, "spice", "spicefd",
false)
GEN_TEST_FUNC(qemuMonitorJSONNBDServerStart, "localhost", 12345,
"test-alias")
-GEN_TEST_FUNC(qemuMonitorJSONNBDServerAdd, "vda", true)
+GEN_TEST_FUNC(qemuMonitorJSONNBDServerAdd, "vda", NULL, true, NULL)
GEN_TEST_FUNC(qemuMonitorJSONDetachCharDev, "serial1")
GEN_TEST_FUNC(qemuMonitorJSONBlockdevTrayOpen, "foodev", true)
GEN_TEST_FUNC(qemuMonitorJSONBlockdevTrayClose, "foodev")
--
2.20.1