Detect the node names when setting block threshold and when reconnecting
or when they are cleared when a block job finishes. This operation will
become a no-op once we fully support node names.
---
src/qemu/qemu_block.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_block.h | 4 ++
src/qemu/qemu_blockjob.c | 2 +
src/qemu/qemu_driver.c | 5 +++
src/qemu/qemu_process.c | 4 ++
5 files changed, 113 insertions(+)
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
index 91c04ab7f..ebf11ceb6 100644
--- a/src/qemu/qemu_block.c
+++ b/src/qemu/qemu_block.c
@@ -278,3 +278,101 @@ qemuBlockNodeNameGetBackingChain(virJSONValuePtr json)
return ret;
}
+
+
+static void
+qemuBlockDiskClearDetectedNodes(virDomainDiskDefPtr disk)
+{
+ virStorageSourcePtr next = disk->src;
+
+ while (next) {
+ VIR_FREE(next->nodeformat);
+ VIR_FREE(next->nodebacking);
+
+ next = next->backingStore;
+ }
+}
+
+
+static int
+qemuBlockDiskDetectNodes(virDomainDiskDefPtr disk,
+ const char *parentnode,
+ virHashTablePtr table)
+{
+ qemuBlockNodeNameBackingChainDataPtr entry = NULL;
+ virStorageSourcePtr src = disk->src;
+
+ /* don't attempt the detection if the top level already has node names */
+ if (!parentnode || src->nodeformat || src->nodebacking)
+ return 0;
+
+ while (src && parentnode) {
+ if (!(entry = virHashLookup(table, parentnode)))
+ break;
+
+ if (src->nodeformat || src->nodebacking) {
+ if (STRNEQ_NULLABLE(src->nodeformat, entry->nodeformat) ||
+ STRNEQ_NULLABLE(src->nodebacking, entry->nodestorage))
+ goto error;
+
+ break;
+ } else {
+ if (VIR_STRDUP(src->nodeformat, entry->nodeformat) < 0 ||
+ VIR_STRDUP(src->nodebacking, entry->nodestorage) < 0)
+ goto error;
+ }
+
+ parentnode = entry->nodebacking;
+ src = src->backingStore;
+ }
+
+ return 0;
+
+ error:
+ qemuBlockDiskClearDetectedNodes(disk);
+ return -1;
+}
+
+
+int
+qemuBlockNodeNamesDetect(virQEMUDriverPtr driver,
+ virDomainObjPtr vm)
+{
+ virHashTablePtr disktable = NULL;
+ virHashTablePtr nodenametable = NULL;
+ virJSONValuePtr data = NULL;
+ virDomainDiskDefPtr disk;
+ struct qemuDomainDiskInfo *info;
+ size_t i;
+ int ret = -1;
+
+ qemuDomainObjEnterMonitor(driver, vm);
+
+ disktable = qemuMonitorGetBlockInfo(qemuDomainGetMonitor(vm));
+ data = qemuMonitorQueryNamedBlockNodes(qemuDomainGetMonitor(vm));
+
+ if (qemuDomainObjExitMonitor(driver, vm) < 0 || !data || !disktable)
+ goto cleanup;
+
+ if (!(nodenametable = qemuBlockNodeNameGetBackingChain(data)))
+ goto cleanup;
+
+ for (i = 0; i < vm->def->ndisks; i++) {
+ disk = vm->def->disks[i];
+
+ if (!(info = virHashLookup(disktable, disk->info.alias)))
+ continue;
+
+ if (qemuBlockDiskDetectNodes(disk, info->nodename, nodenametable) < 0)
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ virJSONValueFree(data);
+ virHashFree(nodenametable);
+ virHashFree(disktable);
+
+ return ret;
+}
diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h
index 26f5ae062..56f4a74dd 100644
--- a/src/qemu/qemu_block.h
+++ b/src/qemu/qemu_block.h
@@ -44,4 +44,8 @@ struct qemuBlockNodeNameBackingChainData {
virHashTablePtr
qemuBlockNodeNameGetBackingChain(virJSONValuePtr data);
+int
+qemuBlockNodeNamesDetect(virQEMUDriverPtr driver,
+ virDomainObjPtr vm);
+
#endif /* __QEMU_BLOCK_H__ */
diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
index 985fae1e9..0601e68da 100644
--- a/src/qemu/qemu_blockjob.c
+++ b/src/qemu/qemu_blockjob.c
@@ -24,6 +24,7 @@
#include "internal.h"
#include "qemu_blockjob.h"
+#include "qemu_block.h"
#include "qemu_domain.h"
#include "conf/domain_conf.h"
@@ -166,6 +167,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver,
disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk,
true, true));
+ ignore_value(qemuBlockNodeNamesDetect(driver, vm));
diskPriv->blockjob = false;
break;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d8e3ddf57..22cf866cd 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -46,6 +46,7 @@
#include "qemu_driver.h"
#include "qemu_agent.h"
#include "qemu_alias.h"
+#include "qemu_block.h"
#include "qemu_conf.h"
#include "qemu_capabilities.h"
#include "qemu_command.h"
@@ -20333,6 +20334,10 @@ qemuDomainSetBlockThreshold(virDomainPtr dom,
if (!(src = qemuDomainGetStorageSourceByDevstr(dev, vm->def)))
goto endjob;
+ if (!src->nodebacking &&
+ qemuBlockNodeNamesDetect(driver, vm) < 0)
+ goto endjob;
+
if (!src->nodebacking) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
_("threshold currently can't be set for block device
'%s'"),
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d40deea10..d8626d410 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -35,6 +35,7 @@
#include "qemu_process.h"
#include "qemu_processpriv.h"
#include "qemu_alias.h"
+#include "qemu_block.h"
#include "qemu_domain.h"
#include "qemu_domain_address.h"
#include "qemu_cgroup.h"
@@ -3474,6 +3475,9 @@ qemuProcessReconnect(void *opaque)
if (qemuProcessRefreshDisks(driver, obj, QEMU_ASYNC_JOB_NONE) < 0)
goto error;
+ if (qemuBlockNodeNamesDetect(driver, obj) < 0)
+ goto error;
+
if (qemuRefreshVirtioChannelState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0)
goto error;
--
2.12.0