[libvirt] [PATCH 23/23] qemu: block: Add code to detect node names when necessary

Peter Krempa pkrempa at redhat.com
Wed Mar 15 16:37:35 UTC 2017


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




More information about the libvir-list mailing list