|
|
0f4c8a |
From e7f6fc0ea19e73e1ecd9a54f12ac9f2df7cb30cf Mon Sep 17 00:00:00 2001
|
|
|
0f4c8a |
Message-Id: <e7f6fc0ea19e73e1ecd9a54f12ac9f2df7cb30cf@dist-git>
|
|
|
0f4c8a |
From: Jiri Denemark <jdenemar@redhat.com>
|
|
|
0f4c8a |
Date: Fri, 6 Oct 2017 14:49:07 +0200
|
|
|
0f4c8a |
Subject: [PATCH] qemu: Fix CPU model broken by older libvirt
|
|
|
0f4c8a |
|
|
|
0f4c8a |
When libvirt older than 3.9.0 reconnected to a running domain started by
|
|
|
0f4c8a |
old libvirt it could have messed up the expansion of host-model by
|
|
|
0f4c8a |
adding features QEMU does not support (such as cmt). Thus whenever we
|
|
|
0f4c8a |
reconnect to a running domain, revert to an active snapshot, or restore
|
|
|
0f4c8a |
a saved domain we need to check the guest CPU model and remove the
|
|
|
0f4c8a |
CPU features unknown to QEMU. We can do this because we know the domain
|
|
|
0f4c8a |
was successfully started, which means the CPU did not contain the
|
|
|
0f4c8a |
features when libvirt started the domain.
|
|
|
0f4c8a |
|
|
|
0f4c8a |
https://bugzilla.redhat.com/show_bug.cgi?id=1495171
|
|
|
0f4c8a |
|
|
|
0f4c8a |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
0f4c8a |
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
|
|
|
0f4c8a |
(cherry picked from commit 6a6f6b91e0e76480ea961f83135efcb4faf3284a)
|
|
|
0f4c8a |
|
|
|
0f4c8a |
Conflicts:
|
|
|
0f4c8a |
src/qemu/qemu_domain.c,
|
|
|
0f4c8a |
src/qemu/qemu_domain.h -- context, one more function new
|
|
|
0f4c8a |
function upstream
|
|
|
0f4c8a |
|
|
|
0f4c8a |
https://bugzilla.redhat.com/show_bug.cgi?id=1508549
|
|
|
0f4c8a |
|
|
|
0f4c8a |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
0f4c8a |
---
|
|
|
0f4c8a |
src/qemu/qemu_domain.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
0f4c8a |
src/qemu/qemu_domain.h | 4 +++
|
|
|
0f4c8a |
src/qemu/qemu_driver.c | 14 +++++++++
|
|
|
0f4c8a |
src/qemu/qemu_process.c | 9 ++++++
|
|
|
0f4c8a |
4 files changed, 102 insertions(+)
|
|
|
0f4c8a |
|
|
|
0f4c8a |
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
|
|
|
0f4c8a |
index a41657099f..68c1f3b7c5 100644
|
|
|
0f4c8a |
--- a/src/qemu/qemu_domain.c
|
|
|
0f4c8a |
+++ b/src/qemu/qemu_domain.c
|
|
|
0f4c8a |
@@ -9324,3 +9324,78 @@ qemuDomainUpdateCPU(virDomainObjPtr vm,
|
|
|
0f4c8a |
|
|
|
0f4c8a |
return 0;
|
|
|
0f4c8a |
}
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+/**
|
|
|
0f4c8a |
+ * qemuDomainFixupCPUS:
|
|
|
0f4c8a |
+ * @vm: domain object
|
|
|
0f4c8a |
+ * @origCPU: original CPU used when the domain was started
|
|
|
0f4c8a |
+ *
|
|
|
0f4c8a |
+ * Libvirt older than 3.9.0 could have messed up the expansion of host-model
|
|
|
0f4c8a |
+ * CPU when reconnecting to a running domain by adding features QEMU does not
|
|
|
0f4c8a |
+ * support (such as cmt). This API fixes both the actual CPU provided by QEMU
|
|
|
0f4c8a |
+ * (stored in the domain object) and the @origCPU used when starting the
|
|
|
0f4c8a |
+ * domain.
|
|
|
0f4c8a |
+ *
|
|
|
0f4c8a |
+ * This is safe even if the original CPU definition used mode='custom' (rather
|
|
|
0f4c8a |
+ * than host-model) since we know QEMU was able to start the domain and thus
|
|
|
0f4c8a |
+ * the CPU definitions do not contain any features unknown to QEMU.
|
|
|
0f4c8a |
+ *
|
|
|
0f4c8a |
+ * This function can only be used on an active domain or when restoring a
|
|
|
0f4c8a |
+ * domain which was running.
|
|
|
0f4c8a |
+ *
|
|
|
0f4c8a |
+ * Returns 0 on success, -1 on error.
|
|
|
0f4c8a |
+ */
|
|
|
0f4c8a |
+int
|
|
|
0f4c8a |
+qemuDomainFixupCPUs(virDomainObjPtr vm,
|
|
|
0f4c8a |
+ virCPUDefPtr *origCPU)
|
|
|
0f4c8a |
+{
|
|
|
0f4c8a |
+ virCPUDefPtr fixedCPU = NULL;
|
|
|
0f4c8a |
+ virCPUDefPtr fixedOrig = NULL;
|
|
|
0f4c8a |
+ virArch arch = vm->def->os.arch;
|
|
|
0f4c8a |
+ int ret = 0;
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+ if (!ARCH_IS_X86(arch))
|
|
|
0f4c8a |
+ return 0;
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+ if (!vm->def->cpu ||
|
|
|
0f4c8a |
+ vm->def->cpu->mode != VIR_CPU_MODE_CUSTOM ||
|
|
|
0f4c8a |
+ !vm->def->cpu->model)
|
|
|
0f4c8a |
+ return 0;
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+ /* Missing origCPU means QEMU created exactly the same virtual CPU which
|
|
|
0f4c8a |
+ * we asked for or libvirt was too old to mess up the translation from
|
|
|
0f4c8a |
+ * host-model.
|
|
|
0f4c8a |
+ */
|
|
|
0f4c8a |
+ if (!*origCPU)
|
|
|
0f4c8a |
+ return 0;
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+ if (virCPUDefFindFeature(vm->def->cpu, "cmt") &&
|
|
|
0f4c8a |
+ (!(fixedCPU = virCPUDefCopyWithoutModel(vm->def->cpu)) ||
|
|
|
0f4c8a |
+ virCPUDefCopyModelFilter(fixedCPU, vm->def->cpu, false,
|
|
|
0f4c8a |
+ virQEMUCapsCPUFilterFeatures, &arch) < 0))
|
|
|
0f4c8a |
+ goto cleanup;
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+ if (virCPUDefFindFeature(*origCPU, "cmt") &&
|
|
|
0f4c8a |
+ (!(fixedOrig = virCPUDefCopyWithoutModel(*origCPU)) ||
|
|
|
0f4c8a |
+ virCPUDefCopyModelFilter(fixedOrig, *origCPU, false,
|
|
|
0f4c8a |
+ virQEMUCapsCPUFilterFeatures, &arch) < 0))
|
|
|
0f4c8a |
+ goto cleanup;
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+ if (fixedCPU) {
|
|
|
0f4c8a |
+ virCPUDefFree(vm->def->cpu);
|
|
|
0f4c8a |
+ VIR_STEAL_PTR(vm->def->cpu, fixedCPU);
|
|
|
0f4c8a |
+ }
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+ if (fixedOrig) {
|
|
|
0f4c8a |
+ virCPUDefFree(*origCPU);
|
|
|
0f4c8a |
+ VIR_STEAL_PTR(*origCPU, fixedOrig);
|
|
|
0f4c8a |
+ }
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+ ret = 0;
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
+ cleanup:
|
|
|
0f4c8a |
+ virCPUDefFree(fixedCPU);
|
|
|
0f4c8a |
+ virCPUDefFree(fixedOrig);
|
|
|
0f4c8a |
+ return ret;
|
|
|
0f4c8a |
+}
|
|
|
0f4c8a |
diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
|
|
|
0f4c8a |
index 7ad34e563e..1a658bcf7e 100644
|
|
|
0f4c8a |
--- a/src/qemu/qemu_domain.h
|
|
|
0f4c8a |
+++ b/src/qemu/qemu_domain.h
|
|
|
0f4c8a |
@@ -930,4 +930,8 @@ qemuDomainUpdateCPU(virDomainObjPtr vm,
|
|
|
0f4c8a |
virCPUDefPtr cpu,
|
|
|
0f4c8a |
virCPUDefPtr *origCPU);
|
|
|
0f4c8a |
|
|
|
0f4c8a |
+int
|
|
|
0f4c8a |
+qemuDomainFixupCPUs(virDomainObjPtr vm,
|
|
|
0f4c8a |
+ virCPUDefPtr *origCPU);
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
#endif /* __QEMU_DOMAIN_H__ */
|
|
|
0f4c8a |
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
|
|
|
0f4c8a |
index b6d72303ca..bfd7ff6c09 100644
|
|
|
0f4c8a |
--- a/src/qemu/qemu_driver.c
|
|
|
0f4c8a |
+++ b/src/qemu/qemu_driver.c
|
|
|
0f4c8a |
@@ -6500,6 +6500,13 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
|
|
|
0f4c8a |
}
|
|
|
0f4c8a |
}
|
|
|
0f4c8a |
|
|
|
0f4c8a |
+ /* No cookie means libvirt which saved the domain was too old to mess up
|
|
|
0f4c8a |
+ * the CPU definitions.
|
|
|
0f4c8a |
+ */
|
|
|
0f4c8a |
+ if (cookie &&
|
|
|
0f4c8a |
+ qemuDomainFixupCPUs(vm, &cookie->cpu) < 0)
|
|
|
0f4c8a |
+ goto cleanup;
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
if (qemuProcessStart(conn, driver, vm, cookie ? cookie->cpu : NULL,
|
|
|
0f4c8a |
asyncJob, "stdio", *fd, path, NULL,
|
|
|
0f4c8a |
VIR_NETDEV_VPORT_PROFILE_OP_RESTORE,
|
|
|
0f4c8a |
@@ -15520,6 +15527,13 @@ qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
|
|
|
0f4c8a |
if (config)
|
|
|
0f4c8a |
virDomainObjAssignDef(vm, config, false, NULL);
|
|
|
0f4c8a |
|
|
|
0f4c8a |
+ /* No cookie means libvirt which saved the domain was too old to
|
|
|
0f4c8a |
+ * mess up the CPU definitions.
|
|
|
0f4c8a |
+ */
|
|
|
0f4c8a |
+ if (cookie &&
|
|
|
0f4c8a |
+ qemuDomainFixupCPUs(vm, &cookie->cpu) < 0)
|
|
|
0f4c8a |
+ goto cleanup;
|
|
|
0f4c8a |
+
|
|
|
0f4c8a |
rc = qemuProcessStart(snapshot->domain->conn, driver, vm,
|
|
|
0f4c8a |
cookie ? cookie->cpu : NULL,
|
|
|
0f4c8a |
QEMU_ASYNC_JOB_START, NULL, -1, NULL, snap,
|
|
|
0f4c8a |
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
|
|
|
0f4c8a |
index 0bed084381..5802a553cf 100644
|
|
|
0f4c8a |
--- a/src/qemu/qemu_process.c
|
|
|
0f4c8a |
+++ b/src/qemu/qemu_process.c
|
|
|
0f4c8a |
@@ -6667,6 +6667,7 @@ qemuProcessRefreshCPU(virQEMUDriverPtr driver,
|
|
|
0f4c8a |
virDomainObjPtr vm)
|
|
|
0f4c8a |
{
|
|
|
0f4c8a |
virCapsPtr caps = virQEMUDriverGetCapabilities(driver, false);
|
|
|
0f4c8a |
+ qemuDomainObjPrivatePtr priv = vm->privateData;
|
|
|
0f4c8a |
virCPUDefPtr host = NULL;
|
|
|
0f4c8a |
virCPUDefPtr cpu = NULL;
|
|
|
0f4c8a |
int ret = -1;
|
|
|
0f4c8a |
@@ -6701,6 +6702,14 @@ qemuProcessRefreshCPU(virQEMUDriverPtr driver,
|
|
|
0f4c8a |
|
|
|
0f4c8a |
if (qemuProcessUpdateCPU(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
|
|
|
0f4c8a |
goto cleanup;
|
|
|
0f4c8a |
+ } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QUERY_CPU_MODEL_EXPANSION)) {
|
|
|
0f4c8a |
+ /* We only try to fix CPUs when the libvirt/QEMU combo used to start
|
|
|
0f4c8a |
+ * the domain did not know about query-cpu-model-expansion in which
|
|
|
0f4c8a |
+ * case the host-model is known to not contain features which QEMU
|
|
|
0f4c8a |
+ * doesn't know about.
|
|
|
0f4c8a |
+ */
|
|
|
0f4c8a |
+ if (qemuDomainFixupCPUs(vm, &priv->origCPU) < 0)
|
|
|
0f4c8a |
+ goto cleanup;
|
|
|
0f4c8a |
}
|
|
|
0f4c8a |
|
|
|
0f4c8a |
ret = 0;
|
|
|
0f4c8a |
--
|
|
|
0f4c8a |
2.15.0
|
|
|
0f4c8a |
|