edecca
From 2e68dbce9f8d49e57a0e16a202483b59e9497054 Mon Sep 17 00:00:00 2001
edecca
Message-Id: <2e68dbce9f8d49e57a0e16a202483b59e9497054@dist-git>
edecca
From: John Ferlan <jferlan@redhat.com>
edecca
Date: Thu, 13 Dec 2018 10:54:33 -0500
edecca
Subject: [PATCH] qemu: Add check for whether KVM nesting is enabled
edecca
edecca
https://bugzilla.redhat.com/show_bug.cgi?id=1645139
edecca
edecca
Support for nested KVM is handled via a kernel module configuration
edecca
parameters values for kvm_intel, kvm_amd, kvm_hv (PPC), or kvm (s390).
edecca
While it's possible to fetch the kmod config values via virKModConfig,
edecca
unfortunately that is the static value and we need to get the
edecca
current/dynamic value from the kernel file system.
edecca
edecca
So this patch adds a new API virHostKVMSupportsNesting that will
edecca
search the 3 kernel modules to get the nesting value and check if
edecca
it is 'Y' (or 'y' just in case) to return a true/false whether
edecca
the KVM kernel supports nesting.
edecca
edecca
We need to do this in order to handle cases where adjustments to
edecca
the value are made after libvirtd is started to force a refetch of
edecca
the latest QEMU capabilities since the correct CPU settings need
edecca
to be made for a guest to add the "vmx=on" to/for the guest config.
edecca
edecca
Signed-off-by: John Ferlan <jferlan@redhat.com>
edecca
ACKed-by: Michal Privoznik <mprivozn@redhat.com>
edecca
(cherry picked from commit b183a75319b90d0af5512be513743e1eab950612)
edecca
edecca
NB:
edecca
Handled merge/build conflict/issue where VIR_AUTOFREE isn't defined
edecca
(or backported to RHEL git).  So rather than relying on the automatic
edecca
free of memory, prior to each possible return add a VIR_FREE. It was
edecca
that or adjust the logic to set a retval and use goto cleanup type
edecca
logic. This way just seemed cleaner.
edecca
edecca
Signed-off-by: John Ferlan <jferlan@redhat.com>
edecca
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
edecca
---
edecca
 src/qemu/qemu_capabilities.c | 58 ++++++++++++++++++++++++++++++++++++
edecca
 1 file changed, 58 insertions(+)
edecca
edecca
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
edecca
index 57b1b99076..ba8c717e22 100644
edecca
--- a/src/qemu/qemu_capabilities.c
edecca
+++ b/src/qemu/qemu_capabilities.c
edecca
@@ -550,6 +550,7 @@ struct _virQEMUCaps {
edecca
     virObject parent;
edecca
 
edecca
     bool usedQMP;
edecca
+    bool kvmSupportsNesting;
edecca
 
edecca
     char *binary;
edecca
     time_t ctime;
edecca
@@ -1606,6 +1607,7 @@ virQEMUCapsPtr virQEMUCapsNewCopy(virQEMUCapsPtr qemuCaps)
edecca
         return NULL;
edecca
 
edecca
     ret->usedQMP = qemuCaps->usedQMP;
edecca
+    ret->kvmSupportsNesting = qemuCaps->kvmSupportsNesting;
edecca
 
edecca
     if (VIR_STRDUP(ret->binary, qemuCaps->binary) < 0)
edecca
         goto error;
edecca
@@ -3597,6 +3599,9 @@ virQEMUCapsLoadCache(virArch hostArch,
edecca
     virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM);
edecca
     virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_QEMU);
edecca
 
edecca
+    if (virXPathBoolean("boolean(./kvmSupportsNesting)", ctxt) > 0)
edecca
+        qemuCaps->kvmSupportsNesting = true;
edecca
+
edecca
     ret = 0;
edecca
  cleanup:
edecca
     VIR_FREE(str);
edecca
@@ -3813,6 +3818,9 @@ virQEMUCapsFormatCache(virQEMUCapsPtr qemuCaps)
edecca
     if (qemuCaps->sevCapabilities)
edecca
         virQEMUCapsFormatSEVInfo(qemuCaps, &buf;;
edecca
 
edecca
+    if (qemuCaps->kvmSupportsNesting)
edecca
+        virBufferAddLit(&buf, "<kvmSupportsNesting/>\n");
edecca
+
edecca
     virBufferAdjustIndent(&buf, -2);
edecca
     virBufferAddLit(&buf, "</qemuCaps>\n");
edecca
 
edecca
@@ -3853,6 +3861,45 @@ virQEMUCapsSaveFile(void *data,
edecca
 }
edecca
 
edecca
 
edecca
+/* Check the kernel module parameters 'nested' file to determine if enabled
edecca
+ *
edecca
+ *   Intel: 'kvm_intel' uses 'Y'
edecca
+ *   AMD:   'kvm_amd' uses '1'
edecca
+ *   PPC64: 'kvm_hv' uses 'Y'
edecca
+ *   S390:  'kvm' uses '1'
edecca
+ */
edecca
+static bool
edecca
+virQEMUCapsKVMSupportsNesting(void)
edecca
+{
edecca
+    static char const * const kmod[] = {"kvm_intel", "kvm_amd",
edecca
+                                        "kvm_hv", "kvm"};
edecca
+    char * value = NULL;
edecca
+    int rc;
edecca
+    size_t i;
edecca
+
edecca
+    for (i = 0; i < ARRAY_CARDINALITY(kmod); i++) {
edecca
+        VIR_FREE(value);
edecca
+        rc = virFileReadValueString(&value, "/sys/module/%s/parameters/nested",
edecca
+                                    kmod[i]);
edecca
+        if (rc == -2)
edecca
+            continue;
edecca
+        if (rc < 0) {
edecca
+            virResetLastError();
edecca
+            VIR_FREE(value);
edecca
+            return false;
edecca
+        }
edecca
+
edecca
+        if (value[0] == 'Y' || value[0] == 'y' || value[0] == '1') {
edecca
+            VIR_FREE(value);
edecca
+            return true;
edecca
+        }
edecca
+    }
edecca
+
edecca
+    VIR_FREE(value);
edecca
+    return false;
edecca
+}
edecca
+
edecca
+
edecca
 static bool
edecca
 virQEMUCapsIsValid(void *data,
edecca
                    void *privData)
edecca
@@ -3861,6 +3908,7 @@ virQEMUCapsIsValid(void *data,
edecca
     virQEMUCapsCachePrivPtr priv = privData;
edecca
     bool kvmUsable;
edecca
     struct stat sb;
edecca
+    bool kvmSupportsNesting;
edecca
 
edecca
     if (!qemuCaps->binary)
edecca
         return true;
edecca
@@ -3938,6 +3986,14 @@ virQEMUCapsIsValid(void *data,
edecca
                       qemuCaps->kernelVersion);
edecca
             return false;
edecca
         }
edecca
+
edecca
+        kvmSupportsNesting = virQEMUCapsKVMSupportsNesting();
edecca
+        if (kvmSupportsNesting != qemuCaps->kvmSupportsNesting) {
edecca
+            VIR_DEBUG("Outdated capabilities for '%s': kvm kernel nested "
edecca
+                      "value changed from %d",
edecca
+                     qemuCaps->binary, qemuCaps->kvmSupportsNesting);
edecca
+            return false;
edecca
+        }
edecca
     }
edecca
 
edecca
     return true;
edecca
@@ -4591,6 +4647,8 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch,
edecca
 
edecca
         if (VIR_STRDUP(qemuCaps->kernelVersion, kernelVersion) < 0)
edecca
             goto error;
edecca
+
edecca
+        qemuCaps->kvmSupportsNesting = virQEMUCapsKVMSupportsNesting();
edecca
     }
edecca
 
edecca
  cleanup:
edecca
-- 
edecca
2.20.1
edecca