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