conf: Add new domain XML element 'iothreadids'

Adding a new XML element 'iothreadids' in order to allow defining
specific IOThread ID's rather than relying on the algorithm to assign
IOThread ID's starting at 1 and incrementing to iothreads count.

This will allow future patches to be able to add new IOThreads by
a specific iothread_id and of course delete any exisiting IOThread.

Each iothreadids element will have 'n' <iothread> children elements
which will have attribute "id".  The "id" will allow for definition
of any "valid" (eg > 0) iothread_id value.

On input, if any <iothreadids> <iothread>'s are provided, they will
be marked so that we only print out what we read in.

On input, if no <iothreadids> are provided, the PostParse code will
self generate a list of ID's starting at 1 and going to the number
of iothreads defined for the domain (just like the current algorithm
numbering scheme).  A future patch will rework the existing algorithm
to make use of the iothreadids list.

On output, only print out the <iothreadids> if they were read in.
This commit is contained in:
John Ferlan 2015-04-02 19:59:25 -04:00
parent a7f0db6904
commit 93383c1ffa
5 changed files with 265 additions and 2 deletions

View File

@ -520,6 +520,18 @@
&lt;iothreads&gt;4&lt;/iothreads&gt;
...
&lt;/domain&gt;
</pre>
<pre>
&lt;domain&gt;
...
&lt;iothreadids&gt;
&lt;iothread id="2"/&gt;
&lt;iothread id="4"/&gt;
&lt;iothread id="6"/&gt;
&lt;iothread id="8"/&gt;
&lt;/iothreadids&gt;
...
&lt;/domain&gt;
</pre>
<dl>
@ -530,7 +542,25 @@
virtio-blk-pci and virtio-blk-ccw target storage devices. There
should be only 1 or 2 IOThreads per host CPU. There may be more
than one supported device assigned to each IOThread.
<span class="since">Since 1.2.8</span>
</dd>
<dt><code>iothreadids</code></dt>
<dd>
The optional <code>iothreadids</code> element provides the capability
to specifically define the IOThread ID's for the domain. By default,
IOThread ID's are sequentially numbered starting from 1 through the
number of <code>iothreads</code> defined for the domain. The
<code>id</code> attribute is used to define the IOThread ID. The
<code>id</code> attribute must be a positive integer greater than 0.
If there are less <code>iothreadids</code> defined than
<code>iothreads</code> defined for the domain, then libvirt will
sequentially fill <code>iothreadids</code> starting at 1 avoiding
any predefined <code>id</code>. If there are more
<code>iothreadids</code> defined than <code>iothreads</code>
defined for the domain, then the <code>iothreads</code> value
will be adjusted accordingly.
<span class="since">Since 1.2.15</span>
</dd>
</dl>
<h3><a name="elementsCPUTuning">CPU Tuning</a></h3>

View File

@ -538,6 +538,18 @@
</element>
</optional>
<optional>
<element name="iothreadids">
<zeroOrMore>
<element name="iothread">
<attribute name="id">
<ref name="unsignedInt"/>
</attribute>
</element>
</zeroOrMore>
</element>
</optional>
<optional>
<ref name="blkiotune"/>
</optional>

View File

@ -2102,6 +2102,32 @@ virDomainPinDefCopy(virDomainPinDefPtr *src, int npin)
return NULL;
}
void
virDomainIOThreadIDDefFree(virDomainIOThreadIDDefPtr def)
{
if (!def)
return;
VIR_FREE(def);
}
static void
virDomainIOThreadIDDefArrayFree(virDomainIOThreadIDDefPtr *def,
int nids)
{
size_t i;
if (!def)
return;
for (i = 0; i < nids; i++)
virDomainIOThreadIDDefFree(def[i]);
VIR_FREE(def);
}
void
virDomainPinDefFree(virDomainPinDefPtr def)
{
@ -2298,6 +2324,8 @@ void virDomainDefFree(virDomainDefPtr def)
virCPUDefFree(def->cpu);
virDomainIOThreadIDDefArrayFree(def->iothreadids, def->niothreadids);
virDomainPinDefArrayFree(def->cputune.vcpupin, def->cputune.nvcpupin);
virDomainPinDefFree(def->cputune.emulatorpin);
@ -13170,6 +13198,54 @@ virDomainIdmapDefParseXML(xmlXPathContextPtr ctxt,
return idmap;
}
/* Parse the XML definition for an IOThread ID
*
* Format is :
*
* <iothreads>4</iothreads>
* <iothreadids>
* <iothread id='1'/>
* <iothread id='3'/>
* <iothread id='5'/>
* <iothread id='7'/>
* </iothreadids>
*/
static virDomainIOThreadIDDefPtr
virDomainIOThreadIDDefParseXML(xmlNodePtr node,
xmlXPathContextPtr ctxt)
{
virDomainIOThreadIDDefPtr iothrid;
xmlNodePtr oldnode = ctxt->node;
char *tmp = NULL;
if (VIR_ALLOC(iothrid) < 0)
return NULL;
ctxt->node = node;
if (!(tmp = virXPathString("string(./@id)", ctxt))) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Missing 'id' attribute in <iothread> element"));
goto error;
}
if (virStrToLong_uip(tmp, NULL, 10, &iothrid->iothread_id) < 0 ||
iothrid->iothread_id == 0) {
virReportError(VIR_ERR_XML_ERROR,
_("invalid iothread 'id' value '%s'"), tmp);
goto error;
}
cleanup:
VIR_FREE(tmp);
ctxt->node = oldnode;
return iothrid;
error:
virDomainIOThreadIDDefFree(iothrid);
goto cleanup;
}
/* Parse the XML definition for a vcpupin
*
* vcpupin has the form of
@ -13976,6 +14052,49 @@ virDomainDefParseXML(xmlDocPtr xml,
}
VIR_FREE(tmp);
/* Extract any iothread id's defined */
if ((n = virXPathNodeSet("./iothreadids/iothread", ctxt, &nodes)) < 0)
goto error;
if (n > def->iothreads)
def->iothreads = n;
if (n && VIR_ALLOC_N(def->iothreadids, n) < 0)
goto error;
for (i = 0; i < n; i++) {
virDomainIOThreadIDDefPtr iothrid = NULL;
if (!(iothrid = virDomainIOThreadIDDefParseXML(nodes[i], ctxt)))
goto error;
if (virDomainIOThreadIDFind(def, iothrid->iothread_id)) {
virReportError(VIR_ERR_XML_ERROR,
_("duplicate iothread id '%u' found"),
iothrid->iothread_id);
virDomainIOThreadIDDefFree(iothrid);
goto error;
}
def->iothreadids[def->niothreadids++] = iothrid;
}
VIR_FREE(nodes);
/* If no iothreadid's or not fully populated, let's finish the job
* here rather than in PostParseCallback
*/
if (def->iothreads && def->iothreads != def->niothreadids) {
unsigned int iothread_id = 1;
while (def->niothreadids != def->iothreads) {
if (!virDomainIOThreadIDFind(def, iothread_id)) {
virDomainIOThreadIDDefPtr iothrid;
if (!(iothrid = virDomainIOThreadIDAdd(def, iothread_id)))
goto error;
iothrid->autofill = true;
}
iothread_id++;
}
}
/* Extract cpu tunables. */
if ((n = virXPathULong("string(./cputune/shares[1])", ctxt,
&def->cputune.shares)) < -1) {
@ -17260,6 +17379,67 @@ virDomainDefAddImplicitControllers(virDomainDefPtr def)
return 0;
}
virDomainIOThreadIDDefPtr
virDomainIOThreadIDFind(virDomainDefPtr def,
unsigned int iothread_id)
{
size_t i;
if (!def->iothreadids || !def->niothreadids)
return NULL;
for (i = 0; i < def->niothreadids; i++) {
if (iothread_id == def->iothreadids[i]->iothread_id)
return def->iothreadids[i];
}
return NULL;
}
virDomainIOThreadIDDefPtr
virDomainIOThreadIDAdd(virDomainDefPtr def,
unsigned int iothread_id)
{
virDomainIOThreadIDDefPtr iothrid = NULL;
if (virDomainIOThreadIDFind(def, iothread_id)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot duplicate iothread_id '%u' in iothreadids"),
iothread_id);
return NULL;
}
if (VIR_ALLOC(iothrid) < 0)
goto error;
iothrid->iothread_id = iothread_id;
if (VIR_APPEND_ELEMENT_COPY(def->iothreadids, def->niothreadids,
iothrid) < 0)
goto error;
return iothrid;
error:
virDomainIOThreadIDDefFree(iothrid);
return NULL;
}
void
virDomainIOThreadIDDel(virDomainDefPtr def,
unsigned int iothread_id)
{
int n;
for (n = 0; n < def->niothreadids; n++) {
if (def->iothreadids[n]->iothread_id == iothread_id) {
virDomainIOThreadIDDefFree(def->iothreadids[n]);
VIR_DELETE_ELEMENT(def->iothreadids, n, def->niothreadids);
return;
}
}
}
/* Check if vcpupin with same id already exists. */
bool
virDomainPinIsDuplicate(virDomainPinDefPtr *def,
@ -20602,8 +20782,27 @@ virDomainDefFormatInternal(virDomainDefPtr def,
virBufferAsprintf(buf, " current='%u'", def->vcpus);
virBufferAsprintf(buf, ">%u</vcpu>\n", def->maxvcpus);
if (def->iothreads > 0)
virBufferAsprintf(buf, "<iothreads>%u</iothreads>\n", def->iothreads);
if (def->iothreads > 0) {
virBufferAsprintf(buf, "<iothreads>%u</iothreads>\n",
def->iothreads);
/* Only print out iothreadids if we read at least one */
for (i = 0; i < def->niothreadids; i++) {
if (!def->iothreadids[i]->autofill)
break;
}
if (i < def->niothreadids) {
virBufferAddLit(buf, "<iothreadids>\n");
virBufferAdjustIndent(buf, 2);
for (i = 0; i < def->niothreadids; i++) {
if (def->iothreadids[i]->autofill)
continue;
virBufferAsprintf(buf, "<iothread id='%u'/>\n",
def->iothreadids[i]->iothread_id);
}
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</iothreadids>\n");
}
}
if (def->cputune.sharesSpecified ||
(def->cputune.nvcpupin && !virDomainIsAllVcpupinInherited(def)) ||

View File

@ -2054,6 +2054,16 @@ struct _virDomainHugePage {
unsigned long long size; /* hugepage size in KiB */
};
typedef struct _virDomainIOThreadIDDef virDomainIOThreadIDDef;
typedef virDomainIOThreadIDDef *virDomainIOThreadIDDefPtr;
struct _virDomainIOThreadIDDef {
bool autofill;
unsigned int iothread_id;
};
void virDomainIOThreadIDDefFree(virDomainIOThreadIDDefPtr def);
typedef struct _virDomainCputune virDomainCputune;
typedef virDomainCputune *virDomainCputunePtr;
@ -2145,6 +2155,8 @@ struct _virDomainDef {
virBitmapPtr cpumask;
unsigned int iothreads;
size_t niothreadids;
virDomainIOThreadIDDefPtr *iothreadids;
virDomainCputune cputune;
@ -2604,6 +2616,12 @@ bool virDomainDefCheckABIStability(virDomainDefPtr src,
int virDomainDefAddImplicitControllers(virDomainDefPtr def);
virDomainIOThreadIDDefPtr virDomainIOThreadIDFind(virDomainDefPtr def,
unsigned int iothread_id);
virDomainIOThreadIDDefPtr virDomainIOThreadIDAdd(virDomainDefPtr def,
unsigned int iothread_id);
void virDomainIOThreadIDDel(virDomainDefPtr def, unsigned int iothread_id);
unsigned int virDomainDefFormatConvertXMLFlags(unsigned int flags);
char *virDomainDefFormat(virDomainDefPtr def,

View File

@ -324,6 +324,10 @@ virDomainHubTypeToString;
virDomainHypervTypeFromString;
virDomainHypervTypeToString;
virDomainInputDefFree;
virDomainIOThreadIDAdd;
virDomainIOThreadIDDefFree;
virDomainIOThreadIDDel;
virDomainIOThreadIDFind;
virDomainLeaseDefFree;
virDomainLeaseIndex;
virDomainLeaseInsert;