From: Peter Krempa Date: Tue, 2 Aug 2016 15:58:43 +0000 (+0200) Subject: conf: Add XML for individual vCPU hotplug X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=5847bc5c64f205a2f00315a2434e8a7bd48c5508;p=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: ... 3 ... 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. --- diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index bfbb0f2834..062045b0fe 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -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> @@ -542,6 +546,42 @@ +
vcpus
+
+ The vcpus element allows to control state of individual vcpus. + + The id 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 vcpu element minus 1. + + The enabled attribute allows to control the state of the + vcpu. Valid values are yes and no. + + hotpluggable 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 + yes and no. + + order 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. + Since 2.2.0 (QEMU only) +

IOThreads Allocation

diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 052f28c867..9a7d03ed94 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -582,6 +582,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 14d4f7df9c..17c2f53966 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -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\n", virDomainDefGetVcpusMax(def)); + if (def->individualvcpus) { + virBufferAddLit(buf, "\n"); + virBufferAdjustIndent(buf, 2); + for (i = 0; i < def->maxvcpus; i++) { + vcpu = def->vcpus[i]; + + virBufferAsprintf(buf, "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, "\n"); + } + ret = 0; cleanup: diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 8b2672487d..b88912508b 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -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; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index d4f472ba28..5f4c642143 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -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; diff --git a/tests/genericxml2xmlindata/generic-vcpus-individual.xml b/tests/genericxml2xmlindata/generic-vcpus-individual.xml new file mode 100644 index 0000000000..cbcf8fd3dd --- /dev/null +++ b/tests/genericxml2xmlindata/generic-vcpus-individual.xml @@ -0,0 +1,23 @@ + + foobar + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + 4 + + + + + + + + hvm + + + + destroy + restart + destroy + + + diff --git a/tests/genericxml2xmltest.c b/tests/genericxml2xmltest.c index a487727a01..2ea2396480 100644 --- a/tests/genericxml2xmltest.c +++ b/tests/genericxml2xmltest.c @@ -97,6 +97,8 @@ mymain(void) DO_TEST("perf"); + DO_TEST("vcpus-individual"); + virObjectUnref(caps); virObjectUnref(xmlopt); diff --git a/tests/testutils.c b/tests/testutils.c index 8af8707fab..8ea6ab82ad 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -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)