提交 def9401a 编写于 作者: J Jiri Denemark

qemu: Update CPU definition according to QEMU

When starting a domain with custom guest CPU specification QEMU may add
or remove some CPU features. There are several reasons for this, e.g.,
QEMU/KVM does not support some requested features or the definition of
the requested CPU model in libvirt's cpu_map.xml differs from the one
QEMU is using. We can't really avoid this because CPU models are allowed
to change with machine types and libvirt doesn't know (and probably
doesn't even want to know) about such changes.

Thus when we want to make sure guest ABI doesn't change when a domain
gets migrated to another host, we need to update our live CPU definition
according to the CPU QEMU created. Once updated, we will change CPU
checking to VIR_CPU_CHECK_FULL to make sure the virtual CPU created
after migration exactly matches the one on the source.

https://bugzilla.redhat.com/show_bug.cgi?id=822148
https://bugzilla.redhat.com/show_bug.cgi?id=824989Signed-off-by: NJiri Denemark <jdenemar@redhat.com>
上级 77c9c4f1
...@@ -712,6 +712,50 @@ virCPUUpdate(virArch arch, ...@@ -712,6 +712,50 @@ virCPUUpdate(virArch arch,
} }
/**
* virCPUUpdateLive:
*
* @arch: CPU architecture
* @cpu: guest CPU definition to be updated
* @dataEnabled: CPU data of the virtual CPU
* @dataDisabled: CPU data with features requested by @cpu but disabled by the
* hypervisor
*
* Update custom mode CPU according to the virtual CPU created by the
* hypervisor.
*
* Returns -1 on error,
* 0 when the CPU was successfully updated,
* 1 when the operation does not make sense on the CPU or it is not
* supported for the given architecture.
*/
int
virCPUUpdateLive(virArch arch,
virCPUDefPtr cpu,
virCPUDataPtr dataEnabled,
virCPUDataPtr dataDisabled)
{
struct cpuArchDriver *driver;
VIR_DEBUG("arch=%s, cpu=%p, dataEnabled=%p, dataDisabled=%p",
virArchToString(arch), cpu, dataEnabled, dataDisabled);
if (!(driver = cpuGetSubDriver(arch)))
return -1;
if (!driver->updateLive)
return 1;
if (cpu->mode != VIR_CPU_MODE_CUSTOM)
return 1;
if (driver->updateLive(cpu, dataEnabled, dataDisabled) < 0)
return -1;
return 0;
}
/** /**
* virCPUCheckFeature: * virCPUCheckFeature:
* *
......
...@@ -86,6 +86,11 @@ typedef int ...@@ -86,6 +86,11 @@ typedef int
(*virCPUArchUpdate)(virCPUDefPtr guest, (*virCPUArchUpdate)(virCPUDefPtr guest,
const virCPUDef *host); const virCPUDef *host);
typedef int
(*virCPUArchUpdateLive)(virCPUDefPtr cpu,
virCPUDataPtr dataEnabled,
virCPUDataPtr dataDisabled);
typedef int typedef int
(*virCPUArchCheckFeature)(const virCPUDef *cpu, (*virCPUArchCheckFeature)(const virCPUDef *cpu,
const char *feature); const char *feature);
...@@ -122,6 +127,7 @@ struct cpuArchDriver { ...@@ -122,6 +127,7 @@ struct cpuArchDriver {
virCPUArchGetHost getHost; virCPUArchGetHost getHost;
cpuArchBaseline baseline; cpuArchBaseline baseline;
virCPUArchUpdate update; virCPUArchUpdate update;
virCPUArchUpdateLive updateLive;
virCPUArchCheckFeature checkFeature; virCPUArchCheckFeature checkFeature;
virCPUArchDataCheckFeature dataCheckFeature; virCPUArchDataCheckFeature dataCheckFeature;
virCPUArchDataFormat dataFormat; virCPUArchDataFormat dataFormat;
...@@ -198,6 +204,12 @@ virCPUUpdate(virArch arch, ...@@ -198,6 +204,12 @@ virCPUUpdate(virArch arch,
const virCPUDef *host) const virCPUDef *host)
ATTRIBUTE_NONNULL(2); ATTRIBUTE_NONNULL(2);
int
virCPUUpdateLive(virArch arch,
virCPUDefPtr cpu,
virCPUDataPtr dataEnabled,
virCPUDataPtr dataDisabled)
ATTRIBUTE_NONNULL(2);
int int
virCPUCheckFeature(virArch arch, virCPUCheckFeature(virArch arch,
......
...@@ -2677,6 +2677,64 @@ virCPUx86Update(virCPUDefPtr guest, ...@@ -2677,6 +2677,64 @@ virCPUx86Update(virCPUDefPtr guest,
} }
static int
virCPUx86UpdateLive(virCPUDefPtr cpu,
virCPUDataPtr dataEnabled,
virCPUDataPtr dataDisabled)
{
virCPUx86MapPtr map;
virCPUx86ModelPtr model = NULL;
virCPUx86Data enabled = VIR_CPU_X86_DATA_INIT;
virCPUx86Data disabled = VIR_CPU_X86_DATA_INIT;
size_t i;
int ret = -1;
if (!(map = virCPUx86GetMap()))
return -1;
if (!(model = x86ModelFromCPU(cpu, map, -1)))
goto cleanup;
if (dataEnabled &&
x86DataCopy(&enabled, &dataEnabled->data.x86) < 0)
goto cleanup;
if (dataDisabled &&
x86DataCopy(&disabled, &dataDisabled->data.x86) < 0)
goto cleanup;
x86DataSubtract(&enabled, &model->data);
for (i = 0; i < map->nfeatures; i++) {
virCPUx86FeaturePtr feature = map->features[i];
if (x86DataIsSubset(&enabled, &feature->data)) {
VIR_DEBUG("Adding feature '%s' enabled by the hypervisor",
feature->name);
if (virCPUDefUpdateFeature(cpu, feature->name,
VIR_CPU_FEATURE_REQUIRE) < 0)
goto cleanup;
}
if (x86DataIsSubset(&disabled, &feature->data)) {
VIR_DEBUG("Removing feature '%s' disabled by the hypervisor",
feature->name);
if (virCPUDefUpdateFeature(cpu, feature->name,
VIR_CPU_FEATURE_DISABLE) < 0)
goto cleanup;
}
}
ret = 0;
cleanup:
x86ModelFree(model);
virCPUx86DataClear(&enabled);
virCPUx86DataClear(&disabled);
return ret;
}
static int static int
virCPUx86CheckFeature(const virCPUDef *cpu, virCPUx86CheckFeature(const virCPUDef *cpu,
const char *name) const char *name)
...@@ -2854,6 +2912,7 @@ struct cpuArchDriver cpuDriverX86 = { ...@@ -2854,6 +2912,7 @@ struct cpuArchDriver cpuDriverX86 = {
#endif #endif
.baseline = x86Baseline, .baseline = x86Baseline,
.update = virCPUx86Update, .update = virCPUx86Update,
.updateLive = virCPUx86UpdateLive,
.checkFeature = virCPUx86CheckFeature, .checkFeature = virCPUx86CheckFeature,
.dataCheckFeature = virCPUx86DataCheckFeature, .dataCheckFeature = virCPUx86DataCheckFeature,
.dataFormat = virCPUx86DataFormat, .dataFormat = virCPUx86DataFormat,
......
...@@ -1016,6 +1016,7 @@ virCPUGetHost; ...@@ -1016,6 +1016,7 @@ virCPUGetHost;
virCPUGetModels; virCPUGetModels;
virCPUTranslate; virCPUTranslate;
virCPUUpdate; virCPUUpdate;
virCPUUpdateLive;
# cpu/cpu_x86.h # cpu/cpu_x86.h
......
...@@ -3840,12 +3840,13 @@ qemuProcessVerifyCPUFeatures(virDomainDefPtr def, ...@@ -3840,12 +3840,13 @@ qemuProcessVerifyCPUFeatures(virDomainDefPtr def,
static int static int
qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, qemuProcessUpdateLiveGuestCPU(virQEMUDriverPtr driver,
virDomainObjPtr vm, virDomainObjPtr vm,
qemuDomainAsyncJob asyncJob) qemuDomainAsyncJob asyncJob)
{ {
virDomainDefPtr def = vm->def; virDomainDefPtr def = vm->def;
virCPUDataPtr cpu = NULL; virCPUDataPtr cpu = NULL;
virCPUDataPtr disabled = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData; qemuDomainObjPrivatePtr priv = vm->privateData;
int rc; int rc;
int ret = -1; int ret = -1;
...@@ -3854,7 +3855,7 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, ...@@ -3854,7 +3855,7 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver,
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
goto cleanup; goto cleanup;
rc = qemuMonitorGetGuestCPU(priv->mon, def->os.arch, &cpu, NULL); rc = qemuMonitorGetGuestCPU(priv->mon, def->os.arch, &cpu, &disabled);
if (qemuDomainObjExitMonitor(driver, vm) < 0) if (qemuDomainObjExitMonitor(driver, vm) < 0)
goto cleanup; goto cleanup;
...@@ -3871,12 +3872,18 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver, ...@@ -3871,12 +3872,18 @@ qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver,
if (qemuProcessVerifyCPUFeatures(def, cpu) < 0) if (qemuProcessVerifyCPUFeatures(def, cpu) < 0)
goto cleanup; goto cleanup;
if ((rc = virCPUUpdateLive(def->os.arch, def->cpu, cpu, disabled)) < 0)
goto cleanup;
else if (rc == 0)
def->cpu->check = VIR_CPU_CHECK_FULL;
} }
ret = 0; ret = 0;
cleanup: cleanup:
virCPUDataFree(cpu); virCPUDataFree(cpu);
virCPUDataFree(disabled);
return ret; return ret;
} }
...@@ -5720,8 +5727,8 @@ qemuProcessLaunch(virConnectPtr conn, ...@@ -5720,8 +5727,8 @@ qemuProcessLaunch(virConnectPtr conn,
if (qemuConnectAgent(driver, vm) < 0) if (qemuConnectAgent(driver, vm) < 0)
goto cleanup; goto cleanup;
VIR_DEBUG("Detecting if required emulator features are present"); VIR_DEBUG("Verifying and updating provided guest CPU");
if (qemuProcessVerifyGuestCPU(driver, vm, asyncJob) < 0) if (qemuProcessUpdateLiveGuestCPU(driver, vm, asyncJob) < 0)
goto cleanup; goto cleanup;
VIR_DEBUG("Setting up post-init cgroup restrictions"); VIR_DEBUG("Setting up post-init cgroup restrictions");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册