VIR_DOMAIN_XML_UPDATE_CPU flag for virDomainGetXMLDesc may be used to get updated custom mode guest CPU definition in case it depends on host CPU. This patch implements the same behavior for host-model and host-passtrhough CPU modes. --- Notes: Version 2: - more verbose commit message src/conf/cpu_conf.c | 75 +++++++++++++++----- src/conf/cpu_conf.h | 8 ++ src/cpu/cpu_x86.c | 30 +++++++- src/libvirt_private.syms | 2 + src/qemu/qemu_domain.c | 12 ++-- tests/cputest.c | 18 ++++-- ...6-host+host+host-model,models,Penryn-result.xml | 19 +++++ .../cputestdata/x86-host+host-model-nofallback.xml | 19 +++++ tests/cputestdata/x86-host+host-model.xml | 18 +++++ tests/cputestdata/x86-host+host-passthrough.xml | 18 +++++ tests/cputestdata/x86-host-model-nofallback.xml | 4 + tests/cputestdata/x86-host-model.xml | 1 + tests/cputestdata/x86-host-passthrough.xml | 1 + 13 files changed, 194 insertions(+), 31 deletions(-) create mode 100644 tests/cputestdata/x86-host+host+host-model,models,Penryn-result.xml create mode 100644 tests/cputestdata/x86-host+host-model-nofallback.xml create mode 100644 tests/cputestdata/x86-host+host-model.xml create mode 100644 tests/cputestdata/x86-host+host-passthrough.xml create mode 100644 tests/cputestdata/x86-host-model-nofallback.xml create mode 100644 tests/cputestdata/x86-host-model.xml create mode 100644 tests/cputestdata/x86-host-passthrough.xml diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c index 31862e2..018d571 100644 --- a/src/conf/cpu_conf.c +++ b/src/conf/cpu_conf.c @@ -61,6 +61,19 @@ VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST, "forbid") +void ATTRIBUTE_NONNULL(1) +virCPUDefFreeModel(virCPUDefPtr def) +{ + unsigned int i; + + VIR_FREE(def->model); + VIR_FREE(def->vendor); + + for (i = 0; i < def->nfeatures; i++) + VIR_FREE(def->features[i].name); + VIR_FREE(def->features); +} + void virCPUDefFree(virCPUDefPtr def) { @@ -69,13 +82,8 @@ virCPUDefFree(virCPUDefPtr def) if (!def) return; - VIR_FREE(def->model); VIR_FREE(def->arch); - VIR_FREE(def->vendor); - - for (i = 0 ; i < def->nfeatures ; i++) - VIR_FREE(def->features[i].name); - VIR_FREE(def->features); + virCPUDefFreeModel(def); for (i = 0 ; i < def->ncells ; i++) { VIR_FREE(def->cells[i].cpumask); @@ -87,6 +95,42 @@ virCPUDefFree(virCPUDefPtr def) } +int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) +virCPUDefCopyModel(virCPUDefPtr dst, + const virCPUDefPtr src, + bool resetPolicy) +{ + unsigned int i; + + if ((src->model && !(dst->model = strdup(src->model))) + || (src->vendor && !(dst->vendor = strdup(src->vendor))) + || VIR_ALLOC_N(dst->features, src->nfeatures) < 0) + goto no_memory; + dst->nfeatures_max = dst->nfeatures = src->nfeatures; + + for (i = 0; i < dst->nfeatures; i++) { + if (dst->type != src->type && resetPolicy) { + if (dst->type == VIR_CPU_TYPE_HOST) + dst->features[i].policy = -1; + else if (src->features[i].policy == -1) + dst->features[i].policy = VIR_CPU_FEATURE_REQUIRE; + else + dst->features[i].policy = src->features[i].policy; + } else { + dst->features[i].policy = src->features[i].policy; + } + + if (!(dst->features[i].name = strdup(src->features[i].name))) + goto no_memory; + } + + return 0; + +no_memory: + virReportOOMError(); + return -1; +} + virCPUDefPtr virCPUDefCopy(const virCPUDefPtr cpu) { @@ -96,13 +140,8 @@ virCPUDefCopy(const virCPUDefPtr cpu) if (!cpu) return NULL; - if (VIR_ALLOC(copy) < 0 - || (cpu->arch && !(copy->arch = strdup(cpu->arch))) - || (cpu->model && !(copy->model = strdup(cpu->model))) - || (cpu->vendor && !(copy->vendor = strdup(cpu->vendor))) - || VIR_ALLOC_N(copy->features, cpu->nfeatures) < 0) + if (VIR_ALLOC(copy) < 0) goto no_memory; - copy->nfeatures_max = cpu->nfeatures; copy->type = cpu->type; copy->mode = cpu->mode; @@ -111,13 +150,12 @@ virCPUDefCopy(const virCPUDefPtr cpu) copy->sockets = cpu->sockets; copy->cores = cpu->cores; copy->threads = cpu->threads; - copy->nfeatures = cpu->nfeatures; - for (i = 0; i < copy->nfeatures; i++) { - copy->features[i].policy = cpu->features[i].policy; - if (!(copy->features[i].name = strdup(cpu->features[i].name))) - goto no_memory; - } + if (cpu->arch && !(copy->arch = strdup(cpu->arch))) + goto no_memory; + + if (virCPUDefCopyModel(copy, cpu, false) < 0) + goto error; if (cpu->ncells) { if (VIR_ALLOC_N(copy->cells, cpu->ncells) < 0) @@ -144,6 +182,7 @@ virCPUDefCopy(const virCPUDefPtr cpu) no_memory: virReportOOMError(); +error: virCPUDefFree(copy); return NULL; } diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h index 4b0b35b..f8b7bf9 100644 --- a/src/conf/cpu_conf.h +++ b/src/conf/cpu_conf.h @@ -118,9 +118,17 @@ struct _virCPUDef { }; +void ATTRIBUTE_NONNULL(1) +virCPUDefFreeModel(virCPUDefPtr def); + void virCPUDefFree(virCPUDefPtr def); +int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) +virCPUDefCopyModel(virCPUDefPtr dst, + const virCPUDefPtr src, + bool resetPolicy); + virCPUDefPtr virCPUDefCopy(const virCPUDefPtr cpu); diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c index ad2d5cd..308604b 100644 --- a/src/cpu/cpu_x86.c +++ b/src/cpu/cpu_x86.c @@ -1686,8 +1686,8 @@ error: static int -x86Update(virCPUDefPtr guest, - const virCPUDefPtr host) +x86UpdateCustom(virCPUDefPtr guest, + const virCPUDefPtr host) { int ret = -1; unsigned int i; @@ -1731,6 +1731,32 @@ cleanup: return ret; } +static int +x86Update(virCPUDefPtr guest, + const virCPUDefPtr host) +{ + switch ((enum virCPUMode) guest->mode) { + case VIR_CPU_MODE_CUSTOM: + return x86UpdateCustom(guest, host); + + case VIR_CPU_MODE_HOST_MODEL: + case VIR_CPU_MODE_HOST_PASSTHROUGH: + if (guest->mode == VIR_CPU_MODE_HOST_MODEL) + guest->match = VIR_CPU_MATCH_EXACT; + else + guest->match = VIR_CPU_MATCH_MINIMUM; + virCPUDefFreeModel(guest); + return virCPUDefCopyModel(guest, host, true); + + case VIR_CPU_MODE_LAST: + break; + } + + virCPUReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected CPU mode: %d"), guest->mode); + return -1; +} + static int x86HasFeature(const union cpuData *data, const char *name) { diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ca4beb1..ac2a892 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -181,9 +181,11 @@ cpuUpdate; # cpu_conf.h virCPUDefAddFeature; virCPUDefCopy; +virCPUDefCopyModel; virCPUDefFormat; virCPUDefFormatBuf; virCPUDefFree; +virCPUDefFreeModel; virCPUDefParseXML; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 6b03c62..a25f4df 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1050,20 +1050,20 @@ char *qemuDomainDefFormatXML(struct qemud_driver *driver, { char *ret = NULL; virCPUDefPtr cpu = NULL; - virCPUDefPtr def_cpu; - - def_cpu = def->cpu; + virCPUDefPtr def_cpu = def->cpu; /* Update guest CPU requirements according to host CPU */ - if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) && def_cpu && def_cpu->model) { + if ((flags & VIR_DOMAIN_XML_UPDATE_CPU) && + def_cpu && + (def_cpu->mode != VIR_CPU_MODE_CUSTOM || def_cpu->model)) { if (!driver->caps || !driver->caps->host.cpu) { qemuReportError(VIR_ERR_OPERATION_FAILED, "%s", _("cannot get host CPU capabilities")); goto cleanup; } - if (!(cpu = virCPUDefCopy(def_cpu)) - || cpuUpdate(cpu, driver->caps->host.cpu)) + if (!(cpu = virCPUDefCopy(def_cpu)) || + cpuUpdate(cpu, driver->caps->host.cpu) < 0) goto cleanup; def->cpu = cpu; } diff --git a/tests/cputest.c b/tests/cputest.c index d8c1713..938e087 100644 --- a/tests/cputest.c +++ b/tests/cputest.c @@ -162,7 +162,8 @@ error: static int cpuTestCompareXML(const char *arch, const virCPUDefPtr cpu, - const char *name) + const char *name, + unsigned int flags) { char *xml = NULL; char *expected = NULL; @@ -176,7 +177,7 @@ cpuTestCompareXML(const char *arch, if (virtTestLoadFile(xml, &expected) < 0) goto cleanup; - if (!(actual = virCPUDefFormat(cpu, 0))) + if (!(actual = virCPUDefFormat(cpu, flags))) goto cleanup; if (STRNEQ(expected, actual)) { @@ -310,7 +311,7 @@ cpuTestGuestData(const void *arg) } result = virBufferContentAndReset(&buf); - ret = cpuTestCompareXML(data->arch, guest, result); + ret = cpuTestCompareXML(data->arch, guest, result, 0); cleanup: VIR_FREE(result); @@ -354,7 +355,7 @@ cpuTestBaseline(const void *arg) if (virAsprintf(&result, "%s-result", data->name) < 0) goto cleanup; - if (cpuTestCompareXML(data->arch, baseline, result) < 0) + if (cpuTestCompareXML(data->arch, baseline, result, 0) < 0) goto cleanup; for (i = 0; i < ncpus; i++) { @@ -406,7 +407,8 @@ cpuTestUpdate(const void *arg) if (virAsprintf(&result, "%s+%s", data->host, data->name) < 0) goto cleanup; - ret = cpuTestCompareXML(data->arch, cpu, result); + ret = cpuTestCompareXML(data->arch, cpu, result, + VIR_DOMAIN_XML_UPDATE_CPU); cleanup: virCPUDefFree(host); @@ -592,6 +594,9 @@ mymain(void) DO_TEST_UPDATE("x86", "host", "min", IDENTICAL); DO_TEST_UPDATE("x86", "host", "pentium3", IDENTICAL); DO_TEST_UPDATE("x86", "host", "guest", SUPERSET); + DO_TEST_UPDATE("x86", "host", "host-model", IDENTICAL); + DO_TEST_UPDATE("x86", "host", "host-model-nofallback", IDENTICAL); + DO_TEST_UPDATE("x86", "host", "host-passthrough", IDENTICAL); /* computing baseline CPUs */ DO_TEST_BASELINE("x86", "incompatible-vendors", -1); @@ -622,6 +627,9 @@ mymain(void) DO_TEST_GUESTDATA("x86", "host", "guest", models, "qemu64", 0); DO_TEST_GUESTDATA("x86", "host", "guest", nomodel, NULL, -1); DO_TEST_GUESTDATA("x86", "host", "guest-nofallback", models, "Penryn", -1); + DO_TEST_GUESTDATA("x86", "host", "host+host-model", models, "Penryn", 0); + DO_TEST_GUESTDATA("x86", "host", "host+host-model-nofallback", + models, "Penryn", -1); free(map); return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); diff --git a/tests/cputestdata/x86-host+host+host-model,models,Penryn-result.xml b/tests/cputestdata/x86-host+host+host-model,models,Penryn-result.xml new file mode 100644 index 0000000..e2b7f5b --- /dev/null +++ b/tests/cputestdata/x86-host+host+host-model,models,Penryn-result.xml @@ -0,0 +1,19 @@ +<cpu mode='custom' match='exact'> + <arch>x86_64</arch> + <model fallback='allow'>core2duo</model> + <feature policy='require' name='lahf_lm'/> + <feature policy='require' name='sse4.1'/> + <feature policy='require' name='dca'/> + <feature policy='require' name='xtpr'/> + <feature policy='require' name='cx16'/> + <feature policy='require' name='tm2'/> + <feature policy='require' name='est'/> + <feature policy='require' name='vmx'/> + <feature policy='require' name='ds_cpl'/> + <feature policy='require' name='pbe'/> + <feature policy='require' name='tm'/> + <feature policy='require' name='ht'/> + <feature policy='require' name='ss'/> + <feature policy='require' name='acpi'/> + <feature policy='require' name='ds'/> +</cpu> diff --git a/tests/cputestdata/x86-host+host-model-nofallback.xml b/tests/cputestdata/x86-host+host-model-nofallback.xml new file mode 100644 index 0000000..bbb68fb --- /dev/null +++ b/tests/cputestdata/x86-host+host-model-nofallback.xml @@ -0,0 +1,19 @@ +<cpu mode='host-model' match='exact'> + <model fallback='forbid'>Penryn</model> + <vendor>Intel</vendor> + <topology sockets='1' cores='2' threads='1'/> + <feature policy='require' name='dca'/> + <feature policy='require' name='xtpr'/> + <feature policy='require' name='tm2'/> + <feature policy='require' name='est'/> + <feature policy='require' name='vmx'/> + <feature policy='require' name='ds_cpl'/> + <feature policy='require' name='monitor'/> + <feature policy='require' name='pbe'/> + <feature policy='require' name='tm'/> + <feature policy='require' name='ht'/> + <feature policy='require' name='ss'/> + <feature policy='require' name='acpi'/> + <feature policy='require' name='ds'/> + <feature policy='require' name='vme'/> +</cpu> diff --git a/tests/cputestdata/x86-host+host-model.xml b/tests/cputestdata/x86-host+host-model.xml new file mode 100644 index 0000000..c1014e2 --- /dev/null +++ b/tests/cputestdata/x86-host+host-model.xml @@ -0,0 +1,18 @@ +<cpu mode='host-model' match='exact'> + <model fallback='allow'>Penryn</model> + <vendor>Intel</vendor> + <feature policy='require' name='dca'/> + <feature policy='require' name='xtpr'/> + <feature policy='require' name='tm2'/> + <feature policy='require' name='est'/> + <feature policy='require' name='vmx'/> + <feature policy='require' name='ds_cpl'/> + <feature policy='require' name='monitor'/> + <feature policy='require' name='pbe'/> + <feature policy='require' name='tm'/> + <feature policy='require' name='ht'/> + <feature policy='require' name='ss'/> + <feature policy='require' name='acpi'/> + <feature policy='require' name='ds'/> + <feature policy='require' name='vme'/> +</cpu> diff --git a/tests/cputestdata/x86-host+host-passthrough.xml b/tests/cputestdata/x86-host+host-passthrough.xml new file mode 100644 index 0000000..721fae5 --- /dev/null +++ b/tests/cputestdata/x86-host+host-passthrough.xml @@ -0,0 +1,18 @@ +<cpu mode='host-passthrough' match='minimum'> + <model>Penryn</model> + <vendor>Intel</vendor> + <feature policy='require' name='dca'/> + <feature policy='require' name='xtpr'/> + <feature policy='require' name='tm2'/> + <feature policy='require' name='est'/> + <feature policy='require' name='vmx'/> + <feature policy='require' name='ds_cpl'/> + <feature policy='require' name='monitor'/> + <feature policy='require' name='pbe'/> + <feature policy='require' name='tm'/> + <feature policy='require' name='ht'/> + <feature policy='require' name='ss'/> + <feature policy='require' name='acpi'/> + <feature policy='require' name='ds'/> + <feature policy='require' name='vme'/> +</cpu> diff --git a/tests/cputestdata/x86-host-model-nofallback.xml b/tests/cputestdata/x86-host-model-nofallback.xml new file mode 100644 index 0000000..4e42eb4 --- /dev/null +++ b/tests/cputestdata/x86-host-model-nofallback.xml @@ -0,0 +1,4 @@ +<cpu mode='host-model'> + <model fallback='forbid'/> + <topology sockets='1' cores='2' threads='1'/> +</cpu> diff --git a/tests/cputestdata/x86-host-model.xml b/tests/cputestdata/x86-host-model.xml new file mode 100644 index 0000000..fd50c03 --- /dev/null +++ b/tests/cputestdata/x86-host-model.xml @@ -0,0 +1 @@ +<cpu mode='host-model'/> diff --git a/tests/cputestdata/x86-host-passthrough.xml b/tests/cputestdata/x86-host-passthrough.xml new file mode 100644 index 0000000..655c7a7 --- /dev/null +++ b/tests/cputestdata/x86-host-passthrough.xml @@ -0,0 +1 @@ +<cpu mode='host-passthrough'/> -- 1.7.8.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list