[libvirt] [PATCH v3 1/6] conf: Add new domain XML element 'iothreadids'
John Ferlan
jferlan at redhat.com
Tue Apr 21 16:37:03 UTC 2015
On 04/21/2015 10:08 AM, Peter Krempa wrote:
> On Tue, Apr 14, 2015 at 21:18:21 -0400, John Ferlan wrote:
>> 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.
>>
>> Signed-off-by: John Ferlan <jferlan at redhat.com>
>> ---
>> docs/formatdomain.html.in | 30 +++++++
>> docs/schemas/domaincommon.rng | 12 +++
>> src/conf/domain_conf.c | 190 +++++++++++++++++++++++++++++++++++++++++-
>> src/conf/domain_conf.h | 15 ++++
>> src/libvirt_private.syms | 3 +
>> 5 files changed, 248 insertions(+), 2 deletions(-)
>>
>> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
>> index e921749..518f7c5 100644
>> --- a/docs/formatdomain.html.in
>> +++ b/docs/formatdomain.html.in
>> @@ -521,6 +521,18 @@
>> ...
>> </domain>
>> </pre>
>> +<pre>
>> +<domain>
>> + ...
>> + <iothreadids>
>> + <iothread id="2"/>
>> + <iothread id="4"/>
>> + <iothread id="6"/>
>> + <iothread id="8"/>
>> + </iothreadids>
>> + ...
>> +</domain>
>> +</pre>
>>
>> <dl>
>> <dt><code>iothreads</code></dt>
>> @@ -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>
>> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
>> index 03fd541..4bd32bd 100644
>> --- a/docs/schemas/domaincommon.rng
>> +++ b/docs/schemas/domaincommon.rng
>> @@ -675,6 +675,18 @@
>> </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>
>>
>> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
>> index 4d7e3c9..e86b7e2 100644
>> --- a/src/conf/domain_conf.c
>> +++ b/src/conf/domain_conf.c
>> @@ -2113,6 +2113,23 @@ virDomainPinDefCopy(virDomainPinDefPtr *src, int npin)
>> return NULL;
>> }
>>
>> +
>> +static void
>> +virDomainIOThreadIDDefArrayFree(virDomainIOThreadIDDefPtr *def,
>> + int nids)
>> +{
>> + size_t i;
>> +
>> + if (!def)
>> + return;
>> +
>> + for (i = 0; i < nids; i++)
>> + VIR_FREE(def[i]);
>> +
>> + VIR_FREE(def);
>> +}
>> +
>> +
>> void
>> virDomainPinDefFree(virDomainPinDefPtr def)
>> {
>> @@ -2310,6 +2327,8 @@ void virDomainDefFree(virDomainDefPtr def)
>>
>> virCPUDefFree(def->cpu);
>>
>> + virDomainIOThreadIDDefArrayFree(def->iothreadids, def->niothreadids);
>> +
>> virDomainPinDefArrayFree(def->cputune.vcpupin, def->cputune.nvcpupin);
>>
>> virDomainPinDefFree(def->cputune.emulatorpin);
>> @@ -3304,6 +3323,18 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
>> return -1;
>> }
>>
>> + /* Fully populate the IOThread ID list */
>> + if (def->iothreads && def->iothreads != def->niothreadids) {
>> + unsigned int iothread_id = 1;
>> + while (def->niothreadids != def->iothreads) {
>> + if (!virDomainIOThreadIDFind(def, iothread_id)) {
>> + if (virDomainIOThreadIDAdd(def, iothread_id) < 0)
>
> This code is _adding_ fields for every iothread that was not specified
> in <iothreadids> but is implied by <iothreads>, but before that you've
> allocated all the structures in [1].
>
Hmm... correct - of course the allocation in [1] was suggested by
previous code review.
>
>> + return -1;
>> + }
>> + iothread_id++;
>> + }
>> + }
>> +
>> if (virDomainDefGetMemoryInitial(def) == 0) {
>> virReportError(VIR_ERR_XML_ERROR, "%s",
>> _("Memory size must be specified via <memory> or in the "
>> @@ -13173,6 +13204,56 @@ 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;
>> + }
>> +
>> + iothrid->defined = true;
>> +
>> + cleanup:
>> + VIR_FREE(tmp);
>> + ctxt->node = oldnode;
>> + return iothrid;
>> +
>> + error:
>> + VIR_FREE(iothrid);
>> + goto cleanup;
>> +}
>> +
>> +
>> /* Parse the XML definition for a vcpupin
>> *
>> * vcpupin has the form of
>> @@ -13948,6 +14029,32 @@ 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, MAX(n, def->iothreads)) < 0)
>> + goto error;
>
> [1]
>
Yes, the MAX(n, def->iothreads) was the prior code review suggestion...
So if I 'revert' back to just 'n', then let the above code handle the
rest, then these two issues should be resolved.
>> +
>> + 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);
>> + VIR_FREE(iothrid);
>> + goto error;
>> + }
>> + def->iothreadids[def->niothreadids++] = iothrid;
>> + }
>> + VIR_FREE(nodes);
>> +
>> /* Extract cpu tunables. */
>> if ((n = virXPathULong("string(./cputune/shares[1])", ctxt,
>> &def->cputune.shares)) < -1) {
>> @@ -17324,6 +17431,66 @@ 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;
>> +}
>> +
>> +int
>> +virDomainIOThreadIDAdd(virDomainDefPtr def,
>> + unsigned int iothread_id)
>
> If this function returned the pointer to the added structure you'd be
> able to use it later to modify other aspects of it.
>
OK seems reasonable... had to change to using VIR_APPEND_ELEMENT_COPY too
>> +{
>> + virDomainIOThreadIDDefPtr iothrid = NULL;
>> +
>> + if (virDomainIOThreadIDFind(def, iothread_id)) {
>> + virReportError(VIR_ERR_INTERNAL_ERROR,
>> + _("cannot duplicate iothread_id '%u' in iothreadids"),
>> + iothread_id);
>> + return -1;
>> + }
>> +
>> + if (VIR_ALLOC(iothrid) < 0)
>> + goto error;
>> +
>> + iothrid->iothread_id = iothread_id;
>> +
>> + if (VIR_APPEND_ELEMENT(def->iothreadids, def->niothreadids, iothrid) < 0)
>> + goto error;
>> +
>> + return 0;
>> +
>> + error:
>> + VIR_FREE(iothrid);
>> + return -1;
>> +}
>> +
>> +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) {
>> + VIR_FREE(def->iothreadids[n]);
>
> This could use a common freeing function, so that once you add more data
> you won't have to tweak it.
>
So you'd prefer a 'common' free function that just calls VIR_FREE() -
that just seems like excessive overhead, but that's fine.
>> + VIR_DELETE_ELEMENT(def->iothreadids, n, def->niothreadids);
>> + return;
>> + }
>> + }
>> +}
>> +
>> /* Check if vcpupin with same id already exists. */
>> bool
>> virDomainPinIsDuplicate(virDomainPinDefPtr *def,
>> @@ -20666,8 +20833,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);
>> + /* If we parsed the iothreadids, then write out those that we parsed */
>
> Seems rather obvious.
>
As a reviewer for now, sure... But what about someone who reads this
code 6, 12, 18 months from now and wonders why the extra loop...
I can adjust the comment to be :
"Only print out iothreadids if we read at least one"
>> + for (i = 0; i < def->niothreadids; i++) {
>> + if (def->iothreadids[i]->defined)
>> + break;
>> + }
>> + if (i < def->niothreadids) {
>> + virBufferAddLit(buf, "<iothreadids>\n");
>> + virBufferAdjustIndent(buf, 2);
>> + for (i = 0; i < def->niothreadids; i++) {
>> + if (!def->iothreadids[i]->defined)
>> + 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)) ||
>> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
>> index e6fa3c9..9e7bdf9 100644
>> --- a/src/conf/domain_conf.h
>> +++ b/src/conf/domain_conf.h
>> @@ -2041,6 +2041,14 @@ struct _virDomainHugePage {
>> unsigned long long size; /* hugepage size in KiB */
>> };
>>
>> +typedef struct _virDomainIOThreadIDDef virDomainIOThreadIDDef;
>> +typedef virDomainIOThreadIDDef *virDomainIOThreadIDDefPtr;
>> +
>> +struct _virDomainIOThreadIDDef {
>> + bool defined;
>
> You may want to invert this field, since the case where you add the
> thread structs due to the fact that <iohreads> was more than the count
> of entries is less common than other places that add the struct.
>
Made for an awkward looking:
for (i = 0; i < def->niothreadids; i++) {
if (!def->iothreadids[i]->undefined)
break;
}
>> + unsigned int iothread_id;
>> +};
>> +
>> typedef struct _virDomainCputune virDomainCputune;
>> typedef virDomainCputune *virDomainCputunePtr;
>>
>> @@ -2132,6 +2140,8 @@ struct _virDomainDef {
>> virBitmapPtr cpumask;
>>
>> unsigned int iothreads;
>> + size_t niothreadids;
>> + virDomainIOThreadIDDefPtr *iothreadids;
>>
>> virDomainCputune cputune;
>>
>> @@ -2590,6 +2600,11 @@ bool virDomainDefCheckABIStability(virDomainDefPtr src,
>>
>> int virDomainDefAddImplicitControllers(virDomainDefPtr def);
>>
>> +virDomainIOThreadIDDefPtr
>> +virDomainIOThreadIDFind(virDomainDefPtr def, unsigned int iothread_id);
>
> Usually the return type is on the same line and the argument list is
> broken if it doesn't fit.
>
OK - perhaps a relic of previous code where even the first argument made
the line too long - been too long to remember for sure.
>> +int 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,
Which gives the following to be squashed in (trying to make progress on
at least the first two patches which compile and pass tests):
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 82c36a4..3ff06b6 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2115,6 +2115,14 @@ virDomainPinDefCopy(virDomainPinDefPtr *src, int
npin)
}
+void
+virDomainIOThreadIDDefFree(virDomainIOThreadIDDefPtr def)
+{
+ if (def)
+ VIR_FREE(def);
+}
+
+
static void
virDomainIOThreadIDDefArrayFree(virDomainIOThreadIDDefPtr *def,
int nids)
@@ -2125,7 +2133,7 @@
virDomainIOThreadIDDefArrayFree(virDomainIOThreadIDDefPtr *def,
return;
for (i = 0; i < nids; i++)
- VIR_FREE(def[i]);
+ virDomainIOThreadIDDefFree(def[i]);
VIR_FREE(def);
}
@@ -3322,8 +3330,11 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
unsigned int iothread_id = 1;
while (def->niothreadids != def->iothreads) {
if (!virDomainIOThreadIDFind(def, iothread_id)) {
- if (virDomainIOThreadIDAdd(def, iothread_id) < 0)
+ virDomainIOThreadIDDefPtr iothrid;
+
+ if (!(iothrid = virDomainIOThreadIDAdd(def, iothread_id)))
return -1;
+ iothrid->undefined = true;
}
iothread_id++;
}
@@ -13216,15 +13227,13 @@ virDomainIOThreadIDDefParseXML(xmlNodePtr node,
goto error;
}
- iothrid->defined = true;
-
cleanup:
VIR_FREE(tmp);
ctxt->node = oldnode;
return iothrid;
error:
- VIR_FREE(iothrid);
+ virDomainIOThreadIDDefFree(iothrid);
goto cleanup;
}
@@ -14042,7 +14051,7 @@ virDomainDefParseXML(xmlDocPtr xml,
if (n > def->iothreads)
def->iothreads = n;
- if (n && VIR_ALLOC_N(def->iothreadids, MAX(n, def->iothreads)) < 0)
+ if (n && VIR_ALLOC_N(def->iothreadids, n) < 0)
goto error;
for (i = 0; i < n; i++) {
@@ -14054,7 +14063,7 @@ virDomainDefParseXML(xmlDocPtr xml,
virReportError(VIR_ERR_XML_ERROR,
_("duplicate iothread id '%u' found"),
iothrid->iothread_id);
- VIR_FREE(iothrid);
+ virDomainIOThreadIDDefFree(iothrid);
goto error;
}
def->iothreadids[def->niothreadids++] = iothrid;
@@ -17362,7 +17371,7 @@ virDomainIOThreadIDFind(virDomainDefPtr def,
return NULL;
}
-int
+virDomainIOThreadIDDefPtr
virDomainIOThreadIDAdd(virDomainDefPtr def,
unsigned int iothread_id)
{
@@ -17372,7 +17381,7 @@ virDomainIOThreadIDAdd(virDomainDefPtr def,
virReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot duplicate iothread_id '%u' in
iothreadids"),
iothread_id);
- return -1;
+ return NULL;
}
if (VIR_ALLOC(iothrid) < 0)
@@ -17380,14 +17389,15 @@ virDomainIOThreadIDAdd(virDomainDefPtr def,
iothrid->iothread_id = iothread_id;
- if (VIR_APPEND_ELEMENT(def->iothreadids, def->niothreadids,
iothrid) < 0)
+ if (VIR_APPEND_ELEMENT_COPY(def->iothreadids, def->niothreadids,
+ iothrid) < 0)
goto error;
- return 0;
+ return iothrid;
error:
- VIR_FREE(iothrid);
- return -1;
+ virDomainIOThreadIDDefFree(iothrid);
+ return NULL;
}
void
@@ -17398,7 +17408,7 @@ virDomainIOThreadIDDel(virDomainDefPtr def,
for (n = 0; n < def->niothreadids; n++) {
if (def->iothreadids[n]->iothread_id == iothread_id) {
- VIR_FREE(def->iothreadids[n]);
+ virDomainIOThreadIDDefFree(def->iothreadids[n]);
VIR_DELETE_ELEMENT(def->iothreadids, n, def->niothreadids);
return;
}
@@ -20749,16 +20759,16 @@ virDomainDefFormatInternal(virDomainDefPtr def,
if (def->iothreads > 0) {
virBufferAsprintf(buf, "<iothreads>%u</iothreads>\n",
def->iothreads);
- /* If we parsed the iothreadids, then write out those that we
parsed */
+ /* Only print out iothreadids if we read at least one */
for (i = 0; i < def->niothreadids; i++) {
- if (def->iothreadids[i]->defined)
+ if (!def->iothreadids[i]->undefined)
break;
}
if (i < def->niothreadids) {
virBufferAddLit(buf, "<iothreadids>\n");
virBufferAdjustIndent(buf, 2);
for (i = 0; i < def->niothreadids; i++) {
- if (!def->iothreadids[i]->defined)
+ if (def->iothreadids[i]->undefined)
continue;
virBufferAsprintf(buf, "<iothread id='%u'/>\n",
def->iothreadids[i]->iothread_id);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 01dc1f9..32de301 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2058,10 +2058,12 @@ typedef struct _virDomainIOThreadIDDef
virDomainIOThreadIDDef;
typedef virDomainIOThreadIDDef *virDomainIOThreadIDDefPtr;
struct _virDomainIOThreadIDDef {
- bool defined;
+ bool undefined;
unsigned int iothread_id;
};
+void virDomainIOThreadIDDefFree(virDomainIOThreadIDDefPtr def);
+
typedef struct _virDomainCputune virDomainCputune;
typedef virDomainCputune *virDomainCputunePtr;
@@ -2612,9 +2614,10 @@ bool
virDomainDefCheckABIStability(virDomainDefPtr src,
int virDomainDefAddImplicitControllers(virDomainDefPtr def);
-virDomainIOThreadIDDefPtr
-virDomainIOThreadIDFind(virDomainDefPtr def, unsigned int iothread_id);
-int virDomainIOThreadIDAdd(virDomainDefPtr def, unsigned int iothread_id);
+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);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 649ed8f..ac35f1b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -325,6 +325,7 @@ virDomainHypervTypeFromString;
virDomainHypervTypeToString;
virDomainInputDefFree;
virDomainIOThreadIDAdd;
+virDomainIOThreadIDDefFree;
virDomainIOThreadIDDel;
virDomainIOThreadIDFind;
virDomainLeaseDefFree;
More information about the libvir-list
mailing list