return 0;
}
+
+/**
+ * qemuDomainFixupCPUS:
+ * @vm: domain object
+ * @origCPU: original CPU used when the domain was started
+ *
+ * Libvirt older than 3.9.0 could have messed up the expansion of host-model
+ * CPU when reconnecting to a running domain by adding features QEMU does not
+ * support (such as cmt). This API fixes both the actual CPU provided by QEMU
+ * (stored in the domain object) and the @origCPU used when starting the
+ * domain.
+ *
+ * This is safe even if the original CPU definition used mode='custom' (rather
+ * than host-model) since we know QEMU was able to start the domain and thus
+ * the CPU definitions do not contain any features unknown to QEMU.
+ *
+ * This function can only be used on an active domain or when restoring a
+ * domain which was running.
+ *
+ * Returns 0 on success, -1 on error.
+ */
+int
+qemuDomainFixupCPUs(virDomainObjPtr vm,
+ virCPUDefPtr *origCPU)
+{
+ virCPUDefPtr fixedCPU = NULL;
+ virCPUDefPtr fixedOrig = NULL;
+ virArch arch = vm->def->os.arch;
+ int ret = 0;
+
+ if (!ARCH_IS_X86(arch))
+ return 0;
+
+ if (!vm->def->cpu ||
+ vm->def->cpu->mode != VIR_CPU_MODE_CUSTOM ||
+ !vm->def->cpu->model)
+ return 0;
+
+ /* Missing origCPU means QEMU created exactly the same virtual CPU which
+ * we asked for or libvirt was too old to mess up the translation from
+ * host-model.
+ */
+ if (!*origCPU)
+ return 0;
+
+ if (virCPUDefFindFeature(vm->def->cpu, "cmt") &&
+ (!(fixedCPU = virCPUDefCopyWithoutModel(vm->def->cpu)) ||
+ virCPUDefCopyModelFilter(fixedCPU, vm->def->cpu, false,
+ virQEMUCapsCPUFilterFeatures, &arch) < 0))
+ goto cleanup;
+
+ if (virCPUDefFindFeature(*origCPU, "cmt") &&
+ (!(fixedOrig = virCPUDefCopyWithoutModel(*origCPU)) ||
+ virCPUDefCopyModelFilter(fixedOrig, *origCPU, false,
+ virQEMUCapsCPUFilterFeatures, &arch) < 0))
+ goto cleanup;
+
+ if (fixedCPU) {
+ virCPUDefFree(vm->def->cpu);
+ VIR_STEAL_PTR(vm->def->cpu, fixedCPU);
+ }
+
+ if (fixedOrig) {
+ virCPUDefFree(*origCPU);
+ VIR_STEAL_PTR(*origCPU, fixedOrig);
+ }
+
+ ret = 0;
+
+ cleanup:
+ virCPUDefFree(fixedCPU);
+ virCPUDefFree(fixedOrig);
+ return ret;
+}
+
+
char *
qemuDomainGetMachineName(virDomainObjPtr vm)
{
}
}
+ /* No cookie means libvirt which saved the domain was too old to mess up
+ * the CPU definitions.
+ */
+ if (cookie &&
+ qemuDomainFixupCPUs(vm, &cookie->cpu) < 0)
+ goto cleanup;
+
if (qemuProcessStart(conn, driver, vm, cookie ? cookie->cpu : NULL,
asyncJob, "stdio", *fd, path, NULL,
VIR_NETDEV_VPORT_PROFILE_OP_RESTORE,
if (config)
virDomainObjAssignDef(vm, config, false, NULL);
+ /* No cookie means libvirt which saved the domain was too old to
+ * mess up the CPU definitions.
+ */
+ if (cookie &&
+ qemuDomainFixupCPUs(vm, &cookie->cpu) < 0)
+ goto cleanup;
+
rc = qemuProcessStart(snapshot->domain->conn, driver, vm,
cookie ? cookie->cpu : NULL,
QEMU_ASYNC_JOB_START, NULL, -1, NULL, snap,
virDomainObjPtr vm)
{
virCapsPtr caps = virQEMUDriverGetCapabilities(driver, false);
+ qemuDomainObjPrivatePtr priv = vm->privateData;
virCPUDefPtr host = NULL;
virCPUDefPtr cpu = NULL;
int ret = -1;
if (qemuProcessUpdateCPU(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
goto cleanup;
+ } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION)) {
+ /* We only try to fix CPUs when the libvirt/QEMU combo used to start
+ * the domain did not know about query-cpu-model-expansion in which
+ * case the host-model is known to not contain features which QEMU
+ * doesn't know about.
+ */
+ if (qemuDomainFixupCPUs(vm, &priv->origCPU) < 0)
+ goto cleanup;
}
ret = 0;