cpu: Update guest CPU in host-* mode

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-passthrough CPU modes.
This commit is contained in:
Jiri Denemark 2011-12-19 15:41:16 +01:00
parent f7dd3a4e62
commit 277bc0dcb8
13 changed files with 194 additions and 31 deletions

View File

@ -61,6 +61,19 @@ VIR_ENUM_IMPL(virCPUFeaturePolicy, VIR_CPU_FEATURE_LAST,
"forbid") "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 void
virCPUDefFree(virCPUDefPtr def) virCPUDefFree(virCPUDefPtr def)
{ {
@ -69,13 +82,8 @@ virCPUDefFree(virCPUDefPtr def)
if (!def) if (!def)
return; return;
VIR_FREE(def->model);
VIR_FREE(def->arch); VIR_FREE(def->arch);
VIR_FREE(def->vendor); virCPUDefFreeModel(def);
for (i = 0 ; i < def->nfeatures ; i++)
VIR_FREE(def->features[i].name);
VIR_FREE(def->features);
for (i = 0 ; i < def->ncells ; i++) { for (i = 0 ; i < def->ncells ; i++) {
VIR_FREE(def->cells[i].cpumask); 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 virCPUDefPtr
virCPUDefCopy(const virCPUDefPtr cpu) virCPUDefCopy(const virCPUDefPtr cpu)
{ {
@ -96,13 +140,8 @@ virCPUDefCopy(const virCPUDefPtr cpu)
if (!cpu) if (!cpu)
return NULL; return NULL;
if (VIR_ALLOC(copy) < 0 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)
goto no_memory; goto no_memory;
copy->nfeatures_max = cpu->nfeatures;
copy->type = cpu->type; copy->type = cpu->type;
copy->mode = cpu->mode; copy->mode = cpu->mode;
@ -111,13 +150,12 @@ virCPUDefCopy(const virCPUDefPtr cpu)
copy->sockets = cpu->sockets; copy->sockets = cpu->sockets;
copy->cores = cpu->cores; copy->cores = cpu->cores;
copy->threads = cpu->threads; copy->threads = cpu->threads;
copy->nfeatures = cpu->nfeatures;
for (i = 0; i < copy->nfeatures; i++) { if (cpu->arch && !(copy->arch = strdup(cpu->arch)))
copy->features[i].policy = cpu->features[i].policy; goto no_memory;
if (!(copy->features[i].name = strdup(cpu->features[i].name)))
goto no_memory; if (virCPUDefCopyModel(copy, cpu, false) < 0)
} goto error;
if (cpu->ncells) { if (cpu->ncells) {
if (VIR_ALLOC_N(copy->cells, cpu->ncells) < 0) if (VIR_ALLOC_N(copy->cells, cpu->ncells) < 0)
@ -144,6 +182,7 @@ virCPUDefCopy(const virCPUDefPtr cpu)
no_memory: no_memory:
virReportOOMError(); virReportOOMError();
error:
virCPUDefFree(copy); virCPUDefFree(copy);
return NULL; return NULL;
} }

View File

@ -118,9 +118,17 @@ struct _virCPUDef {
}; };
void ATTRIBUTE_NONNULL(1)
virCPUDefFreeModel(virCPUDefPtr def);
void void
virCPUDefFree(virCPUDefPtr def); virCPUDefFree(virCPUDefPtr def);
int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
virCPUDefCopyModel(virCPUDefPtr dst,
const virCPUDefPtr src,
bool resetPolicy);
virCPUDefPtr virCPUDefPtr
virCPUDefCopy(const virCPUDefPtr cpu); virCPUDefCopy(const virCPUDefPtr cpu);

View File

@ -1686,8 +1686,8 @@ error:
static int static int
x86Update(virCPUDefPtr guest, x86UpdateCustom(virCPUDefPtr guest,
const virCPUDefPtr host) const virCPUDefPtr host)
{ {
int ret = -1; int ret = -1;
unsigned int i; unsigned int i;
@ -1731,6 +1731,32 @@ cleanup:
return ret; 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, static int x86HasFeature(const union cpuData *data,
const char *name) const char *name)
{ {

View File

@ -181,9 +181,11 @@ cpuUpdate;
# cpu_conf.h # cpu_conf.h
virCPUDefAddFeature; virCPUDefAddFeature;
virCPUDefCopy; virCPUDefCopy;
virCPUDefCopyModel;
virCPUDefFormat; virCPUDefFormat;
virCPUDefFormatBuf; virCPUDefFormatBuf;
virCPUDefFree; virCPUDefFree;
virCPUDefFreeModel;
virCPUDefParseXML; virCPUDefParseXML;

View File

@ -1050,20 +1050,20 @@ char *qemuDomainDefFormatXML(struct qemud_driver *driver,
{ {
char *ret = NULL; char *ret = NULL;
virCPUDefPtr cpu = NULL; virCPUDefPtr cpu = NULL;
virCPUDefPtr def_cpu; virCPUDefPtr def_cpu = def->cpu;
def_cpu = def->cpu;
/* Update guest CPU requirements according to host 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) { if (!driver->caps || !driver->caps->host.cpu) {
qemuReportError(VIR_ERR_OPERATION_FAILED, qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("cannot get host CPU capabilities")); "%s", _("cannot get host CPU capabilities"));
goto cleanup; goto cleanup;
} }
if (!(cpu = virCPUDefCopy(def_cpu)) if (!(cpu = virCPUDefCopy(def_cpu)) ||
|| cpuUpdate(cpu, driver->caps->host.cpu)) cpuUpdate(cpu, driver->caps->host.cpu) < 0)
goto cleanup; goto cleanup;
def->cpu = cpu; def->cpu = cpu;
} }

View File

@ -162,7 +162,8 @@ error:
static int static int
cpuTestCompareXML(const char *arch, cpuTestCompareXML(const char *arch,
const virCPUDefPtr cpu, const virCPUDefPtr cpu,
const char *name) const char *name,
unsigned int flags)
{ {
char *xml = NULL; char *xml = NULL;
char *expected = NULL; char *expected = NULL;
@ -176,7 +177,7 @@ cpuTestCompareXML(const char *arch,
if (virtTestLoadFile(xml, &expected) < 0) if (virtTestLoadFile(xml, &expected) < 0)
goto cleanup; goto cleanup;
if (!(actual = virCPUDefFormat(cpu, 0))) if (!(actual = virCPUDefFormat(cpu, flags)))
goto cleanup; goto cleanup;
if (STRNEQ(expected, actual)) { if (STRNEQ(expected, actual)) {
@ -310,7 +311,7 @@ cpuTestGuestData(const void *arg)
} }
result = virBufferContentAndReset(&buf); result = virBufferContentAndReset(&buf);
ret = cpuTestCompareXML(data->arch, guest, result); ret = cpuTestCompareXML(data->arch, guest, result, 0);
cleanup: cleanup:
VIR_FREE(result); VIR_FREE(result);
@ -354,7 +355,7 @@ cpuTestBaseline(const void *arg)
if (virAsprintf(&result, "%s-result", data->name) < 0) if (virAsprintf(&result, "%s-result", data->name) < 0)
goto cleanup; goto cleanup;
if (cpuTestCompareXML(data->arch, baseline, result) < 0) if (cpuTestCompareXML(data->arch, baseline, result, 0) < 0)
goto cleanup; goto cleanup;
for (i = 0; i < ncpus; i++) { for (i = 0; i < ncpus; i++) {
@ -406,7 +407,8 @@ cpuTestUpdate(const void *arg)
if (virAsprintf(&result, "%s+%s", data->host, data->name) < 0) if (virAsprintf(&result, "%s+%s", data->host, data->name) < 0)
goto cleanup; goto cleanup;
ret = cpuTestCompareXML(data->arch, cpu, result); ret = cpuTestCompareXML(data->arch, cpu, result,
VIR_DOMAIN_XML_UPDATE_CPU);
cleanup: cleanup:
virCPUDefFree(host); virCPUDefFree(host);
@ -592,6 +594,9 @@ mymain(void)
DO_TEST_UPDATE("x86", "host", "min", IDENTICAL); DO_TEST_UPDATE("x86", "host", "min", IDENTICAL);
DO_TEST_UPDATE("x86", "host", "pentium3", IDENTICAL); DO_TEST_UPDATE("x86", "host", "pentium3", IDENTICAL);
DO_TEST_UPDATE("x86", "host", "guest", SUPERSET); 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 */ /* computing baseline CPUs */
DO_TEST_BASELINE("x86", "incompatible-vendors", -1); 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", models, "qemu64", 0);
DO_TEST_GUESTDATA("x86", "host", "guest", nomodel, NULL, -1); DO_TEST_GUESTDATA("x86", "host", "guest", nomodel, NULL, -1);
DO_TEST_GUESTDATA("x86", "host", "guest-nofallback", models, "Penryn", -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); free(map);
return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE); return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,4 @@
<cpu mode='host-model'>
<model fallback='forbid'/>
<topology sockets='1' cores='2' threads='1'/>
</cpu>

View File

@ -0,0 +1 @@
<cpu mode='host-model'/>

View File

@ -0,0 +1 @@
<cpu mode='host-passthrough'/>