[PATCH 5/6] qemu: Implement support for configuring iothread to virtqueue mapping for disks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add validation and formatting of the commandline arguments for
'iothread-vq-mapping' parameter. The validation logic mirrors waht qemu
allows.

Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx>
---
 src/hypervisor/domain_driver.c |  15 ++++-
 src/qemu/qemu_command.c        |  45 +++++++++++++
 src/qemu/qemu_validate.c       | 117 +++++++++++++++++++++++++++++----
 3 files changed, 165 insertions(+), 12 deletions(-)

diff --git a/src/hypervisor/domain_driver.c b/src/hypervisor/domain_driver.c
index d9469ad6f9..85d68b056c 100644
--- a/src/hypervisor/domain_driver.c
+++ b/src/hypervisor/domain_driver.c
@@ -555,7 +555,20 @@ virDomainDriverDelIOThreadCheck(virDomainDef *def,
     }

     for (i = 0; i < def->ndisks; i++) {
-        if (def->disks[i]->iothread == iothread_id) {
+        GSList *n;
+        bool inuse = false;
+
+        for (n = def->disks[i]->iothreads; n; n = n->next) {
+            virDomainDiskIothreadDef *iothread = n->data;
+
+            if (iothread->id == iothread_id) {
+                inuse = true;
+                break;
+            }
+        }
+
+        if (inuse ||
+            def->disks[i]->iothread == iothread_id) {
             virReportError(VIR_ERR_INVALID_ARG,
                            _("cannot remove IOThread %1$u since it is being used by disk '%2$s'"),
                            iothread_id, def->disks[i]->dst);
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index bc285c0b6f..147b0eabb1 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1731,6 +1731,45 @@ qemuBuildDriveStr(virDomainDiskDef *disk)
 }


+static virJSONValue *
+qemuBuildDiskDeviceIothreadMappingProps(GSList *iothreads)
+{
+    g_autoptr(virJSONValue) ret = virJSONValueNewArray();
+    GSList *n;
+
+    for (n = iothreads; n; n = n->next) {
+        virDomainDiskIothreadDef *ioth = n->data;
+        g_autoptr(virJSONValue) props = NULL;
+        g_autoptr(virJSONValue) queues = NULL;
+        g_autofree char *alias = g_strdup_printf("iothread%u", ioth->id);
+        size_t i;
+
+        if (ioth->nqueues > 0) {
+            queues = virJSONValueNewArray();
+
+            for (i = 0; i < ioth->nqueues; i++) {
+                g_autoptr(virJSONValue) vq = virJSONValueNewNumberUint(ioth->queues[i]);
+
+                if (virJSONValueArrayAppend(queues, &vq))
+                    return NULL;
+            }
+        }
+
+        if (virJSONValueObjectAdd(&props,
+                                  "s:iothread", alias,
+                                  "A:vqs", &queues,
+                                  NULL) < 0)
+            return NULL;
+
+
+        if (virJSONValueArrayAppend(ret, &props))
+            return NULL;
+    }
+
+    return g_steal_pointer(&ret);
+}
+
+
 virJSONValue *
 qemuBuildDiskDeviceProps(const virDomainDef *def,
                          virDomainDiskDef *disk,
@@ -1792,11 +1831,16 @@ qemuBuildDiskDeviceProps(const virDomainDef *def,

     case VIR_DOMAIN_DISK_BUS_VIRTIO: {
         virTristateSwitch scsi = VIR_TRISTATE_SWITCH_ABSENT;
+        g_autoptr(virJSONValue) iothreadMapping = NULL;
         g_autofree char *iothread = NULL;

         if (disk->iothread > 0)
             iothread = g_strdup_printf("iothread%u", disk->iothread);

+        if (disk->iothreads &&
+            !(iothreadMapping = qemuBuildDiskDeviceIothreadMappingProps(disk->iothreads)))
+            return NULL;
+
         if (virStorageSourceGetActualType(disk->src) != VIR_STORAGE_TYPE_VHOST_USER &&
             virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_SCSI)) {
             /* if sg_io is true but the scsi option isn't supported,
@@ -1820,6 +1864,7 @@ qemuBuildDiskDeviceProps(const virDomainDef *def,
                                   "T:scsi", scsi,
                                   "p:num-queues", disk->queues,
                                   "p:queue-size", disk->queue_size,
+                                  "A:iothread-vq-mapping", &iothreadMapping,
                                   NULL) < 0)
             return NULL;
     }
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index 9e50c2f45b..9611bff767 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -2669,12 +2669,24 @@ qemuValidateDomainDeviceDefDiskSerial(const char *value)
 }


-static bool
+static int
 qemuValidateDomainDeviceDefDiskIOThreads(const virDomainDef *def,
-                                         const virDomainDiskDef *disk)
+                                         const virDomainDiskDef *disk,
+                                         virQEMUCaps *qemuCaps)
 {
+    if (disk->iothread == 0 && !disk->iothreads)
+        return 0;
+
     switch (disk->bus) {
     case VIR_DOMAIN_DISK_BUS_VIRTIO:
+        if (disk->iothreads) {
+            if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_BLK_IOTHREAD_MAPPING)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("IOThread mapping for disk '%1$s' is not available with this QEMU binary"),
+                               disk->dst);
+                return -1;
+            }
+        }
         break;

     case VIR_DOMAIN_DISK_BUS_IDE:
@@ -2690,18 +2702,101 @@ qemuValidateDomainDeviceDefDiskIOThreads(const virDomainDef *def,
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("IOThreads not available for bus %1$s target %2$s"),
                        virDomainDiskBusTypeToString(disk->bus), disk->dst);
-        return false;
+        return -1;
     }

-    /* Can we find the disk iothread in the iothreadid list? */
-    if (!virDomainIOThreadIDFind(def, disk->iothread)) {
-        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                       _("Disk iothread '%1$u' not defined in iothreadid"),
-                       disk->iothread);
-        return false;
+    if (disk->iothreads) {
+        virDomainDiskIothreadDef *first_ioth = disk->iothreads->data;
+        g_autoptr(virBitmap) queueMap = NULL;
+        g_autoptr(GHashTable) iothreads = virHashNew(NULL);
+        ssize_t unused;
+        GSList *n;
+
+        if (first_ioth->queues) {
+            if (disk->queues == 0) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("disk 'queue' count must be configured for explicit iothread to queue mapping"));
+                return -1;
+            }
+
+            queueMap = virBitmapNew(disk->queues);
+        }
+
+        /* we are validating that:
+         * - there are no duplicate iothreads
+         * - there are only valid iothreads
+         * - if queue mapping is provided
+         *    - queue is in range
+         *    - it must be provided for all assigned iothreads
+         *    - it must be provided for all queues
+         *    - queue must be assigned only once
+         */
+        for (n = disk->iothreads; n; n = n->next) {
+            virDomainDiskIothreadDef *ioth = n->data;
+            g_autofree char *alias = g_strdup_printf("iothread%u", ioth->id);
+            size_t i;
+
+            if (g_hash_table_contains(iothreads, alias)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("Duplicate mapping for iothread '%1$u'"), ioth->id);
+                return -1;
+            }
+
+            g_hash_table_insert(iothreads, g_steal_pointer(&alias), NULL);
+
+            if (!virDomainIOThreadIDFind(def, ioth->id)) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("Disk iothread '%1$u' not defined in iothreadid"),
+                               ioth->id);
+                return -1;
+            }
+
+            if (!!queueMap != !!ioth->queues) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                               _("iothread to queue mapping must be provided for all iothreads or for none"));
+                return -1;
+            }
+
+            for (i = 0; i < ioth->nqueues; i++) {
+                bool hasMapping;
+
+                if (virBitmapGetBit(queueMap, ioth->queues[i], &hasMapping) < 0) {
+                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                   _("disk iothread queue '%1$u' mapping out of range"),
+                                   ioth->queues[i]);
+                    return -1;
+                }
+
+                if (hasMapping) {
+                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                   _("disk iothread queue '%1$u' is already assigned"),
+                                   ioth->queues[i]);
+                    return -1;
+                }
+
+                ignore_value(virBitmapSetBit(queueMap, ioth->queues[i]));
+
+            }
+        }
+
+        if (queueMap) {
+            if ((unused = virBitmapNextClearBit(queueMap, -1)) >= 0) {
+                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                               _("missing iothread mapping for queue '%1$zd'"),
+                               unused);
+                return -1;
+            }
+        }
+    } else {
+        if (!virDomainIOThreadIDFind(def, disk->iothread)) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Disk iothread '%1$u' not defined in iothreadid"),
+                           disk->iothread);
+            return -1;
+        }
     }

-    return true;
+    return 0;
 }


@@ -2956,7 +3051,7 @@ qemuValidateDomainDeviceDefDiskFrontend(const virDomainDiskDef *disk,
         qemuValidateDomainDeviceDefDiskSerial(disk->serial) < 0)
         return -1;

-    if (disk->iothread && !qemuValidateDomainDeviceDefDiskIOThreads(def, disk))
+    if (qemuValidateDomainDeviceDefDiskIOThreads(def, disk, qemuCaps) < 0)
         return -1;

     return 0;
-- 
2.43.0
_______________________________________________
Devel mailing list -- devel@xxxxxxxxxxxxxxxxx
To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxx




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux