diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index de4e4ebfb6..35f48b273b 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -470,6 +470,32 @@
+
+
+ IOThreads are dedicated event loop threads for supported disk
+ devices to perform block I/O requests in order to improve
+ scalability especially on an SMP host/guest with many LUNs.
+ Since 1.2.8 (QEMU only)
+
+
+
+<domain>
+ ...
+ <iothreads>4</iothreads>
+ ...
+</domain>
+
+
+
+ iothreads
+ -
+ The content of this optional element defines the number
+ of IOThreads to be assigned to the domain for use by
+ virtio-blk-pci target storage devices. There should be
+ only 1 or 2 IOThreads per host CPU. There may be more than
+ supported device assigned to each IOThread.
+
+
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 3170db25c3..5f1c22658d 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -631,6 +631,12 @@
+
+
+
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 8e42641b83..adf197b80b 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -11977,6 +11977,15 @@ virDomainDefParseXML(xmlDocPtr xml,
}
}
+ /* Optional - iothreads */
+ tmp = virXPathString("string(./iothreads[1])", ctxt);
+ if (tmp && virStrToLong_uip(tmp, NULL, 10, &def->iothreads) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid iothreads count '%s'"), tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
+
/* Extract cpu tunables. */
if ((n = virXPathULong("string(./cputune/shares[1])", ctxt,
&def->cputune.shares)) < -1) {
@@ -14566,6 +14575,14 @@ virDomainDefCheckABIStability(virDomainDefPtr src,
goto error;
}
+ if (src->iothreads != dst->iothreads) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Target domain iothreads count %u does not "
+ "match source %u"),
+ dst->iothreads, src->iothreads);
+ goto error;
+ }
+
if (STRNEQ(src->os.type, dst->os.type)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Target domain OS type %s does not match source %s"),
@@ -17971,6 +17988,9 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virBufferAsprintf(buf, " current='%u'", def->vcpus);
virBufferAsprintf(buf, ">%u\n", def->maxvcpus);
+ if (def->iothreads > 0)
+ virBufferAsprintf(buf, "%u\n", def->iothreads);
+
if (def->cputune.sharesSpecified ||
(def->cputune.nvcpupin && !virDomainIsAllVcpupinInherited(def)) ||
def->cputune.period || def->cputune.quota ||
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a05254a7b7..f8ae0e7689 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1915,6 +1915,8 @@ struct _virDomainDef {
int placement_mode;
virBitmapPtr cpumask;
+ unsigned int iothreads;
+
struct {
unsigned long shares;
bool sharesSpecified;