}
+/**
+ * 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:
*
(*virCPUArchUpdate)(virCPUDefPtr guest,
const virCPUDef *host);
+typedef int
+(*virCPUArchUpdateLive)(virCPUDefPtr cpu,
+ virCPUDataPtr dataEnabled,
+ virCPUDataPtr dataDisabled);
+
typedef int
(*virCPUArchCheckFeature)(const virCPUDef *cpu,
const char *feature);
virCPUArchGetHost getHost;
cpuArchBaseline baseline;
virCPUArchUpdate update;
+ virCPUArchUpdateLive updateLive;
virCPUArchCheckFeature checkFeature;
virCPUArchDataCheckFeature dataCheckFeature;
virCPUArchDataFormat dataFormat;
const virCPUDef *host)
ATTRIBUTE_NONNULL(2);
+int
+virCPUUpdateLive(virArch arch,
+ virCPUDefPtr cpu,
+ virCPUDataPtr dataEnabled,
+ virCPUDataPtr dataDisabled)
+ ATTRIBUTE_NONNULL(2);
int
virCPUCheckFeature(virArch arch,
}
+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
virCPUx86CheckFeature(const virCPUDef *cpu,
const char *name)
#endif
.baseline = x86Baseline,
.update = virCPUx86Update,
+ .updateLive = virCPUx86UpdateLive,
.checkFeature = virCPUx86CheckFeature,
.dataCheckFeature = virCPUx86DataCheckFeature,
.dataFormat = virCPUx86DataFormat,
virCPUGetModels;
virCPUTranslate;
virCPUUpdate;
+virCPUUpdateLive;
# cpu/cpu_x86.h
static int
-qemuProcessVerifyGuestCPU(virQEMUDriverPtr driver,
- virDomainObjPtr vm,
- qemuDomainAsyncJob asyncJob)
+qemuProcessUpdateLiveGuestCPU(virQEMUDriverPtr driver,
+ virDomainObjPtr vm,
+ qemuDomainAsyncJob asyncJob)
{
virDomainDefPtr def = vm->def;
virCPUDataPtr cpu = NULL;
+ virCPUDataPtr disabled = NULL;
qemuDomainObjPrivatePtr priv = vm->privateData;
int rc;
int ret = -1;
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
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)
goto cleanup;
if (qemuProcessVerifyCPUFeatures(def, cpu) < 0)
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;
cleanup:
virCPUDataFree(cpu);
+ virCPUDataFree(disabled);
return ret;
}
if (qemuConnectAgent(driver, vm) < 0)
goto cleanup;
- VIR_DEBUG("Detecting if required emulator features are present");
- if (qemuProcessVerifyGuestCPU(driver, vm, asyncJob) < 0)
+ VIR_DEBUG("Verifying and updating provided guest CPU");
+ if (qemuProcessUpdateLiveGuestCPU(driver, vm, asyncJob) < 0)
goto cleanup;
VIR_DEBUG("Setting up post-init cgroup restrictions");