mirror of https://gitee.com/openkylin/libvirt.git
conf: Add XML for individual vCPU hotplug
Individual vCPU hotplug requires us to track the state of any vCPU. To allow this add the following XML: <domain> ... <vcpu current='2'>3</vcpu> <vcpus> <vcpu id='0' enabled='yes' hotpluggable='no' order='1'/> <vcpu id='1' enabled='yes' hotpluggable='yes' order='2'/> <vcpu id='1' enabled='no' hotpluggable='yes'/> </vcpus> ... The 'enabled' attribute allows to control the state of the vcpu. 'hotpluggable' controls whether given vcpu can be hotplugged and 'order' allows to specify the order to add the vcpus.
This commit is contained in:
parent
c84c2cb389
commit
5847bc5c64
|
@ -489,6 +489,10 @@
|
|||
<domain>
|
||||
...
|
||||
<vcpu placement='static' cpuset="1-4,^3,6" current="1">2</vcpu>
|
||||
<vcpus>
|
||||
<vcpu id='0' enabled='yes' hotpluggable='no' order='1'/>
|
||||
<vcpu id='1' enabled='no' hotpluggable='yes'/>
|
||||
</vcpus>
|
||||
...
|
||||
</domain>
|
||||
</pre>
|
||||
|
@ -542,6 +546,42 @@
|
|||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt><code>vcpus</code></dt>
|
||||
<dd>
|
||||
The vcpus element allows to control state of individual vcpus.
|
||||
|
||||
The <code>id</code> attribute specifies the vCPU id as used by libvirt
|
||||
in other places such as vcpu pinning, scheduler information and NUMA
|
||||
assignment. Note that the vcpu ID as seen in the guest may differ from
|
||||
libvirt ID in certain cases. Valid IDs are from 0 to the maximum vcpu
|
||||
count as set by the <code>vcpu</code> element minus 1.
|
||||
|
||||
The <code>enabled</code> attribute allows to control the state of the
|
||||
vcpu. Valid values are <code>yes</code> and <code>no</code>.
|
||||
|
||||
<code>hotpluggable</code> controls whether given vcpu can be hotplugged
|
||||
and hotunplugged in cases when the cpu is enabled at boot. Note that
|
||||
all disabled vcpus must be hotpluggable. Valid values are
|
||||
<code>yes</code> and <code>no</code>.
|
||||
|
||||
<code>order</code> allows to specify the order to add the vcpus. For
|
||||
hypervisors/platforms that require to insert multiple vcpus at once
|
||||
the order may be be duplicated accross all vcpus that need to be
|
||||
enabled at once. Specifying order is not necessary, vcpus are then
|
||||
added in an arbitrary order.
|
||||
|
||||
Note that hypervisors may create hotpluggable vcpus differently from
|
||||
boot vcpus thus special initialization may be necessary.
|
||||
|
||||
Hypervisors may require that vcpus enabled on boot which are not
|
||||
hotpluggable are clustered at the beginning starting with ID 0. It may
|
||||
be also required that vcpu 0 is always present and non-hotpluggable.
|
||||
|
||||
Note that providing state for individual cpus may be necessary to enable
|
||||
support of addressable vCPU hotplug and this feature may not be
|
||||
supported by all hypervisors.
|
||||
<span class="since">Since 2.2.0 (QEMU only)</span>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h3><a name="elementsIOThreadsAllocation">IOThreads Allocation</a></h3>
|
||||
|
|
|
@ -582,6 +582,31 @@
|
|||
</element>
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<element name="vcpus">
|
||||
<zeroOrMore>
|
||||
<element name="vcpu">
|
||||
<attribute name="id">
|
||||
<ref name="unsignedInt"/>
|
||||
</attribute>
|
||||
<attribute name="enabled">
|
||||
<ref name="virYesNo"/>
|
||||
</attribute>
|
||||
<optional>
|
||||
<attribute name="hotpluggable">
|
||||
<ref name="virYesNo"/>
|
||||
</attribute>
|
||||
</optional>
|
||||
<optional>
|
||||
<attribute name="order">
|
||||
<ref name="unsignedInt"/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</optional>
|
||||
|
||||
<optional>
|
||||
<element name="iothreads">
|
||||
<ref name="unsignedInt"/>
|
||||
|
|
|
@ -4332,6 +4332,13 @@ virDomainDefPostParseCheckFeatures(virDomainDefPtr def,
|
|||
}
|
||||
}
|
||||
|
||||
if (UNSUPPORTED(VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS) &&
|
||||
def->individualvcpus) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("individual CPU state configuration is not supported"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4405,6 +4412,43 @@ virDomainDefPostParseDeviceIterator(virDomainDefPtr def,
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainVcpuDefPostParse(virDomainDefPtr def)
|
||||
{
|
||||
virDomainVcpuDefPtr vcpu;
|
||||
size_t maxvcpus = virDomainDefGetVcpusMax(def);
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < maxvcpus; i++) {
|
||||
vcpu = virDomainDefGetVcpu(def, i);
|
||||
|
||||
switch (vcpu->hotpluggable) {
|
||||
case VIR_TRISTATE_BOOL_ABSENT:
|
||||
if (vcpu->online)
|
||||
vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO;
|
||||
else
|
||||
vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
|
||||
break;
|
||||
|
||||
case VIR_TRISTATE_BOOL_NO:
|
||||
if (!vcpu->online) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||
_("vcpu '%zu' is both offline and not "
|
||||
"hotpluggable"), i);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case VIR_TRISTATE_BOOL_YES:
|
||||
case VIR_TRISTATE_BOOL_LAST:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
virDomainDefPostParseInternal(virDomainDefPtr def,
|
||||
struct virDomainDefPostParseDeviceIteratorData *data)
|
||||
|
@ -4416,6 +4460,9 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (virDomainVcpuDefPostParse(def) < 0)
|
||||
return -1;
|
||||
|
||||
if (virDomainDefPostParseMemory(def, data->parseFlags) < 0)
|
||||
return -1;
|
||||
|
||||
|
@ -15521,6 +15568,8 @@ virDomainVcpuParse(virDomainDefPtr def,
|
|||
virDomainXMLOptionPtr xmlopt)
|
||||
{
|
||||
int n;
|
||||
xmlNodePtr *nodes = NULL;
|
||||
size_t i;
|
||||
char *tmp = NULL;
|
||||
unsigned int maxvcpus;
|
||||
unsigned int vcpus;
|
||||
|
@ -15549,8 +15598,6 @@ virDomainVcpuParse(virDomainDefPtr def,
|
|||
vcpus = maxvcpus;
|
||||
}
|
||||
|
||||
if (virDomainDefSetVcpus(def, vcpus) < 0)
|
||||
goto cleanup;
|
||||
|
||||
tmp = virXPathString("string(./vcpu[1]/@placement)", ctxt);
|
||||
if (tmp) {
|
||||
|
@ -15582,9 +15629,82 @@ virDomainVcpuParse(virDomainDefPtr def,
|
|||
}
|
||||
}
|
||||
|
||||
if ((n = virXPathNodeSet("./vcpus/vcpu", ctxt, &nodes)) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (n) {
|
||||
/* if individual vcpu states are provided take them as master */
|
||||
def->individualvcpus = true;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
virDomainVcpuDefPtr vcpu;
|
||||
int state;
|
||||
unsigned int id;
|
||||
unsigned int order;
|
||||
|
||||
if (!(tmp = virXMLPropString(nodes[i], "id")) ||
|
||||
virStrToLong_uip(tmp, NULL, 10, &id) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("missing or invalid vcpu id"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
VIR_FREE(tmp);
|
||||
|
||||
if (id >= def->maxvcpus) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("vcpu id '%u' is out of range of maximum "
|
||||
"vcpu count"), id);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
vcpu = virDomainDefGetVcpu(def, id);
|
||||
|
||||
if (!(tmp = virXMLPropString(nodes[i], "enabled"))) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("missing vcpu enabled state"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if ((state = virTristateBoolTypeFromString(tmp)) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("invalid vcpu 'enabled' value '%s'"), tmp);
|
||||
goto cleanup;
|
||||
}
|
||||
VIR_FREE(tmp);
|
||||
|
||||
vcpu->online = state == VIR_TRISTATE_BOOL_YES;
|
||||
|
||||
if ((tmp = virXMLPropString(nodes[i], "hotpluggable"))) {
|
||||
int hotpluggable;
|
||||
if ((hotpluggable = virTristateBoolTypeFromString(tmp)) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR,
|
||||
_("invalid vcpu 'hotpluggable' value '%s'"), tmp);
|
||||
goto cleanup;
|
||||
}
|
||||
vcpu->hotpluggable = hotpluggable;
|
||||
VIR_FREE(tmp);
|
||||
}
|
||||
|
||||
if ((tmp = virXMLPropString(nodes[i], "order"))) {
|
||||
if (virStrToLong_uip(tmp, NULL, 10, &order) < 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s",
|
||||
_("invalid vcpu order"));
|
||||
goto cleanup;
|
||||
}
|
||||
vcpu->order = order;
|
||||
VIR_FREE(tmp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (virDomainDefSetVcpus(def, vcpus) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(nodes);
|
||||
VIR_FREE(tmp);
|
||||
|
||||
return ret;
|
||||
|
@ -18642,6 +18762,13 @@ virDomainDefVcpuCheckAbiStability(virDomainDefPtr src,
|
|||
"destination definitions"), i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (svcpu->order != dvcpu->order) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||
_("vcpu enable order of vCPU '%zu' differs between "
|
||||
"source and destination definitions"), i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -22946,6 +23073,8 @@ static int
|
|||
virDomainCpuDefFormat(virBufferPtr buf,
|
||||
const virDomainDef *def)
|
||||
{
|
||||
virDomainVcpuDefPtr vcpu;
|
||||
size_t i;
|
||||
char *cpumask = NULL;
|
||||
int ret = -1;
|
||||
|
||||
|
@ -22962,6 +23091,27 @@ virDomainCpuDefFormat(virBufferPtr buf,
|
|||
virBufferAsprintf(buf, " current='%u'", virDomainDefGetVcpus(def));
|
||||
virBufferAsprintf(buf, ">%u</vcpu>\n", virDomainDefGetVcpusMax(def));
|
||||
|
||||
if (def->individualvcpus) {
|
||||
virBufferAddLit(buf, "<vcpus>\n");
|
||||
virBufferAdjustIndent(buf, 2);
|
||||
for (i = 0; i < def->maxvcpus; i++) {
|
||||
vcpu = def->vcpus[i];
|
||||
|
||||
virBufferAsprintf(buf, "<vcpu id='%zu' enabled='%s'",
|
||||
i, vcpu->online ? "yes" : "no");
|
||||
if (vcpu->hotpluggable)
|
||||
virBufferAsprintf(buf, " hotpluggable='%s'",
|
||||
virTristateBoolTypeToString(vcpu->hotpluggable));
|
||||
|
||||
if (vcpu->order != 0)
|
||||
virBufferAsprintf(buf, " order='%d'", vcpu->order);
|
||||
|
||||
virBufferAddLit(buf, "/>\n");
|
||||
}
|
||||
virBufferAdjustIndent(buf, -2);
|
||||
virBufferAddLit(buf, "</vcpus>\n");
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
|
|
|
@ -2046,6 +2046,9 @@ typedef virDomainVcpuDef *virDomainVcpuDefPtr;
|
|||
|
||||
struct _virDomainVcpuDef {
|
||||
bool online;
|
||||
virTristateBool hotpluggable;
|
||||
unsigned int order;
|
||||
|
||||
virBitmapPtr cpumask;
|
||||
|
||||
virDomainThreadSchedParam sched;
|
||||
|
@ -2142,6 +2145,8 @@ struct _virDomainDef {
|
|||
|
||||
virDomainVcpuDefPtr *vcpus;
|
||||
size_t maxvcpus;
|
||||
/* set if the vcpu definition was specified individually */
|
||||
bool individualvcpus;
|
||||
int placement_mode;
|
||||
virBitmapPtr cpumask;
|
||||
|
||||
|
@ -2344,6 +2349,7 @@ typedef enum {
|
|||
VIR_DOMAIN_DEF_FEATURE_MEMORY_HOTPLUG = (1 << 1),
|
||||
VIR_DOMAIN_DEF_FEATURE_OFFLINE_VCPUPIN = (1 << 2),
|
||||
VIR_DOMAIN_DEF_FEATURE_NAME_SLASH = (1 << 3),
|
||||
VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS = (1 << 4),
|
||||
} virDomainDefFeatures;
|
||||
|
||||
|
||||
|
|
|
@ -5846,8 +5846,17 @@ qemuDomainRefreshVcpuInfo(virQEMUDriverPtr driver,
|
|||
VIR_STEAL_PTR(vcpupriv->alias, info[i].alias);
|
||||
vcpupriv->enable_id = info[i].id;
|
||||
|
||||
if (hotplug && state)
|
||||
if (hotplug && state) {
|
||||
vcpu->online = !!info[i].qom_path;
|
||||
|
||||
/* mark cpus that don't have an alias as non-hotpluggable */
|
||||
if (vcpu->online) {
|
||||
if (vcpupriv->alias)
|
||||
vcpu->hotpluggable = VIR_TRISTATE_BOOL_YES;
|
||||
else
|
||||
vcpu->hotpluggable = VIR_TRISTATE_BOOL_NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<domain type='qemu'>
|
||||
<name>foobar</name>
|
||||
<uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
|
||||
<memory unit='KiB'>219136</memory>
|
||||
<currentMemory unit='KiB'>219136</currentMemory>
|
||||
<vcpu placement='static' current='2'>4</vcpu>
|
||||
<vcpus>
|
||||
<vcpu id='0' enabled='no' hotpluggable='yes' order='1'/>
|
||||
<vcpu id='1' enabled='yes' hotpluggable='no'/>
|
||||
<vcpu id='2' enabled='no' hotpluggable='yes' order='2'/>
|
||||
<vcpu id='3' enabled='yes' hotpluggable='no'/>
|
||||
</vcpus>
|
||||
<os>
|
||||
<type arch='i686' machine='pc'>hvm</type>
|
||||
<boot dev='hd'/>
|
||||
</os>
|
||||
<clock offset='utc'/>
|
||||
<on_poweroff>destroy</on_poweroff>
|
||||
<on_reboot>restart</on_reboot>
|
||||
<on_crash>destroy</on_crash>
|
||||
<devices>
|
||||
</devices>
|
||||
</domain>
|
|
@ -97,6 +97,8 @@ mymain(void)
|
|||
|
||||
DO_TEST("perf");
|
||||
|
||||
DO_TEST("vcpus-individual");
|
||||
|
||||
virObjectUnref(caps);
|
||||
virObjectUnref(xmlopt);
|
||||
|
||||
|
|
|
@ -1089,7 +1089,9 @@ virCapsPtr virTestGenericCapsInit(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static virDomainDefParserConfig virTestGenericDomainDefParserConfig;
|
||||
static virDomainDefParserConfig virTestGenericDomainDefParserConfig = {
|
||||
.features = VIR_DOMAIN_DEF_FEATURE_INDIVIDUAL_VCPUS,
|
||||
};
|
||||
static virDomainXMLPrivateDataCallbacks virTestGenericPrivateDataCallbacks;
|
||||
|
||||
virDomainXMLOptionPtr virTestGenericDomainXMLConfInit(void)
|
||||
|
|
Loading…
Reference in New Issue