[libvirt] [PATCH] qemu: Refresh caps cache after booting a different kernel

Jiri Denemark jdenemar at redhat.com
Mon Jan 22 10:46:14 UTC 2018


Whenever a different kernel is booted, some capabilities related to KVM
(such as CPUID bits) may change. We need to refresh the cache to see the
changes.

Signed-off-by: Jiri Denemark <jdenemar at redhat.com>
---

Notes:
    The capabilities may also change if a parameter passed to a kvm module
    changes (kvm_intel.nested is a good example) so this is not a complete
    solution, but we're hopefully getting closer to it :-)

 src/qemu/qemu_capabilities.c | 57 +++++++++++++++++++++++++++++++++++++-------
 src/qemu/qemu_capspriv.h     |  1 +
 tests/qemucapsprobe.c        |  2 +-
 3 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index ab0ea8ec0d..2c573827f1 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -52,6 +52,7 @@
 #include <unistd.h>
 #include <sys/wait.h>
 #include <stdarg.h>
+#include <sys/utsname.h>
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -510,6 +511,7 @@ struct _virQEMUCaps {
     unsigned int libvirtVersion;
     unsigned int microcodeVersion;
     char *package;
+    char *kernelVersion;
 
     virArch arch;
 
@@ -2303,6 +2305,9 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps)
     if (VIR_STRDUP(ret->package, qemuCaps->package) < 0)
         goto error;
 
+    if (VIR_STRDUP(ret->kernelVersion, qemuCaps->kernelVersion) < 0)
+        goto error;
+
     ret->arch = qemuCaps->arch;
 
     if (qemuCaps->kvmCPUModels) {
@@ -2363,6 +2368,7 @@ void virQEMUCapsDispose(void *obj)
     virBitmapFree(qemuCaps->flags);
 
     VIR_FREE(qemuCaps->package);
+    VIR_FREE(qemuCaps->kernelVersion);
     VIR_FREE(qemuCaps->binary);
 
     VIR_FREE(qemuCaps->gicCapabilities);
@@ -3834,6 +3840,7 @@ struct _virQEMUCapsCachePriv {
     gid_t runGid;
     virArch hostArch;
     unsigned int microcodeVersion;
+    char *kernelVersion;
 };
 typedef struct _virQEMUCapsCachePriv virQEMUCapsCachePriv;
 typedef virQEMUCapsCachePriv *virQEMUCapsCachePrivPtr;
@@ -3845,6 +3852,7 @@ virQEMUCapsCachePrivFree(void *privData)
     virQEMUCapsCachePrivPtr priv = privData;
 
     VIR_FREE(priv->libDir);
+    VIR_FREE(priv->kernelVersion);
     VIR_FREE(priv);
 }
 
@@ -3970,6 +3978,12 @@ virQEMUCapsLoadCache(virArch hostArch,
             goto cleanup;
     }
 
+    if (virXPathBoolean("boolean(./kernelVersion)", ctxt) > 0) {
+        qemuCaps->kernelVersion = virXPathString("string(./kernelVersion)", ctxt);
+        if (!qemuCaps->kernelVersion)
+            goto cleanup;
+    }
+
     if (!(str = virXPathString("string(./arch)", ctxt))) {
         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("missing arch in QEMU capabilities cache"));
@@ -4248,6 +4262,10 @@ virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps)
         virBufferAsprintf(&buf, "<package>%s</package>\n",
                           qemuCaps->package);
 
+    if (qemuCaps->kernelVersion)
+        virBufferAsprintf(&buf, "<kernelVersion>%s</kernelVersion>\n",
+                          qemuCaps->kernelVersion);
+
     virBufferAsprintf(&buf, "<arch>%s</arch>\n",
                       virArchToString(qemuCaps->arch));
 
@@ -4385,14 +4403,24 @@ virQEMUCapsIsValid(void *data,
         return false;
     }
 
-    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM) &&
-        priv->microcodeVersion != qemuCaps->microcodeVersion) {
-        VIR_DEBUG("Outdated capabilities for '%s': microcode version changed "
-                  "(%u vs %u)",
-                  qemuCaps->binary,
-                  priv->microcodeVersion,
-                  qemuCaps->microcodeVersion);
-        return false;
+    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) {
+        if (priv->microcodeVersion != qemuCaps->microcodeVersion) {
+            VIR_DEBUG("Outdated capabilities for '%s': microcode version "
+                      "changed (%u vs %u)",
+                      qemuCaps->binary,
+                      priv->microcodeVersion,
+                      qemuCaps->microcodeVersion);
+            return false;
+        }
+
+        if (STRNEQ_NULLABLE(priv->kernelVersion, qemuCaps->kernelVersion)) {
+            VIR_DEBUG("Outdated capabilities for '%s': kernel version changed "
+                      "('%s' vs '%s')",
+                      qemuCaps->binary,
+                      priv->kernelVersion,
+                      qemuCaps->kernelVersion);
+            return false;
+        }
     }
 
     return true;
@@ -5228,6 +5256,7 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch,
                                 uid_t runUid,
                                 gid_t runGid,
                                 unsigned int microcodeVersion,
+                                const char *kernelVersion,
                                 bool qmpOnly)
 {
     virQEMUCapsPtr qemuCaps;
@@ -5284,9 +5313,13 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch,
     virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM);
     virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_QEMU);
 
-    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM))
+    if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM)) {
         qemuCaps->microcodeVersion = microcodeVersion;
 
+        if (VIR_STRDUP(qemuCaps->kernelVersion, kernelVersion) < 0)
+            goto error;
+    }
+
  cleanup:
     VIR_FREE(qmperr);
     return qemuCaps;
@@ -5309,6 +5342,7 @@ virQEMUCapsNewData(const char *binary,
                                            priv->runUid,
                                            priv->runGid,
                                            priv->microcodeVersion,
+                                           priv->kernelVersion,
                                            false);
 }
 
@@ -5397,6 +5431,7 @@ virQEMUCapsCacheNew(const char *libDir,
     char *capsCacheDir = NULL;
     virFileCachePtr cache = NULL;
     virQEMUCapsCachePrivPtr priv = NULL;
+    struct utsname uts = { 0 };
 
     if (virAsprintf(&capsCacheDir, "%s/capabilities", cacheDir) < 0)
         goto error;
@@ -5417,6 +5452,10 @@ virQEMUCapsCacheNew(const char *libDir,
     priv->runGid = runGid;
     priv->microcodeVersion = microcodeVersion;
 
+    if (uname(&uts) == 0 &&
+        virAsprintf(&priv->kernelVersion, "%s %s", uts.release, uts.version) < 0)
+        goto error;
+
  cleanup:
     VIR_FREE(capsCacheDir);
     return cache;
diff --git a/src/qemu/qemu_capspriv.h b/src/qemu/qemu_capspriv.h
index 98d163b920..222f3368e3 100644
--- a/src/qemu/qemu_capspriv.h
+++ b/src/qemu/qemu_capspriv.h
@@ -37,6 +37,7 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch,
                                 uid_t runUid,
                                 gid_t runGid,
                                 unsigned int microcodeVersion,
+                                const char *kernelVersion,
                                 bool qmpOnly);
 
 int virQEMUCapsLoadCache(virArch hostArch,
diff --git a/tests/qemucapsprobe.c b/tests/qemucapsprobe.c
index a5f5a38b16..7d60246949 100644
--- a/tests/qemucapsprobe.c
+++ b/tests/qemucapsprobe.c
@@ -72,7 +72,7 @@ main(int argc, char **argv)
         return EXIT_FAILURE;
 
     if (!(caps = virQEMUCapsNewForBinaryInternal(VIR_ARCH_NONE, argv[1], "/tmp",
-                                                 -1, -1, 0, true)))
+                                                 -1, -1, 0, NULL, true)))
         return EXIT_FAILURE;
 
     virObjectUnref(caps);
-- 
2.16.0




More information about the libvir-list mailing list