mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-20 11:48:28 -06:00
cpuUpdate() for updating guest CPU according to host CPU
Useful mainly for migration. cpuUpdate changes guest CPU requirements in the following way: - match == "strict" || match == "exact" - optional features which are supported by host CPU are changed into required features - optional features which are not supported by host CPU are disabled - all other features remain untouched - match == "minimum" - match is changed into "exact" - optional features and all features not mentioned in guest CPU specification which are supported by host CPU become required features - other optional features are disabled - all other features remain untouched This ensures that no feature will suddenly disappear from the guest after migration.
This commit is contained in:
parent
5982168290
commit
661ae104c2
@ -403,3 +403,25 @@ cpuBaseline(virCPUDefPtr *cpus,
|
||||
|
||||
return cpu;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cpuUpdate(virCPUDefPtr guest,
|
||||
const virCPUDefPtr host)
|
||||
{
|
||||
struct cpuArchDriver *driver;
|
||||
|
||||
VIR_DEBUG("guest=%p, host=%p", guest, host);
|
||||
|
||||
if ((driver = cpuGetSubDriver(host->arch)) == NULL)
|
||||
return -1;
|
||||
|
||||
if (driver->update == NULL) {
|
||||
virCPUReportError(VIR_ERR_NO_SUPPORT,
|
||||
_("cannot update guest CPU data for %s architecture"),
|
||||
host->arch);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return driver->update(guest, host);
|
||||
}
|
||||
|
@ -76,6 +76,10 @@ typedef virCPUDefPtr
|
||||
const char **models,
|
||||
unsigned int nmodels);
|
||||
|
||||
typedef int
|
||||
(*cpuArchUpdate) (virCPUDefPtr guest,
|
||||
const virCPUDefPtr host);
|
||||
|
||||
|
||||
struct cpuArchDriver {
|
||||
const char *name;
|
||||
@ -88,6 +92,7 @@ struct cpuArchDriver {
|
||||
cpuArchNodeData nodeData;
|
||||
cpuArchGuestData guestData;
|
||||
cpuArchBaseline baseline;
|
||||
cpuArchUpdate update;
|
||||
};
|
||||
|
||||
|
||||
@ -138,4 +143,8 @@ cpuBaseline (virCPUDefPtr *cpus,
|
||||
const char **models,
|
||||
unsigned int nmodels);
|
||||
|
||||
extern int
|
||||
cpuUpdate (virCPUDefPtr guest,
|
||||
const virCPUDefPtr host);
|
||||
|
||||
#endif /* __VIR_CPU_H__ */
|
||||
|
@ -219,4 +219,5 @@ struct cpuArchDriver cpuDriverGeneric = {
|
||||
.nodeData = NULL,
|
||||
.guestData = NULL,
|
||||
.baseline = genericBaseline,
|
||||
.update = NULL,
|
||||
};
|
||||
|
@ -249,6 +249,33 @@ x86DataFromModel(const struct x86_model *model)
|
||||
}
|
||||
|
||||
|
||||
/* also removes all detected features from data */
|
||||
static int
|
||||
x86DataToCPUFeatures(virCPUDefPtr cpu,
|
||||
int policy,
|
||||
union cpuData *data,
|
||||
const struct x86_map *map)
|
||||
{
|
||||
const struct x86_feature *feature = map->features;
|
||||
struct cpuX86cpuid *cpuid;
|
||||
unsigned int i;
|
||||
|
||||
while (feature != NULL) {
|
||||
for (i = 0; i < feature->ncpuid; i++) {
|
||||
if ((cpuid = x86DataCpuid(data, feature->cpuid[i].function))
|
||||
&& x86cpuidMatchMasked(cpuid, feature->cpuid + i)) {
|
||||
x86cpuidClearBits(cpuid, feature->cpuid + i);
|
||||
if (virCPUDefAddFeature(cpu, feature->name, policy) < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
feature = feature->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static virCPUDefPtr
|
||||
x86DataToCPU(const union cpuData *data,
|
||||
const struct x86_model *model,
|
||||
@ -256,9 +283,7 @@ x86DataToCPU(const union cpuData *data,
|
||||
{
|
||||
virCPUDefPtr cpu;
|
||||
union cpuData *tmp = NULL;
|
||||
struct cpuX86cpuid *cpuid;
|
||||
const struct x86_feature *feature;
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
if (VIR_ALLOC(cpu) < 0 ||
|
||||
(cpu->model = strdup(model->name)) == NULL ||
|
||||
@ -270,20 +295,8 @@ x86DataToCPU(const union cpuData *data,
|
||||
model->cpuid + i);
|
||||
}
|
||||
|
||||
feature = map->features;
|
||||
while (feature != NULL) {
|
||||
for (i = 0; i < feature->ncpuid; i++) {
|
||||
if ((cpuid = x86DataCpuid(tmp, feature->cpuid[i].function))
|
||||
&& x86cpuidMatchMasked(cpuid, feature->cpuid + i)) {
|
||||
x86cpuidClearBits(cpuid, feature->cpuid + i);
|
||||
if (virCPUDefAddFeature(cpu, feature->name,
|
||||
VIR_CPU_FEATURE_REQUIRE) < 0)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
feature = feature->next;
|
||||
}
|
||||
if (x86DataToCPUFeatures(cpu, VIR_CPU_FEATURE_REQUIRE, tmp, map))
|
||||
goto error;
|
||||
|
||||
cleanup:
|
||||
x86DataFree(tmp);
|
||||
@ -560,6 +573,29 @@ x86ModelMergeFeature(struct x86_model *model,
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
x86ModelHasFeature(struct x86_model *model,
|
||||
const struct x86_feature *feature)
|
||||
{
|
||||
unsigned int i;
|
||||
struct cpuX86cpuid *cpuid;
|
||||
struct cpuX86cpuid *model_cpuid;
|
||||
|
||||
if (feature == NULL)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < feature->ncpuid; i++) {
|
||||
cpuid = feature->cpuid + i;
|
||||
model_cpuid = x86cpuidFind(model->cpuid, model->ncpuid,
|
||||
cpuid->function);
|
||||
if (!x86cpuidMatchMasked(model_cpuid, cpuid))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static struct x86_model *
|
||||
x86ModelFromCPU(const virCPUDefPtr cpu,
|
||||
const struct x86_map *map,
|
||||
@ -610,6 +646,47 @@ error:
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
x86ModelSubtractCPU(struct x86_model *model,
|
||||
const virCPUDefPtr cpu,
|
||||
const struct x86_map *map)
|
||||
{
|
||||
const struct x86_model *cpu_model;
|
||||
unsigned int i;
|
||||
|
||||
if (!(cpu_model = x86ModelFind(map, cpu->model))) {
|
||||
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unknown CPU model %s"),
|
||||
cpu->model);
|
||||
return -1;
|
||||
}
|
||||
|
||||
x86ModelSubtract(model, cpu_model);
|
||||
|
||||
for (i = 0; i < cpu->nfeatures; i++) {
|
||||
const struct x86_feature *feature;
|
||||
unsigned int j;
|
||||
|
||||
if (!(feature = x86FeatureFind(map, cpu->features[i].name))) {
|
||||
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unknown CPU feature %s"),
|
||||
cpu->features[i].name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (j = 0; j < feature->ncpuid; j++) {
|
||||
struct cpuX86cpuid *cpuid;
|
||||
cpuid = x86cpuidFind(model->cpuid, model->ncpuid,
|
||||
feature->cpuid[j].function);
|
||||
if (cpuid)
|
||||
x86cpuidClearBits(cpuid, feature->cpuid + j);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static enum compare_result
|
||||
x86ModelCompare(const struct x86_model *model1,
|
||||
const struct x86_model *model2)
|
||||
@ -1277,6 +1354,55 @@ error:
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
x86Update(virCPUDefPtr guest,
|
||||
const virCPUDefPtr host)
|
||||
{
|
||||
int ret = -1;
|
||||
unsigned int i;
|
||||
struct x86_map *map;
|
||||
struct x86_model *host_model = NULL;
|
||||
union cpuData *data = NULL;
|
||||
|
||||
if (!(map = x86LoadMap()) ||
|
||||
!(host_model = x86ModelFromCPU(host, map, 0)))
|
||||
goto cleanup;
|
||||
|
||||
for (i = 0; i < guest->nfeatures; i++) {
|
||||
if (guest->features[i].policy == VIR_CPU_FEATURE_OPTIONAL) {
|
||||
const struct x86_feature *feature;
|
||||
if (!(feature = x86FeatureFind(map, guest->features[i].name))) {
|
||||
virCPUReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Unknown CPU feature %s"),
|
||||
guest->features[i].name);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (x86ModelHasFeature(host_model, feature))
|
||||
guest->features[i].policy = VIR_CPU_FEATURE_REQUIRE;
|
||||
else
|
||||
guest->features[i].policy = VIR_CPU_FEATURE_DISABLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (guest->match == VIR_CPU_MATCH_MINIMUM) {
|
||||
guest->match = VIR_CPU_MATCH_EXACT;
|
||||
if (x86ModelSubtractCPU(host_model, guest, map)
|
||||
|| !(data = x86DataFromModel(host_model))
|
||||
|| x86DataToCPUFeatures(guest, VIR_CPU_FEATURE_REQUIRE, data, map))
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
x86MapFree(map);
|
||||
x86ModelFree(host_model);
|
||||
x86DataFree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct cpuArchDriver cpuDriverX86 = {
|
||||
.name = "x86",
|
||||
.arch = archs,
|
||||
@ -1292,4 +1418,5 @@ struct cpuArchDriver cpuDriverX86 = {
|
||||
#endif
|
||||
.guestData = x86GuestData,
|
||||
.baseline = x86Baseline,
|
||||
.update = x86Update,
|
||||
};
|
||||
|
@ -81,6 +81,7 @@ cpuDecode;
|
||||
cpuEncode;
|
||||
cpuGuestData;
|
||||
cpuNodeData;
|
||||
cpuUpdate;
|
||||
|
||||
|
||||
# cpu_conf.h
|
||||
|
Loading…
Reference in New Issue
Block a user