[libvirt] [PATCH v2 4/6] cpu: Update guest CPU in host-* mode

Jiri Denemark jdenemar at redhat.com
Thu Jan 12 11:02:58 UTC 2012


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




More information about the libvir-list mailing list