]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: monitor: Fix usage of 'query-blockstats'
authorPeter Krempa <pkrempa@redhat.com>
Wed, 24 Nov 2021 16:22:29 +0000 (17:22 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Thu, 25 Nov 2021 14:27:56 +0000 (15:27 +0100)
Commit bc24810c2cab modified code querying blockstats to use the
'query-nodes' parameter so that we can fetch stats also for images which
are not attached to a frontend such as block copy and backup scratch
images.

Unfortunately that broke the old blockstats because if 'query-nodes' is
enabled qemu doesn't output the 'qdev' parameter which our code used for
matching to the disk and also qemu neglects to populate the frontend
stats at all so we can't even switch to using nodename for matching.

To fix this we need to do two calls, one with 'query-nodes' disabled
using the old logic to populate everything and then an additional one
which populates all the remaining images.

Closes: https://gitlab.com/libvirt/libvirt/-/issues/246
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Tested-by: Erik Skultety <eskultet@redhat.com>
src/qemu/qemu_monitor_json.c
tests/qemumonitorjsontest.c

index 3030cff6646896e4c57fa67281a3aa28c3c189c2..56f0b22b2ae90c914bd74bd65ccb593214aa0963 100644 (file)
@@ -2446,6 +2446,30 @@ qemuMonitorJSONGetOneBlockStatsInfo(virJSONValue *dev,
 }
 
 
+static int
+qemuMonitorJSONGetOneBlockStatsNodeInfo(virJSONValue *dev,
+                                        GHashTable *hash)
+{
+    qemuBlockStats *bstats = NULL;
+    int nstats = 0;
+    const char *nodename = NULL;
+
+    if (!(nodename = virJSONValueObjectGetString(dev, "node-name")))
+        return 0;
+
+    /* we already have the stats */
+    if (g_hash_table_contains(hash, nodename))
+        return 0;
+
+    if (!(bstats = qemuMonitorJSONBlockStatsCollectData(dev, &nstats)))
+        return -1;
+
+    g_hash_table_insert(hash, g_strdup(nodename), bstats);
+
+    return nstats;
+}
+
+
 virJSONValue *
 qemuMonitorJSONQueryBlockstats(qemuMonitor *mon,
                                bool queryNodes)
@@ -2475,13 +2499,14 @@ qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitor *mon,
     int nstats = 0;
     int rc;
     size_t i;
-    g_autoptr(virJSONValue) devices = NULL;
+    g_autoptr(virJSONValue) blockstatsDevices = NULL;
+    g_autoptr(virJSONValue) blockstatsNodes = NULL;
 
-    if (!(devices = qemuMonitorJSONQueryBlockstats(mon, true)))
+    if (!(blockstatsDevices = qemuMonitorJSONQueryBlockstats(mon, false)))
         return -1;
 
-    for (i = 0; i < virJSONValueArraySize(devices); i++) {
-        virJSONValue *dev = virJSONValueArrayGet(devices, i);
+    for (i = 0; i < virJSONValueArraySize(blockstatsDevices); i++) {
+        virJSONValue *dev = virJSONValueArrayGet(blockstatsDevices, i);
         const char *dev_name;
 
         if (!dev || virJSONValueGetType(dev) != VIR_JSON_TYPE_OBJECT) {
@@ -2505,6 +2530,25 @@ qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitor *mon,
             nstats = rc;
     }
 
+    if (!(blockstatsNodes = qemuMonitorJSONQueryBlockstats(mon, true)))
+        return -1;
+
+    for (i = 0; i < virJSONValueArraySize(blockstatsNodes); i++) {
+        virJSONValue *dev = virJSONValueArrayGet(blockstatsNodes, i);
+
+        if (!dev || virJSONValueGetType(dev) != VIR_JSON_TYPE_OBJECT) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("blockstats device entry was not in expected format"));
+            return -1;
+        }
+
+        if ((rc = qemuMonitorJSONGetOneBlockStatsNodeInfo(dev, hash)) < 0)
+            return -1;
+
+        if (rc > nstats)
+            nstats = rc;
+    }
+
     return nstats;
 }
 
index 0de523007bed0f8b23880fa2e22f319fe8e186c2..bcf5caa9a41e533fb55b1d7d42fc590155eebef4 100644 (file)
@@ -1615,6 +1615,8 @@ testQemuMonitorJSONqemuMonitorJSONGetAllBlockStatsInfo(const void *opaque)
 
     if (qemuMonitorTestAddItem(test, "query-blockstats", reply) < 0)
         return -1;
+    if (qemuMonitorTestAddItem(test, "query-blockstats", reply) < 0)
+        return -1;
 
 #define CHECK0FULL(var, value, varformat, valformat) \
     if (stats->var != value) { \