/* * Linux maintains cpu bit map. For example, if cpuid=5's flag is not set * and max cpu is 7. The map file shows 0-4,6-7. This function parses * it and returns cpumap. */ static char * linuxParseCPUmap(int *max_cpuid, const char *path) { char *map = NULL; char *str = NULL; int max_id = 0, i; if (virFileReadAll(path, 5 * VIR_DOMAIN_CPUMASK_LEN, &str) < 0) { virReportOOMError(); goto error; } if (VIR_ALLOC_N(map, VIR_DOMAIN_CPUMASK_LEN) < 0) { virReportOOMError(); goto error; } if (virDomainCpuSetParse(str, 0, map, VIR_DOMAIN_CPUMASK_LEN) < 0) { goto error; } for (i = 0; i < VIR_DOMAIN_CPUMASK_LEN; i++) { if (map[i]) { max_id = i; } } *max_cpuid = max_id; return map; error: VIR_FREE(str); VIR_FREE(map); return NULL; }
virCPUDefPtr virCPUDefParseXML(const xmlNodePtr node, xmlXPathContextPtr ctxt, enum virCPUType mode) { virCPUDefPtr def; xmlNodePtr *nodes = NULL; int n; unsigned int i; char *cpuMode; if (!xmlStrEqual(node->name, BAD_CAST "cpu")) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("XML does not contain expected 'cpu' element")); return NULL; } if (VIR_ALLOC(def) < 0) { virReportOOMError(); return NULL; } if (mode == VIR_CPU_TYPE_AUTO) { if (virXPathBoolean("boolean(./arch)", ctxt)) { if (virXPathBoolean("boolean(./@match)", ctxt)) { virCPUReportError(VIR_ERR_XML_ERROR, "%s", _("'arch' element element cannot be used inside 'cpu'" " element with 'match' attribute'")); goto error; } def->type = VIR_CPU_TYPE_HOST; } else { def->type = VIR_CPU_TYPE_GUEST; } } else { def->type = mode; } if ((cpuMode = virXMLPropString(node, "mode"))) { if (def->type == VIR_CPU_TYPE_HOST) { VIR_FREE(cpuMode); virCPUReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("Attribute mode is only allowed for guest CPU")); goto error; } else { def->mode = virCPUModeTypeFromString(cpuMode); if (def->mode < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, _("Invalid mode attribute '%s'"), cpuMode); VIR_FREE(cpuMode); goto error; } VIR_FREE(cpuMode); } } else { if (def->type == VIR_CPU_TYPE_HOST) def->mode = -1; else def->mode = VIR_CPU_MODE_CUSTOM; } if (def->type == VIR_CPU_TYPE_GUEST) { char *match = virXMLPropString(node, "match"); if (!match) { if (virXPathBoolean("boolean(./model)", ctxt)) def->match = VIR_CPU_MATCH_EXACT; else def->match = -1; } else { def->match = virCPUMatchTypeFromString(match); VIR_FREE(match); if (def->match < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid match attribute for CPU specification")); goto error; } } } if (def->type == VIR_CPU_TYPE_HOST) { def->arch = virXPathString("string(./arch[1])", ctxt); if (!def->arch) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing CPU architecture")); goto error; } } if (!(def->model = virXPathString("string(./model[1])", ctxt)) && def->type == VIR_CPU_TYPE_HOST) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing CPU model name")); goto error; } if (def->type == VIR_CPU_TYPE_GUEST && def->mode != VIR_CPU_MODE_HOST_PASSTHROUGH && virXPathBoolean("boolean(./model[1]/@fallback)", ctxt)) { const char *fallback; fallback = virXPathString("string(./model[1]/@fallback)", ctxt); if (fallback) { def->fallback = virCPUFallbackTypeFromString(fallback); VIR_FREE(fallback); if (def->fallback < 0) { virCPUReportError(VIR_ERR_XML_ERROR, "%s", _("Invalid fallback attribute")); goto error; } } } def->vendor = virXPathString("string(./vendor[1])", ctxt); if (def->vendor && !def->model) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("CPU vendor specified without CPU model")); goto error; } if (virXPathNode("./topology[1]", ctxt)) { int ret; unsigned long ul; ret = virXPathULong("string(./topology[1]/@sockets)", ctxt, &ul); if (ret < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing 'sockets' attribute in CPU topology")); goto error; } def->sockets = (unsigned int) ul; ret = virXPathULong("string(./topology[1]/@cores)", ctxt, &ul); if (ret < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing 'cores' attribute in CPU topology")); goto error; } def->cores = (unsigned int) ul; ret = virXPathULong("string(./topology[1]/@threads)", ctxt, &ul); if (ret < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing 'threads' attribute in CPU topology")); goto error; } def->threads = (unsigned int) ul; if (!def->sockets || !def->cores || !def->threads) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid CPU topology")); goto error; } } n = virXPathNodeSet("./feature", ctxt, &nodes); if (n < 0) goto error; if (n > 0) { if (!def->model) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Non-empty feature list specified without CPU model")); goto error; } if (VIR_RESIZE_N(def->features, def->nfeatures_max, def->nfeatures, n) < 0) goto no_memory; def->nfeatures = n; } for (i = 0 ; i < n ; i++) { char *name; int policy; /* enum virDomainCPUFeaturePolicy */ unsigned int j; if (def->type == VIR_CPU_TYPE_GUEST) { char *strpolicy; strpolicy = virXMLPropString(nodes[i], "policy"); if (strpolicy == NULL) policy = VIR_CPU_FEATURE_REQUIRE; else policy = virCPUFeaturePolicyTypeFromString(strpolicy); VIR_FREE(strpolicy); if (policy < 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid CPU feature policy")); goto error; } } else { policy = -1; } if (!(name = virXMLPropString(nodes[i], "name")) || *name == 0) { VIR_FREE(name); virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid CPU feature name")); goto error; } for (j = 0 ; j < i ; j++) { if (STREQ(name, def->features[j].name)) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, _("CPU feature `%s' specified more than once"), name); VIR_FREE(name); goto error; } } def->features[i].name = name; def->features[i].policy = policy; } if (virXPathNode("./numa[1]", ctxt)) { VIR_FREE(nodes); n = virXPathNodeSet("./numa[1]/cell", ctxt, &nodes); if (n <= 0) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("NUMA topology defined without NUMA cells")); goto error; } if (VIR_RESIZE_N(def->cells, def->ncells_max, def->ncells, n) < 0) goto no_memory; def->ncells = n; for (i = 0 ; i < n ; i++) { char *cpus, *memory; int cpumasklen = VIR_DOMAIN_CPUMASK_LEN; int ret, ncpus = 0; def->cells[i].cellid = i; cpus = virXMLPropString(nodes[i], "cpus"); if (!cpus) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing 'cpus' attribute in NUMA cell")); goto error; } def->cells[i].cpustr = cpus; if (VIR_ALLOC_N(def->cells[i].cpumask, cpumasklen) < 0) goto no_memory; ncpus = virDomainCpuSetParse(cpus, 0, def->cells[i].cpumask, cpumasklen); if (ncpus <= 0) goto error; def->cells_cpus += ncpus; memory = virXMLPropString(nodes[i], "memory"); if (!memory) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Missing 'memory' attribute in NUMA cell")); goto error; } ret = virStrToLong_ui(memory, NULL, 10, &def->cells[i].mem); if (ret == -1) { virCPUReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid 'memory' attribute in NUMA cell")); VIR_FREE(memory); goto error; } VIR_FREE(memory); } } cleanup: VIR_FREE(nodes); return def; no_memory: virReportOOMError(); error: virCPUDefFree(def); def = NULL; goto cleanup; }