diff --git a/src/cpu/cpu_map.xml b/src/cpu/cpu_map.xml index 12987a0d877978ae734037c1d766d589b31a473d..18c7b0d3cb123cc3bc5afa5df6966602773ae2cc 100644 --- a/src/cpu/cpu_map.xml +++ b/src/cpu/cpu_map.xml @@ -328,7 +328,7 @@ - + diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index af2e08eb8be8c57a01bfcc61d3f5c7105490fe8d..7571f1619a4c0a3cd19d53347975d81fe755b356 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -89,6 +89,7 @@ struct x86_map { struct x86_vendor *vendors; struct x86_feature *features; struct x86_model *models; + struct x86_feature *migrate_blockers; }; static struct x86_map* virCPUx86Map = NULL; @@ -591,6 +592,28 @@ x86FeatureFree(struct x86_feature *feature) } +static struct x86_feature * +x86FeatureCopy(const struct x86_feature *src) +{ + struct x86_feature *feature; + + if (VIR_ALLOC(feature) < 0) + return NULL; + + if (VIR_STRDUP(feature->name, src->name) < 0) + goto error; + + if ((feature->data = x86DataCopy(src->data)) == NULL) + goto error; + + return feature; + + error: + x86FeatureFree(feature); + return NULL; +} + + static struct x86_feature * x86FeatureFind(const struct x86_map *map, const char *name) @@ -677,6 +700,9 @@ x86FeatureLoad(xmlXPathContextPtr ctxt, int ret = 0; size_t i; int n; + char *str = NULL; + bool migratable = true; + struct x86_feature *migrate_blocker = NULL; if (!(feature = x86FeatureNew())) goto error; @@ -694,6 +720,10 @@ x86FeatureLoad(xmlXPathContextPtr ctxt, goto ignore; } + str = virXPathString("string(@migratable)", ctxt); + if (STREQ_NULLABLE(str, "no")) + migratable = false; + n = virXPathNodeSet("./cpuid", ctxt, &nodes); if (n < 0) goto ignore; @@ -710,6 +740,14 @@ x86FeatureLoad(xmlXPathContextPtr ctxt, goto error; } + if (!migratable) { + if ((migrate_blocker = x86FeatureCopy(feature)) == NULL) + goto error; + + migrate_blocker->next = map->migrate_blockers; + map->migrate_blockers = migrate_blocker; + } + if (map->features == NULL) { map->features = feature; } else { @@ -720,6 +758,7 @@ x86FeatureLoad(xmlXPathContextPtr ctxt, out: ctxt->node = ctxt_node; VIR_FREE(nodes); + VIR_FREE(str); return ret; @@ -728,6 +767,7 @@ x86FeatureLoad(xmlXPathContextPtr ctxt, ignore: x86FeatureFree(feature); + x86FeatureFree(migrate_blocker); goto out; } @@ -1093,6 +1133,12 @@ x86MapFree(struct x86_map *map) x86VendorFree(vendor); } + while (map->migrate_blockers != NULL) { + struct x86_feature *migrate_blocker = map->migrate_blockers; + map->migrate_blockers = migrate_blocker->next; + x86FeatureFree(migrate_blocker); + } + VIR_FREE(map); } @@ -2025,16 +2071,15 @@ x86UpdateHostModel(virCPUDefPtr guest, const virCPUDef *host) { virCPUDefPtr oldguest = NULL; + const struct x86_map *map; + const struct x86_feature *feat; size_t i; int ret = -1; guest->match = VIR_CPU_MATCH_EXACT; - /* no updates are required */ - if (guest->nfeatures == 0) { - virCPUDefFreeModel(guest); - return virCPUDefCopyModel(guest, host, true); - } + if (!(map = virCPUx86GetMap())) + goto cleanup; /* update the host model according to the desired configuration */ if (!(oldguest = virCPUDefCopy(guest))) @@ -2044,6 +2089,16 @@ x86UpdateHostModel(virCPUDefPtr guest, if (virCPUDefCopyModel(guest, host, true) < 0) goto cleanup; + /* Remove non-migratable features by default + * Note: this only works as long as no CPU model contains non-migratable + * features directly */ + for (i = 0; i < guest->nfeatures; i++) { + for (feat = map->migrate_blockers; feat; feat = feat->next) { + if (STREQ(feat->name, guest->features[i].name)) + VIR_DELETE_ELEMENT_INPLACE(guest->features, i, guest->nfeatures); + } + } + for (i = 0; i < oldguest->nfeatures; i++) { if (virCPUDefUpdateFeature(guest, oldguest->features[i].name, diff --git a/tests/cputest.c b/tests/cputest.c index 94c0ebceadf4b66c1d3bd912f0d57471970774b8..a5075768fca9f272348370bc98d0b94e9220b679 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -599,6 +599,7 @@ mymain(void) DO_TEST_UPDATE("x86", "host", "host-model", VIR_CPU_COMPARE_IDENTICAL); DO_TEST_UPDATE("x86", "host", "host-model-nofallback", VIR_CPU_COMPARE_IDENTICAL); DO_TEST_UPDATE("x86", "host", "host-passthrough", VIR_CPU_COMPARE_IDENTICAL); + DO_TEST_UPDATE("x86", "host-invtsc", "host-model", VIR_CPU_COMPARE_SUPERSET); /* computing baseline CPUs */ DO_TEST_BASELINE("x86", "incompatible-vendors", 0, -1); diff --git a/tests/cputestdata/x86-host-invtsc+host-model.xml b/tests/cputestdata/x86-host-invtsc+host-model.xml new file mode 100644 index 0000000000000000000000000000000000000000..ad1bbf807cbb54bf4beafd8211ecd10f71ea9c77 --- /dev/null +++ b/tests/cputestdata/x86-host-invtsc+host-model.xml @@ -0,0 +1,22 @@ + + SandyBridge + Intel + + + + + + + + + + + + + + + + + + + diff --git a/tests/cputestdata/x86-host-invtsc.xml b/tests/cputestdata/x86-host-invtsc.xml new file mode 100644 index 0000000000000000000000000000000000000000..f5583992e1d9e180133fa97fc46256937f74377c --- /dev/null +++ b/tests/cputestdata/x86-host-invtsc.xml @@ -0,0 +1,27 @@ + + x86_64 + SandyBridge + Intel + + + + + + + + + + + + + + + + + + + + + + +