Introduce a new <iothreads> sub-element of disk's <driver> which will allow configuring multiple iothreads and also map them to specific virt-queues of virtio devices. Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- docs/formatdomain.rst | 23 +++++++++- src/conf/domain_conf.c | 76 +++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 14 ++++++ src/conf/domain_validate.c | 8 ++++ src/conf/schemas/domaincommon.rng | 47 ++++++++++++++----- 5 files changed, 155 insertions(+), 13 deletions(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 96e03a3807..b8a12c2ab3 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -3338,7 +3338,28 @@ paravirtualized driver is specified via the ``disk`` element. assigned to the same IOThread and are numbered from 1 to the domain iothreads value. Available for a disk device ``target`` configured to use "virtio" ``bus`` and "pci" or "ccw" ``address`` types. :since:`Since 1.2.8 - (QEMU 2.1)` + (QEMU 2.1)` *Note:* ``iothread`` is mutually exclusive with ``iothreads``. + - The optional ``iothreads`` sub-element allows specifying multiple IOThreads + via the ``iothread`` sub-element with attribute ``id`` the disk will use + for I/O operations. Optionally the ``iothread`` element can have multiple + ``queue`` subelements specifying that given iothread should be used to + handle given queues. :since:`Since 10.0.0 (QEMU 9.0, virtio disks only)`. + Example:: + + <driver name='qemu' queues='2'> + <iothreads> + <iothread id='1'> + <queue id='1'/> + </iothread> + <iothread id='2'> + <queue id='1'/> + </iothread> + <iothread id='3'> + <queue id='2'/> + </iothread> + </iothreads> + </driver> + - The optional ``queues`` attribute specifies the number of virt queues for virtio-blk ( :since:`Since 3.9.0` ) or vhost-user-blk ( :since `Since 7.1.0` ) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index db3d12cb49..aab37b4304 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2337,6 +2337,17 @@ virDomainDefGetVcpusTopology(const virDomainDef *def, } +void +virDomainDiskIothreadDefFree(virDomainDiskIothreadDef *def) +{ + if (!def) + return; + + g_free(def->queues); + g_free(def); +} + + static virDomainDiskDef * virDomainDiskDefNewSource(virDomainXMLOption *xmlopt, virStorageSource **src) @@ -2385,6 +2396,7 @@ virDomainDiskDefFree(virDomainDiskDef *def) g_free(def->virtio); virDomainDeviceInfoClear(&def->info); virObjectUnref(def->privateData); + g_slist_free_full(def->iothreads, (GDestroyNotify) virDomainDiskIothreadDefFree); g_free(def); } @@ -7775,6 +7787,8 @@ static int virDomainDiskDefDriverParseXML(virDomainDiskDef *def, xmlNodePtr cur) { + xmlNodePtr iothreadsNode; + def->driverName = virXMLPropString(cur, "name"); if (virXMLPropEnum(cur, "cache", virDomainDiskCacheTypeFromString, @@ -7821,6 +7835,44 @@ virDomainDiskDefDriverParseXML(virDomainDiskDef *def, if (virXMLPropUInt(cur, "iothread", 10, VIR_XML_PROP_NONZERO, &def->iothread) < 0) return -1; + if ((iothreadsNode = virXMLNodeGetSubelement(cur, "iothreads"))) { + g_autoslist(virDomainDiskIothreadDef) ioth = NULL; + g_autoptr(GPtrArray) iothreadNodes = NULL; + + if ((iothreadNodes = virXMLNodeGetSubelementList(iothreadsNode, "iothread"))) { + size_t i; + + for (i = 0; i < iothreadNodes->len; i++) { + xmlNodePtr iothNode = g_ptr_array_index(iothreadNodes, i); + g_autoptr(virDomainDiskIothreadDef) iothdef = g_new0(virDomainDiskIothreadDef, 1); + g_autoptr(GPtrArray) queueNodes = NULL; + + if (virXMLPropUInt(iothNode, "id", 10, VIR_XML_PROP_REQUIRED, + &iothdef->id) < 0) + return -1; + + if ((queueNodes = virXMLNodeGetSubelementList(iothNode, "queue"))) { + size_t q; + + iothdef->queues = g_new0(unsigned int, queueNodes->len); + iothdef->nqueues = queueNodes->len; + + for (q = 0; q < queueNodes->len; q++) { + xmlNodePtr queueNode = g_ptr_array_index(queueNodes, q); + + if (virXMLPropUInt(queueNode, "id", 10, VIR_XML_PROP_REQUIRED, + &(iothdef->queues[q])) < 0) + return -1; + } + } + + ioth = g_slist_prepend(ioth, g_steal_pointer(&iothdef)); + } + + def->iothreads = g_slist_reverse(g_steal_pointer(&ioth)); + } + } + if (virXMLPropEnum(cur, "detect_zeroes", virDomainDiskDetectZeroesTypeFromString, VIR_XML_PROP_NONZERO, &def->detect_zeroes) < 0) @@ -22715,6 +22767,30 @@ virDomainDiskDefFormatDriver(virBuffer *buf, virXMLFormatElement(&childBuf, "metadata_cache", NULL, &metadataCacheChildBuf); } + if (disk->iothreads) { + g_auto(virBuffer) iothreadsChildBuf = VIR_BUFFER_INIT_CHILD(&childBuf); + GSList *n; + + for (n = disk->iothreads; n; n = n->next) { + virDomainDiskIothreadDef *iothDef = n->data; + g_auto(virBuffer) iothreadAttrBuf = VIR_BUFFER_INITIALIZER; + g_auto(virBuffer) iothreadChildBuf = VIR_BUFFER_INIT_CHILD(&iothreadsChildBuf); + + virBufferAsprintf(&iothreadAttrBuf, " id='%u'", iothDef->id); + + if (iothDef->queues) { + size_t q; + + for (q = 0; q < iothDef->nqueues; q++) + virBufferAsprintf(&iothreadChildBuf, "<queue id='%u'/>\n", iothDef->queues[q]); + } + + virXMLFormatElement(&iothreadsChildBuf, "iothread", &iothreadAttrBuf, &iothreadChildBuf); + } + + virXMLFormatElement(&childBuf, "iothreads", NULL, &iothreadsChildBuf); + } + virXMLFormatElement(buf, "driver", &attrBuf, &childBuf); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 14901b37ba..a5757ae808 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -515,6 +515,19 @@ typedef enum { VIR_ENUM_DECL(virDomainSnapshotLocation); +struct _virDomainDiskIothreadDef { + unsigned int id; + + /* optional list of virtqueues the iothread should handle */ + unsigned int *queues; + size_t nqueues; +}; + +typedef struct _virDomainDiskIothreadDef virDomainDiskIothreadDef; +void virDomainDiskIothreadDefFree(virDomainDiskIothreadDef *def); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainDiskIothreadDef, virDomainDiskIothreadDefFree); + + /* Stores the virtual disk configuration */ struct _virDomainDiskDef { virStorageSource *src; /* non-NULL. XXX Allow NULL for empty cdrom? */ @@ -569,6 +582,7 @@ struct _virDomainDiskDef { virDomainDeviceSGIO sgio; virDomainDiskDiscard discard; unsigned int iothread; /* unused = 0, > 0 specific thread # */ + GSList *iothreads; /* List of virDomainDiskIothreadsDef */ virDomainDiskDetectZeroes detect_zeroes; virTristateSwitch discard_no_unref; char *domain_name; /* backend domain name */ diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c index c72108886e..d485ec4fb1 100644 --- a/src/conf/domain_validate.c +++ b/src/conf/domain_validate.c @@ -934,6 +934,14 @@ virDomainDiskDefValidate(const virDomainDef *def, } } + /* configuring both <driver iothread='n'> and it's <iothreads> sub-element + * isn't supported */ + if (disk->iothread && disk->iothreads) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("disk 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 f318c06797..3f856452cf 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -2536,9 +2536,26 @@ </optional> </element> </define> - <!-- - Disk may use a special driver for access. - --> + + <define name="diskDriverIothreads"> + <element name="iothreads"> + <oneOrMore> + <element name="iothread"> + <attribute name="id"> + <ref name="unsignedInt"/> + </attribute> + <zeroOrMore> + <element name="queue"> + <attribute name="id"> + <ref name="unsignedInt"/> + </attribute> + </element> + </zeroOrMore> + </element> + </oneOrMore> + </element> + </define> + <define name="diskDriver"> <element name="driver"> <optional> @@ -2590,17 +2607,23 @@ </attribute> </optional> <ref name="virtioOptions"/> - <optional> - <element name="metadata_cache"> - <optional> - <element name="max_size"> - <ref name="scaledInteger"/> - </element> - </optional> - </element> - </optional> + <interleave> + <optional> + <element name="metadata_cache"> + <optional> + <element name="max_size"> + <ref name="scaledInteger"/> + </element> + </optional> + </element> + </optional> + <optional> + <ref name="diskDriverIothreads"/> + </optional> + </interleave> </element> </define> + <define name="driverFormat"> <optional> <attribute name="name"> -- 2.43.0 _______________________________________________ Devel mailing list -- devel@xxxxxxxxxxxxxxxxx To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxx