Blob Blame History Raw
From 10561682792d0ea540235636e80b0b3e85ce412a Mon Sep 17 00:00:00 2001
Message-Id: <10561682792d0ea540235636e80b0b3e85ce412a@dist-git>
From: Peter Krempa <pkrempa@redhat.com>
Date: Wed, 28 Jul 2021 17:37:21 +0200
Subject: [PATCH] RHEL: Enable usage of x-blockdev-reopen
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

RHEL-only

Introduce a new capability QEMU_CAPS_BLOCKDEV_REOPEN_COM_REDHAT_AV_8_2_0_API
based on the presence of '__com.redhat_rhel-av-8_2_0-api' feature for
'x-blockdev-reopen' which states that reopen works for what libvirt
is going to use it and wire up code to call the x- prefixed command.

This implementation will become dormant once qemu starts supporting
upstream-stable blockdev-reopen.

https://bugzilla.redhat.com/show_bug.cgi?id=1799013

Starting with libvirt-7.6, upstream has adapted to the new format of
arguments so this patch was modified to support blockdev-reopen which
takes an array of nodes to reopen.

https://bugzilla.redhat.com/show_bug.cgi?id=1929765
Message-Id: <3fcde2fc6add36d5276ae224caf18adc8bca7d48.1627486352.git.pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
---
 src/qemu/qemu_block.c        | 24 +++++++++++++++---------
 src/qemu/qemu_block.h        |  3 ++-
 src/qemu/qemu_capabilities.c | 11 +++++++++++
 src/qemu/qemu_capabilities.h |  1 +
 src/qemu/qemu_monitor.c      |  5 +++--
 src/qemu/qemu_monitor.h      |  3 ++-
 src/qemu/qemu_monitor_json.c | 12 +++++++++---
 src/qemu/qemu_monitor_json.h |  3 ++-
 tests/qemumonitorjsontest.c  |  2 +-
 9 files changed, 46 insertions(+), 18 deletions(-)

diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
index 53a0b919f9..8871eb9fdc 100644
--- a/src/qemu/qemu_block.c
+++ b/src/qemu/qemu_block.c
@@ -3322,7 +3322,8 @@ qemuBlockBitmapsHandleCommitFinish(virStorageSource *topsrc,
 
 int
 qemuBlockReopenFormatMon(qemuMonitor *mon,
-                         virStorageSource *src)
+                         virStorageSource *src,
+                         bool downstream)
 {
     g_autoptr(virJSONValue) reopenprops = NULL;
     g_autoptr(virJSONValue) srcprops = NULL;
@@ -3331,15 +3332,19 @@ qemuBlockReopenFormatMon(qemuMonitor *mon,
     if (!(srcprops = qemuBlockStorageSourceGetBlockdevProps(src, src->backingStore)))
         return -1;
 
-    if (virJSONValueArrayAppend(reopenoptions, &srcprops) < 0)
-        return -1;
+    if (downstream) {
+        reopenprops = g_steal_pointer(&srcprops);
+    } else {
+        if (virJSONValueArrayAppend(reopenoptions, &srcprops) < 0)
+            return -1;
 
-    if (virJSONValueObjectAdd(&reopenprops,
-                              "a:options", &reopenoptions,
-                              NULL) < 0)
-        return -1;
+        if (virJSONValueObjectAdd(&reopenprops,
+                                  "a:options", &reopenoptions,
+                                  NULL) < 0)
+            return -1;
+    }
 
-    if (qemuMonitorBlockdevReopen(mon, &reopenprops) < 0)
+    if (qemuMonitorBlockdevReopen(mon, &reopenprops, downstream) < 0)
         return -1;
 
     return 0;
@@ -3363,6 +3368,7 @@ qemuBlockReopenFormat(virDomainObj *vm,
 {
     qemuDomainObjPrivate *priv = vm->privateData;
     virQEMUDriver *driver = priv->driver;
+    bool downstream = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN_COM_REDHAT_AV_8_2_0_API);
     int rc;
 
     /* If we are lacking the object here, qemu might have opened an image with
@@ -3376,7 +3382,7 @@ qemuBlockReopenFormat(virDomainObj *vm,
     if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
         return -1;
 
-    rc = qemuBlockReopenFormatMon(priv->mon, src);
+    rc = qemuBlockReopenFormatMon(priv->mon, src, downstream);
 
     if (qemuDomainObjExitMonitor(driver, vm) < 0 || rc < 0)
         return -1;
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
index 54601a48a9..88fc9974c4 100644
--- a/src/qemu/qemu_block.h
+++ b/src/qemu/qemu_block.h
@@ -268,7 +268,8 @@ qemuBlockBitmapsHandleCommitFinish(virStorageSource *topsrc,
 /* only for use in qemumonitorjsontest */
 int
 qemuBlockReopenFormatMon(qemuMonitor *mon,
-                         virStorageSource *src);
+                         virStorageSource *src,
+                         bool downstream);
 
 int
 qemuBlockReopenReadWrite(virDomainObj *vm,
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 30a557706b..f6ea51d17e 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -651,6 +651,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
               "device.json", /* QEMU_CAPS_DEVICE_JSON */
               "query-dirty-rate", /* QEMU_CAPS_QUERY_DIRTY_RATE */
               "rbd-encryption", /* QEMU_CAPS_RBD_ENCRYPTION */
+              "blockdev-reopen.__com.redhat_rhel-av-8_2_0-api", /* QEMU_CAPS_BLOCKDEV_REOPEN_COM_REDHAT_AV_8_2_0_API */
     );
 
 
@@ -1536,6 +1537,7 @@ static struct virQEMUCapsDevicePropsFlags virQEMUCapsDevicePropsVhostUserFS[] =
 /* see documentation for virQEMUQAPISchemaPathGet for the query format */
 static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = {
     { "block-commit/arg-type/*top",  QEMU_CAPS_ACTIVE_COMMIT },
+    { "x-blockdev-reopen/$__com.redhat_rhel-av-8_2_0-api", QEMU_CAPS_BLOCKDEV_REOPEN_COM_REDHAT_AV_8_2_0_API },
     { "blockdev-add/arg-type/options/+gluster/debug-level", QEMU_CAPS_GLUSTER_DEBUG_LEVEL},
     { "blockdev-add/arg-type/+gluster/debug", QEMU_CAPS_GLUSTER_DEBUG_LEVEL},
     { "blockdev-add/arg-type/+vxhs", QEMU_CAPS_VXHS},
@@ -5189,6 +5191,15 @@ virQEMUCapsInitProcessCaps(virQEMUCaps *qemuCaps)
         qemuCaps->arch == VIR_ARCH_MIPS)
         virQEMUCapsSet(qemuCaps, QEMU_CAPS_SCSI_NCR53C90);
 
+    /* RHEL-only:
+     * - if upstream blockdev-reopen is enabled, clear the downstream flag
+     * - if the downstream flag is present but not the upstream, assert the upstream flag too
+     */
+    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN))
+        virQEMUCapsClear(qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN_COM_REDHAT_AV_8_2_0_API);
+    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN_COM_REDHAT_AV_8_2_0_API))
+        virQEMUCapsSet(qemuCaps, QEMU_CAPS_BLOCKDEV_REOPEN);
+
     virQEMUCapsInitProcessCapsInterlock(qemuCaps);
 }
 
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 61bdbdb2ac..79c05d603c 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -631,6 +631,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */
     QEMU_CAPS_DEVICE_JSON, /* -device accepts JSON */
     QEMU_CAPS_QUERY_DIRTY_RATE, /* accepts query-dirty-rate */
     QEMU_CAPS_RBD_ENCRYPTION, /* Ceph RBD encryption support */
+    QEMU_CAPS_BLOCKDEV_REOPEN_COM_REDHAT_AV_8_2_0_API, /* downstream support for blockdev reopen in rhel-av-8.2.0 */
 
     QEMU_CAPS_LAST /* this must always be the last item */
 } virQEMUCapsFlags;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 26b59801b8..ad00e471d6 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4291,14 +4291,15 @@ qemuMonitorBlockdevAdd(qemuMonitor *mon,
 
 int
 qemuMonitorBlockdevReopen(qemuMonitor *mon,
-                          virJSONValue **props)
+                          virJSONValue **props,
+                          bool downstream)
 {
     VIR_DEBUG("props=%p (node-name=%s)", *props,
               NULLSTR(virJSONValueObjectGetString(*props, "node-name")));
 
     QEMU_CHECK_MONITOR(mon);
 
-    return qemuMonitorJSONBlockdevReopen(mon, props);
+    return qemuMonitorJSONBlockdevReopen(mon, props, downstream);
 }
 
 
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 99ecebc648..acbc49cc69 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1422,7 +1422,8 @@ int qemuMonitorBlockdevAdd(qemuMonitor *mon,
                            virJSONValue **props);
 
 int qemuMonitorBlockdevReopen(qemuMonitor *mon,
-                              virJSONValue **props);
+                              virJSONValue **props,
+                              bool downstream);
 
 int qemuMonitorBlockdevDel(qemuMonitor *mon,
                            const char *nodename);
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 56f0b22b2a..efaee0d28c 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -8009,13 +8009,19 @@ qemuMonitorJSONBlockdevAdd(qemuMonitor *mon,
 
 int
 qemuMonitorJSONBlockdevReopen(qemuMonitor *mon,
-                              virJSONValue **props)
+                              virJSONValue **props,
+                              bool downstream)
 {
     g_autoptr(virJSONValue) cmd = NULL;
     g_autoptr(virJSONValue) reply = NULL;
 
-    if (!(cmd = qemuMonitorJSONMakeCommandInternal("blockdev-reopen", props)))
-        return -1;
+    if (downstream) {
+        if (!(cmd = qemuMonitorJSONMakeCommandInternal("x-blockdev-reopen", props)))
+            return -1;
+    } else {
+        if (!(cmd = qemuMonitorJSONMakeCommandInternal("blockdev-reopen", props)))
+            return -1;
+    }
 
     if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
         return -1;
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index f7fb13f56c..61389d9dd8 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -594,7 +594,8 @@ int qemuMonitorJSONBlockdevAdd(qemuMonitor *mon,
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
 int qemuMonitorJSONBlockdevReopen(qemuMonitor *mon,
-                                  virJSONValue **props)
+                                  virJSONValue **props,
+                                  bool downstream)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
 
 int qemuMonitorJSONBlockdevDel(qemuMonitor *mon,
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index bcf5caa9a4..b6cec5e362 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -2784,7 +2784,7 @@ testQemuMonitorJSONBlockdevReopen(const void *opaque)
     if (qemuMonitorTestAddItem(test, "blockdev-reopen", "{\"return\":{}}") < 0)
         return -1;
 
-    if (qemuBlockReopenFormatMon(qemuMonitorTestGetMonitor(test), src) < 0)
+    if (qemuBlockReopenFormatMon(qemuMonitorTestGetMonitor(test), src, false) < 0)
         return -1;
 
     return 0;
-- 
2.34.1