diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 9698b96ce9..298ad46a45 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:: + + + + + + + + + + + + + + + - 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 8d945a9416..be57a1981e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -2330,6 +2330,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) @@ -2378,6 +2389,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); } @@ -7766,6 +7778,8 @@ static int virDomainDiskDefDriverParseXML(virDomainDiskDef *def, xmlNodePtr cur) { + xmlNodePtr iothreadsNode; + def->driverName = virXMLPropString(cur, "name"); if (virXMLPropEnum(cur, "cache", virDomainDiskCacheTypeFromString, @@ -7812,6 +7826,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) @@ -22705,6 +22757,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, "\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 a7a7f770c1..d176bda5f8 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -503,6 +503,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? */ @@ -557,6 +570,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 and it's 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 c1c267d303..a34427c330 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -2536,9 +2536,26 @@ - + + + + + + + + + + + + + + + + + + + + @@ -2590,17 +2607,23 @@ - - - - - - - - - + + + + + + + + + + + + + + +