mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
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:
parent
f7dd3a4e62
commit
277bc0dcb8
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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>
|
19
tests/cputestdata/x86-host+host-model-nofallback.xml
Normal file
19
tests/cputestdata/x86-host+host-model-nofallback.xml
Normal 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>
|
18
tests/cputestdata/x86-host+host-model.xml
Normal file
18
tests/cputestdata/x86-host+host-model.xml
Normal 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>
|
18
tests/cputestdata/x86-host+host-passthrough.xml
Normal file
18
tests/cputestdata/x86-host+host-passthrough.xml
Normal 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>
|
4
tests/cputestdata/x86-host-model-nofallback.xml
Normal file
4
tests/cputestdata/x86-host-model-nofallback.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<cpu mode='host-model'>
|
||||||
|
<model fallback='forbid'/>
|
||||||
|
<topology sockets='1' cores='2' threads='1'/>
|
||||||
|
</cpu>
|
1
tests/cputestdata/x86-host-model.xml
Normal file
1
tests/cputestdata/x86-host-model.xml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<cpu mode='host-model'/>
|
1
tests/cputestdata/x86-host-passthrough.xml
Normal file
1
tests/cputestdata/x86-host-passthrough.xml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<cpu mode='host-passthrough'/>
|
Loading…
Reference in New Issue
Block a user