diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 52a6353bd6..d2dbcb8ca9 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -901,11 +901,15 @@
copying host CPU definition from capabilities XML into domain XML.
Since the CPU definition is copied just before starting a domain,
exactly the same XML can be used on different hosts while still
- providing the best guest CPU each host supports. Neither
- match
attribute nor any feature
elements
- can be used in this mode. Specifying CPU model is not supported
- either, but model
's fallback
attribute may
- still be used. Libvirt does not model every aspect of each CPU so
+ providing the best guest CPU each host supports. The
+ match
attribute can't be used in this mode. Specifying
+ CPU model is not supported either, but model
's
+ fallback
attribute may still be used. Using the
+ feature
element, specific flags may be enabled or
+ disabled specifically in addition to the host model. This may be
+ used to fine tune features that can be emulated.
+ (Since 1.1.1).
+ Libvirt does not model every aspect of each CPU so
the guest CPU will not match the host CPU exactly. On the other
hand, the ABI provided to the guest is reproducible. During
migration, complete CPU model definition is transferred to the
diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c
index 1e657ad91e..d3fbebac67 100644
--- a/src/conf/cpu_conf.c
+++ b/src/conf/cpu_conf.c
@@ -361,7 +361,7 @@ virCPUDefParseXML(const xmlNodePtr node,
goto error;
if (n > 0) {
- if (!def->model) {
+ if (!def->model && def->mode != VIR_CPU_MODE_HOST_MODEL) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("Non-empty feature list specified without "
"CPU model"));
@@ -574,7 +574,9 @@ virCPUDefFormatBuf(virBufferPtr buf,
(def->mode == VIR_CPU_MODE_HOST_MODEL ||
(def->mode == VIR_CPU_MODE_CUSTOM && def->model)));
- if (!def->model && def->nfeatures) {
+ if (!def->model &&
+ def->mode != VIR_CPU_MODE_HOST_MODEL &&
+ def->nfeatures) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Non-empty feature list specified without CPU model"));
return -1;
@@ -614,32 +616,30 @@ virCPUDefFormatBuf(virBufferPtr buf,
virBufferAddLit(buf, "/>\n");
}
- if (formatModel) {
- for (i = 0; i < def->nfeatures; i++) {
- virCPUFeatureDefPtr feature = def->features + i;
+ for (i = 0; i < def->nfeatures; i++) {
+ virCPUFeatureDefPtr feature = def->features + i;
- if (!feature->name) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("Missing CPU feature name"));
+ if (!feature->name) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Missing CPU feature name"));
+ return -1;
+ }
+
+ if (def->type == VIR_CPU_TYPE_GUEST) {
+ const char *policy;
+
+ policy = virCPUFeaturePolicyTypeToString(feature->policy);
+ if (!policy) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unexpected CPU feature policy %d"),
+ feature->policy);
return -1;
}
-
- if (def->type == VIR_CPU_TYPE_GUEST) {
- const char *policy;
-
- policy = virCPUFeaturePolicyTypeToString(feature->policy);
- if (!policy) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Unexpected CPU feature policy %d"),
- feature->policy);
- return -1;
- }
- virBufferAsprintf(buf, "\n",
- policy, feature->name);
- } else {
- virBufferAsprintf(buf, "\n",
- feature->name);
- }
+ virBufferAsprintf(buf, "\n",
+ policy, feature->name);
+ } else {
+ virBufferAsprintf(buf, "\n",
+ feature->name);
}
}
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 928a67b96a..cc7926e779 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -1739,6 +1739,41 @@ cleanup:
return ret;
}
+
+static int
+x86UpdateHostModel(virCPUDefPtr guest,
+ const virCPUDefPtr host)
+{
+ virCPUDefPtr oldguest;
+ size_t i;
+
+ guest->match = VIR_CPU_MATCH_EXACT;
+
+ /* no updates are required */
+ if (guest->nfeatures == 0) {
+ virCPUDefFreeModel(guest);
+ return virCPUDefCopyModel(guest, host, true);
+ }
+
+ /* update the host model according to the desired configuration */
+ if (!(oldguest = virCPUDefCopy(guest)))
+ return -1;
+
+ virCPUDefFreeModel(guest);
+ if (virCPUDefCopyModel(guest, host, true) < 0)
+ return -1;
+
+ for (i = 0; i < oldguest->nfeatures; i++) {
+ if (virCPUDefUpdateFeature(guest,
+ oldguest->features[i].name,
+ oldguest->features[i].policy) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
static int
x86Update(virCPUDefPtr guest,
const virCPUDefPtr host)
@@ -1748,11 +1783,10 @@ x86Update(virCPUDefPtr guest,
return x86UpdateCustom(guest, host);
case VIR_CPU_MODE_HOST_MODEL:
+ return x86UpdateHostModel(guest, host);
+
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;
+ guest->match = VIR_CPU_MATCH_MINIMUM;
virCPUDefFreeModel(guest);
return virCPUDefCopyModel(guest, host, true);