diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index 285b272ce8..ce3506be55 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -180,6 +180,17 @@ struct _virCPUx86Model { * The corresponding features are a genuine part of the new model. */ GStrv addedFeatures; + + /* Pinter to the model this one was derived from. */ + virCPUx86Model *ancestor; + + /* Pointer to the canonical model if this model is just an alias. + * Because the aliases were actually added to the CPU map before their + * canonical models, we store this relation in the XML reversed. That is, + * this model contains all the data and the canonical model is defined + * using this model as an ancestor without adding any additional data. + */ + const virCPUx86Model *canonical; }; typedef struct _virCPUx86Map virCPUx86Map; @@ -1567,6 +1578,7 @@ x86ModelParseAncestor(virCPUx86Model *model, return -1; } + model->ancestor = ancestor; model->vendor = ancestor->vendor; model->signatures = virCPUx86SignaturesCopy(ancestor->signatures); x86DataCopy(&model->data, &ancestor->data); @@ -1582,9 +1594,11 @@ x86ModelParseAncestor(virCPUx86Model *model, } +/* Updates @changed if signatures are set. */ static int x86ModelParseSignatures(virCPUx86Model *model, - xmlXPathContextPtr ctxt) + xmlXPathContextPtr ctxt, + bool *changed) { g_autofree xmlNodePtr *nodes = NULL; VIR_XPATH_NODE_AUTORESTORE(ctxt) @@ -1628,14 +1642,17 @@ x86ModelParseSignatures(virCPUx86Model *model, return -1; } + *changed = true; return 0; } +/* Updates @changed if vendor changes. */ static int x86ModelParseVendor(virCPUx86Model *model, xmlXPathContextPtr ctxt, - virCPUx86Map *map) + virCPUx86Map *map, + bool *changed) { g_autofree char *vendor = NULL; int rc; @@ -1658,14 +1675,17 @@ x86ModelParseVendor(virCPUx86Model *model, return -1; } + *changed = true; return 0; } +/* Updates @changed if features are added. */ static int x86ModelParseFeatures(virCPUx86Model *model, xmlXPathContextPtr ctxt, - virCPUx86Map *map) + virCPUx86Map *map, + bool *changed) { g_autofree xmlNodePtr *nodes = NULL; size_t i; @@ -1725,6 +1745,7 @@ x86ModelParseFeatures(virCPUx86Model *model, model->removedFeatures = g_renew(char *, model->removedFeatures, nremoved + 1); model->addedFeatures = g_renew(char *, model->addedFeatures, nadded + 1); + *changed = true; return 0; } @@ -1736,6 +1757,7 @@ x86ModelParse(xmlXPathContextPtr ctxt, { virCPUx86Map *map = data; g_autoptr(virCPUx86Model) model = NULL; + bool changed = false; if (x86ModelFind(map, name)) { virReportError(VIR_ERR_INTERNAL_ERROR, @@ -1755,15 +1777,28 @@ x86ModelParse(xmlXPathContextPtr ctxt, if (x86ModelParseAncestor(model, ctxt, map) < 0) return -1; - if (x86ModelParseSignatures(model, ctxt) < 0) + if (x86ModelParseSignatures(model, ctxt, &changed) < 0) return -1; - if (x86ModelParseVendor(model, ctxt, map) < 0) + if (x86ModelParseVendor(model, ctxt, map, &changed) < 0) return -1; - if (x86ModelParseFeatures(model, ctxt, map) < 0) + if (x86ModelParseFeatures(model, ctxt, map, &changed) < 0) return -1; + if (model->ancestor && !changed) { + if (model->ancestor->canonical) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cannot set CPU model '%1$s' as canonical name of '%2$s' which is already an alias of '%3$s'"), + model->name, + model->ancestor->name, + model->ancestor->canonical->name); + return -1; + } + + model->ancestor->canonical = model; + } + VIR_APPEND_ELEMENT(map->models, map->nmodels, model); return 0;