mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-01 17:35:17 +00:00
conf: Add possibility to configure multiple iothreads per disk
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@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
parent
ee7121ab8e
commit
0cb7b1b2c3
@ -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` )
|
||||
|
@ -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, "<queue id='%u'/>\n", iothDef->queues[q]);
|
||||
}
|
||||
|
||||
virXMLFormatElement(&iothreadsChildBuf, "iothread", &iothreadAttrBuf, &iothreadChildBuf);
|
||||
}
|
||||
|
||||
virXMLFormatElement(&childBuf, "iothreads", NULL, &iothreadsChildBuf);
|
||||
}
|
||||
|
||||
virXMLFormatElement(buf, "driver", &attrBuf, &childBuf);
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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">
|
||||
|
Loading…
x
Reference in New Issue
Block a user