Upcoming qemu release will support configuring mapping iothreads to
virtio queues for 'virtio-scsi' controllers in order to improve
performance.
Reuse the infrastructure we have from the same configuration for
'virti-blk' to implement the conf support for this feature.
Signed-off-by: Peter Krempa <pkrempa(a)redhat.com>
---
docs/formatdomain.rst | 39 +++++++++++++++++++++++++++++++
src/conf/domain_conf.c | 10 +++++++-
src/conf/domain_conf.h | 1 +
src/conf/domain_validate.c | 10 +++++++-
src/conf/schemas/domaincommon.rng | 3 +++
src/hypervisor/domain_driver.c | 3 ++-
6 files changed, 63 insertions(+), 3 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index c1876ad467..92374ce2f3 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -4168,6 +4168,45 @@ An optional sub-element ``driver`` can specify the driver specific
options:
If a specific IOThread is desired for a specific SCSI ``disk``, then multiple
controllers must be defined each having a specific ``iothread`` value. The
``iothread`` value must be within the range 1 to the domain iothreads value.
+``iothreads``
+ Supported for ``virtio-scsi`` controllers using ``address`` types ``pci`` and
+ ``ccw``. :since:`since 11.2.0 (QEMU 10.0).` Mutually exclusive with ``iothread``.
+
+ The optional ``iothreads`` sub-element allows specifying multiple IOThreads
+ via the ``iothread`` sub-element with attribute ``id`` the ``virtio-scsi``
+ controller will use for I/O operations. The virt queues (see ``queues``
+ attribute of ``driver``) are automatically distributed among the configured
+ iothreads.
+
+ Optionally the ``iothread`` element can have multiple ``queue``
+ subelements with mandatory ``id`` atribute specifying that the iothread
+ should be used to handle given virt queue. If queue mapping is present
+ the ``queues`` attribute of ``driver`` must be configured and all
+ configured virt queues must be included in the mapping. The
+ ``virtio-scsi`` device exposes request virt queues ``0`` to ``N-1`` where
+ N is the number of queues configured for the device.
+
+ Example::
+
+ <driver queues='4>
+ <iothreads>
+ <iothread id='2'/>
+ <iothread id='3'/>
+ </iothreads>
+ </driver>
+
+ <driver queues='3'>
+ <iothreads>
+ <iothread id='2'>
+ <queue id='1'/>
+ </iothread>
+ <iothread id='3'>
+ <queue id='0'/>
+ <queue id='2'/>
+ </iothread>
+ </iothreads>
+ </driver>
+
virtio options
For virtio controllers, `Virtio-related options`_ can
also be set. ( :since:`Since 3.5.0` )
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b94cf99236..28d811de1f 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2565,6 +2565,8 @@ void virDomainControllerDefFree(virDomainControllerDef *def)
if (!def)
return;
+ g_slist_free_full(def->iothreads, (GDestroyNotify)
virDomainIothreadMappingDefFree);
+
virDomainDeviceInfoClear(&def->info);
g_free(def->virtio);
@@ -8639,6 +8641,9 @@ virDomainControllerDefParseXML(virDomainXMLOption *xmlopt,
&def->iothread) < 0)
return NULL;
+ if (virDomainIothreadMappingDefParse(driver, &def->iothreads) < 0)
+ return NULL;
+
if (virDomainVirtioOptionsParseXML(driver, &def->virtio) < 0)
return NULL;
}
@@ -23486,6 +23491,7 @@ virDomainControllerDriverFormat(virBuffer *buf,
virDomainControllerDef *def)
{
g_auto(virBuffer) driverBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) driverChildBuf = VIR_BUFFER_INIT_CHILD(buf);
if (def->queues)
virBufferAsprintf(&driverBuf, " queues='%u'",
def->queues);
@@ -23504,9 +23510,11 @@ virDomainControllerDriverFormat(virBuffer *buf,
if (def->iothread)
virBufferAsprintf(&driverBuf, " iothread='%u'",
def->iothread);
+ virDomainIothreadMappingDefFormat(&driverChildBuf, def->iothreads);
+
virDomainVirtioOptionsFormat(&driverBuf, def->virtio);
- virXMLFormatElement(buf, "driver", &driverBuf, NULL);
+ virXMLFormatElement(buf, "driver", &driverBuf, &driverChildBuf);
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 3a97fd866c..c8a8d17c91 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -764,6 +764,7 @@ struct _virDomainControllerDef {
unsigned int max_sectors;
virTristateSwitch ioeventfd;
unsigned int iothread; /* unused = 0, > 0 specific thread # */
+ GSList *iothreads; /* List of virDomainIothreadMappingDef */
union {
virDomainVirtioSerialOpts vioserial;
virDomainPCIControllerOpts pciopts;
diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
index f2a98f143d..33c3a3ffcc 100644
--- a/src/conf/domain_validate.c
+++ b/src/conf/domain_validate.c
@@ -1267,7 +1267,7 @@ virDomainControllerDefValidate(const virDomainControllerDef
*controller)
}
}
- if (controller->iothread != 0) {
+ if (controller->iothread != 0 || controller->iothreads) {
if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI ||
!(controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI ||
controller->model ==
VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL ||
@@ -1276,6 +1276,14 @@ virDomainControllerDefValidate(const virDomainControllerDef
*controller)
_("iothreads are supported only by 'virtio-scsi'
controllers"));
return -1;
}
+
+ /* configuring both <driver iothread='n'> and it's
<iothreads> sub-element
+ * isn't supported */
+ if (controller->iothread && controller->iothreads) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("controller driver 'iothread' attribute
can't be used together with 'iothreads' subelement"));
+ return -1;
+ }
}
return 0;
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index 3276569325..e4f4626b33 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -3064,6 +3064,9 @@
<optional>
<ref name="driverIOThread"/>
</optional>
+ <optional>
+ <ref name="iothreadMapping"/>
+ </optional>
<ref name="virtioOptions"/>
</element>
</optional>
diff --git a/src/hypervisor/domain_driver.c b/src/hypervisor/domain_driver.c
index b7499a376f..29ba358477 100644
--- a/src/hypervisor/domain_driver.c
+++ b/src/hypervisor/domain_driver.c
@@ -585,7 +585,8 @@ virDomainDriverDelIOThreadCheck(virDomainDef *def,
}
for (i = 0; i < def->ncontrollers; i++) {
- if (def->controllers[i]->iothread == iothread_id) {
+ if (virDomainIothreadMappingDefHasIothread(def->controllers[i]->iothreads,
iothread_id) ||
+ def->controllers[i]->iothread == iothread_id) {
virReportError(VIR_ERR_INVALID_ARG,
_("cannot remove IOThread '%1$u' since it is
being used by controller"),
iothread_id);
--
2.48.1