qemu: monitor: Fix usage of 'query-blockstats'

Commit bc24810c2c 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>
This commit is contained in:
Peter Krempa 2021-11-24 17:22:29 +01:00
parent 4b453bbb2f
commit d120fc5253
2 changed files with 50 additions and 4 deletions

View 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 * virJSONValue *
qemuMonitorJSONQueryBlockstats(qemuMonitor *mon, qemuMonitorJSONQueryBlockstats(qemuMonitor *mon,
bool queryNodes) bool queryNodes)
@ -2475,13 +2499,14 @@ qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitor *mon,
int nstats = 0; int nstats = 0;
int rc; int rc;
size_t i; 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; return -1;
for (i = 0; i < virJSONValueArraySize(devices); i++) { for (i = 0; i < virJSONValueArraySize(blockstatsDevices); i++) {
virJSONValue *dev = virJSONValueArrayGet(devices, i); virJSONValue *dev = virJSONValueArrayGet(blockstatsDevices, i);
const char *dev_name; const char *dev_name;
if (!dev || virJSONValueGetType(dev) != VIR_JSON_TYPE_OBJECT) { if (!dev || virJSONValueGetType(dev) != VIR_JSON_TYPE_OBJECT) {
@ -2505,6 +2530,25 @@ qemuMonitorJSONGetAllBlockStatsInfo(qemuMonitor *mon,
nstats = rc; 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; return nstats;
} }

View File

@ -1615,6 +1615,8 @@ testQemuMonitorJSONqemuMonitorJSONGetAllBlockStatsInfo(const void *opaque)
if (qemuMonitorTestAddItem(test, "query-blockstats", reply) < 0) if (qemuMonitorTestAddItem(test, "query-blockstats", reply) < 0)
return -1; return -1;
if (qemuMonitorTestAddItem(test, "query-blockstats", reply) < 0)
return -1;
#define CHECK0FULL(var, value, varformat, valformat) \ #define CHECK0FULL(var, value, varformat, valformat) \
if (stats->var != value) { \ if (stats->var != value) { \