]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: block: Add code to detect node names when necessary
authorPeter Krempa <pkrempa@redhat.com>
Wed, 15 Mar 2017 12:03:21 +0000 (13:03 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Mon, 27 Mar 2017 08:35:19 +0000 (10:35 +0200)
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
src/qemu/qemu_block.h
src/qemu/qemu_blockjob.c
src/qemu/qemu_driver.c
src/qemu/qemu_process.c

index 91c04ab7f233429f13a808a1d0cdb5f7d14bc0bb..e3190784212d5f43aee9bd859e82820bcd0b39ff 100644 (file)
@@ -278,3 +278,105 @@ 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)
+{
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virHashTablePtr disktable = NULL;
+    virHashTablePtr nodenametable = NULL;
+    virJSONValuePtr data = NULL;
+    virDomainDiskDefPtr disk;
+    struct qemuDomainDiskInfo *info;
+    size_t i;
+    int ret = -1;
+
+    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QUERY_NAMED_BLOCK_NODES))
+        return 0;
+
+    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;
+}
index 26f5ae06255d1273c5e78dce17116bd26b6d37f0..56f4a74dd913fc864373f3720d75b401a2f48854 100644 (file)
@@ -44,4 +44,8 @@ struct qemuBlockNodeNameBackingChainData {
 virHashTablePtr
 qemuBlockNodeNameGetBackingChain(virJSONValuePtr data);
 
+int
+qemuBlockNodeNamesDetect(virQEMUDriverPtr driver,
+                         virDomainObjPtr vm);
+
 #endif /* __QEMU_BLOCK_H__ */
index 985fae1e96ebf2aee5da7927cfda1431fa86af4c..0601e68da852b78ae8bf7061aa42c39de1dfc25d 100644 (file)
@@ -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;
 
index f6403e43c1070c788f366cf9230d1fd0c5f60c5d..2c2041912409bf3751c64266c6b229fdb2ebae35 100644 (file)
@@ -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"
@@ -20354,6 +20355,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'"),
index 6f72fb4d791dfd841f4c533b182465da8beb1fa1..b0e3e90964bfe7b44c7631a4284f1185dcf80b2c 100644 (file)
@@ -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"
@@ -3486,6 +3487,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;