Sunday, 27 February
2011
Sun, 27 Feb
'11
8:39 a.m.
cputune XML:
<cputune>
<vcpupin vcpu='0' cpuset='0'/>
<vcpupin vcpu='1' cpuset='1'/>
</cputune>
* src/conf/domain_conf.h (New struct for vcputune and vcpupin,
declarations for new internal helper functions for cputune
support)
* src/conf/domain_conf.c (Update "virDomainDefParseXML" to parse,
and "declaration" to build cputune xml, implementations for
new internal helper functions).
* src/libvirt_private.syms (Add new internal functions, and also
"virAllocVar", as VIR_ALLOC_VAR is used in the patch series)
---
src/conf/domain_conf.c | 278 ++++++++++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 27 +++++
src/libvirt_private.syms | 4 +
3 files changed, 309 insertions(+), 0 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b97c1f0..698f738 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -848,6 +848,22 @@ virDomainClockDefClear(virDomainClockDefPtr def)
VIR_FREE(def->timers);
}
+static void
+virDomainVcpupinDefFree(virDomainVcpupinDefPtr *def,
+ int nvcpupin)
+{
+ int i;
+
+ if (!def || !nvcpupin)
+ return;
+
+ for(i = 0; i < nvcpupin; i++) {
+ VIR_FREE(def[i]);
+ }
+
+ VIR_FREE(def);
+}
+
void virDomainDefFree(virDomainDefPtr def)
{
unsigned int i;
@@ -936,6 +952,8 @@ void virDomainDefFree(virDomainDefPtr def)
virCPUDefFree(def->cpu);
+ virDomainVcpupinDefFree(def->cputune.vcpupin, def->cputune.nvcpupin);
+
virSysinfoDefFree(def->sysinfo);
if (def->namespaceData && def->ns.free)
@@ -3522,6 +3540,196 @@ error:
goto cleanup;
}
+/* Check if vcpupin with same vcpuid already exists.
+ * Return 1 if exists, 0 if not. */
+int
+virDomainVcpupinIsDuplicate(virDomainVcpupinDefPtr *def,
+ int nvcpupin,
+ int vcpu)
+{
+ int i;
+
+ if (!def || !nvcpupin)
+ return 0;
+
+ for (i = 0; i < nvcpupin; i++) {
+ if (def[i]->vcpuid == vcpu)
+ return 1;
+ }
+
+ return 0;
+}
+
+virDomainVcpupinDefPtr
+virDomainVcpupinFindByVcpu(virDomainVcpupinDefPtr *def,
+ int nvcpupin,
+ int vcpu)
+{
+ int i;
+
+ if (!def || !nvcpupin)
+ return NULL;
+
+ for (i = 0; i < nvcpupin; i++) {
+ if (def[i]->vcpuid == vcpu)
+ return def[i];
+ }
+
+ return NULL;
+}
+
+int
+virDomainVcpupinAdd(virDomainDefPtr def,
+ unsigned char *cpumap,
+ int maplen,
+ int vcpu)
+{
+ virDomainVcpupinDefPtr *vcpupin_list = NULL;
+ virDomainVcpupinDefPtr vcpupin = NULL;
+ char *cpumask = NULL;
+ int i;
+
+ if (VIR_ALLOC_N(cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ /* Reset cpumask to all 0s. */
+ for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++)
+ cpumask[i] = 0;
+
+ /* Convert bitmap (cpumap) to cpumask, which is byte map? */
+ for (i = 0; i < maplen; i++) {
+ int cur;
+
+ for (cur = 0; cur < 8; cur++) {
+ if (cpumap[i] & (1 << cur))
+ cpumask[i * 8 + cur] = 1;
+ }
+ }
+
+ /* No vcpupin exists yet. */
+ if (!def->cputune.nvcpupin) {
+ if (VIR_ALLOC(vcpupin) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC(vcpupin_list) < 0) {
+ virReportOOMError();
+ VIR_FREE(vcpupin);
+ goto cleanup;
+ }
+
+ vcpupin->vcpuid = vcpu;
+ vcpupin->cpumask = cpumask;
+ vcpupin_list[def->cputune.nvcpupin++] = vcpupin;
+
+ def->cputune.vcpupin = vcpupin_list;
+ } else {
+ vcpupin_list = def->cputune.vcpupin;
+
+ if (virDomainVcpupinIsDuplicate(vcpupin_list,
+ def->cputune.nvcpupin,
+ vcpu)) {
+ vcpupin = virDomainVcpupinFindByVcpu(vcpupin_list,
+ def->cputune.nvcpupin,
+ vcpu);
+ vcpupin->vcpuid = vcpu;
+ vcpupin->cpumask = cpumask;
+ } else {
+ if (VIR_ALLOC(vcpupin) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (VIR_REALLOC_N(vcpupin_list, def->cputune.nvcpupin + 1) < 0) {
+ virReportOOMError();
+ VIR_FREE(vcpupin);
+ goto cleanup;
+ }
+
+ vcpupin->vcpuid = vcpu;
+ vcpupin->cpumask = cpumask;
+ vcpupin_list[def->cputune.nvcpupin++] = vcpupin;
+ }
+ }
+
+ return 0;
+
+cleanup:
+ VIR_FREE(cpumask);
+ return -1;
+}
+
+/* Parse the XML definition for a vcpupin */
+static virDomainVcpupinDefPtr
+virDomainVcpupinDefParseXML(const xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ int maxvcpus,
+ int flags ATTRIBUTE_UNUSED)
+{
+ virDomainVcpupinDefPtr def;
+ xmlNodePtr oldnode = ctxt->node;
+ unsigned int vcpuid;
+ char *tmp = NULL;
+ int ret;
+
+ if (VIR_ALLOC(def) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ ctxt->node = node;
+
+ ret = virXPathUInt("string(./@vcpu)", ctxt, &vcpuid);
+ if (ret == -2) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("vcpu id must be an unsigned
integer"));
+ goto error;
+ } else if (ret == -1) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("can't parse vcpupin
node"));
+ goto error;
+ }
+
+ if (vcpuid >= maxvcpus) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("vcpu id must be less than
maxvcpus"));
+ goto error;
+ }
+
+ def->vcpuid = vcpuid;
+
+ tmp = virXMLPropString(node, "cpuset");
+
+ if (tmp) {
+ char *set = tmp;
+ int cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
+
+ if (VIR_ALLOC_N(def->cpumask, cpumasklen) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+ if (virDomainCpuSetParse((const char **)&set,
+ 0, def->cpumask,
+ cpumasklen) < 0)
+ goto error;
+ VIR_FREE(tmp);
+ } else {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing cpuset for vcpupin"));
+ goto error;
+ }
+
+cleanup:
+ ctxt->node = oldnode;
+ return def;
+
+error:
+ VIR_FREE(def);
+ goto cleanup;
+}
/* Parse the XML definition for a clock timer */
static virDomainTimerDefPtr
@@ -5244,6 +5452,46 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
VIR_FREE(tmp);
}
+ /* Extract cpu tunables. */
+ if (virXPathULong("string(./cputune/shares[1])", ctxt,
+ &def->cputune.shares) < 0)
+ def->cputune.shares = 0;
+
+ if ((n = virXPathNodeSet("./cputune/vcpupin", ctxt, &nodes)) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract vcpupin
nodes"));
+ goto error;
+ }
+
+ if (n && VIR_ALLOC_N(def->cputune.vcpupin, n) < 0)
+ goto no_memory;
+
+ if (n > def->maxvcpus) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("vcpupin nodes must be less than
maxvcpus"));
+ goto error;
+ }
+
+ for (i = 0 ; i < n ; i++) {
+ virDomainVcpupinDefPtr vcpupin = NULL;
+ vcpupin = virDomainVcpupinDefParseXML(nodes[i], ctxt, def->maxvcpus, 0);
+
+ if (!vcpupin)
+ goto error;
+
+ if (virDomainVcpupinIsDuplicate(def->cputune.vcpupin,
+ def->cputune.nvcpupin,
+ vcpupin->vcpuid)) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("duplicate vcpupin for same
vcpu"));
+ VIR_FREE(vcpupin);
+ goto error;
+ }
+
+ def->cputune.vcpupin[def->cputune.nvcpupin++] = vcpupin;
+ }
+ VIR_FREE(nodes);
+
n = virXPathNodeSet("./features/*", ctxt, &nodes);
if (n < 0)
goto error;
@@ -7708,6 +7956,36 @@ char *virDomainDefFormat(virDomainDefPtr def,
virBufferVSprintf(&buf, " current='%u'", def->vcpus);
virBufferVSprintf(&buf, ">%u</vcpu>\n", def->maxvcpus);
+ if (def->cputune.shares || def->cputune.vcpupin)
+ virBufferAddLit(&buf, " <cputune>\n");
+
+ if (def->cputune.shares)
+ virBufferVSprintf(&buf, " <shares>%lu</shares>\n",
+ def->cputune.shares);
+ if (def->cputune.vcpupin) {
+ int i;
+ for (i = 0; i < def->cputune.nvcpupin; i++) {
+ virBufferVSprintf(&buf, " <vcpupin vcpu='%u' ",
+ def->cputune.vcpupin[i]->vcpuid);
+
+ char *cpumask = NULL;
+ cpumask = virDomainCpuSetFormat(def->cputune.vcpupin[i]->cpumask,
+ VIR_DOMAIN_CPUMASK_LEN);
+
+ if (cpumask == NULL) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("failed to format cpuset for
vcpupin"));
+ goto cleanup;
+ }
+
+ virBufferVSprintf(&buf, "cpuset='%s'/>\n",
cpumask);
+ VIR_FREE(cpumask);
+ }
+ }
+
+ if (def->cputune.shares || def->cputune.vcpupin)
+ virBufferAddLit(&buf, " </cputune>\n");
+
if (def->sysinfo)
virDomainSysinfoDefFormat(&buf, def->sysinfo);
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 30aeccc..53467cd 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1032,6 +1032,21 @@ int virDomainSnapshotObjUnref(virDomainSnapshotObjPtr snapshot);
int virDomainSnapshotHasChildren(virDomainSnapshotObjPtr snap,
virDomainSnapshotObjListPtr snapshots);
+typedef struct _virDomainVcpupinDef virDomainVcpupinDef;
+typedef virDomainVcpupinDef *virDomainVcpupinDefPtr;
+struct _virDomainVcpupinDef {
+ int vcpuid;
+ char *cpumask;
+};
+
+int virDomainVcpupinIsDuplicate(virDomainVcpupinDefPtr *def,
+ int nvcpupin,
+ int vcpu);
+
+virDomainVcpupinDefPtr virDomainVcpupinFindByVcpu(virDomainVcpupinDefPtr *def,
+ int nvcpupin,
+ int vcpu);
+
/* Guest VM main configuration */
typedef struct _virDomainDef virDomainDef;
typedef virDomainDef *virDomainDefPtr;
@@ -1060,6 +1075,12 @@ struct _virDomainDef {
int cpumasklen;
char *cpumask;
+ struct {
+ unsigned long shares;
+ int nvcpupin;
+ virDomainVcpupinDefPtr *vcpupin;
+ } cputune;
+
/* These 3 are based on virDomainLifeCycleAction enum flags */
int onReboot;
int onPoweroff;
@@ -1196,6 +1217,12 @@ int
virDomainDeviceVirtioSerialAddressIsValid(virDomainDeviceVirtioSerialAddress
int virDomainDeviceInfoIsSet(virDomainDeviceInfoPtr info);
void virDomainDeviceInfoClear(virDomainDeviceInfoPtr info);
void virDomainDefClearPCIAddresses(virDomainDefPtr def);
+
+int virDomainVcpupinAdd(virDomainDefPtr def,
+ unsigned char *cpumap,
+ int maplen,
+ int vcpu);
+
void virDomainDefClearDeviceAliases(virDomainDefPtr def);
typedef int (*virDomainDeviceInfoCallback)(virDomainDefPtr def,
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 66917ca..10b97ce 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -315,6 +315,9 @@ virDomainTimerTickpolicyTypeFromString;
virDomainTimerTickpolicyTypeToString;
virDomainTimerTrackTypeFromString;
virDomainTimerTrackTypeToString;
+virDomainVcpupinAdd;
+virDomainVcpupinFindByVcpu;
+virDomainVcpupinIsDuplicate;
virDomainVideoDefFree;
virDomainVideoDefaultRAM;
virDomainVideoDefaultType;
@@ -563,6 +566,7 @@ virVMOperationTypeToString;
# memory.h
virAlloc;
virAllocN;
+virAllocVar;
virExpandN;
virFree;
virReallocN;
--
1.7.4