]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: x86: Use kvzalloc() to allocate VM struct
authorSean Christopherson <seanjc@google.com>
Fri, 23 May 2025 00:11:37 +0000 (17:11 -0700)
committerSean Christopherson <seanjc@google.com>
Tue, 24 Jun 2025 19:50:48 +0000 (12:50 -0700)
Allocate VM structs via kvzalloc(), i.e. try to use a contiguous physical
allocation before falling back to __vmalloc(), to avoid the overhead of
establishing the virtual mappings.  For non-debug builds, The SVM and VMX
(and TDX) structures are now just below 7000 bytes in the worst case
scenario (see below), i.e. are order-1 allocations, and will likely remain
that way for quite some time.

Add compile-time assertions in vendor code to ensure the size of the
structures, sans the memslot hash tables, are order-0 allocations, i.e.
are less than 4KiB.  There's nothing fundamentally wrong with a larger
kvm_{svm,vmx,tdx} size, but given that the size of the structure (without
the memslots hash tables) is below 2KiB after 18+ years of existence,
more than doubling the size would be quite notable.

Add sanity checks on the memslot hash table sizes, partly to ensure they
aren't resized without accounting for the impact on VM structure size, and
partly to document that the majority of the size of VM structures comes
from the memslots.

Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
Link: https://lore.kernel.org/r/20250523001138.3182794-4-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/svm/svm.c
arch/x86/kvm/vmx/tdx.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/x86.h

index 17529e5d717c411d1af7750dc794f75c9143c0e0..109a5cfd68b6a461c1188d6f1238d9727607931b 100644 (file)
@@ -1962,7 +1962,7 @@ void kvm_x86_vendor_exit(void);
 #define __KVM_HAVE_ARCH_VM_ALLOC
 static inline struct kvm *kvm_arch_alloc_vm(void)
 {
-       return __vmalloc(kvm_x86_ops.vm_size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+       return kvzalloc(kvm_x86_ops.vm_size, GFP_KERNEL_ACCOUNT);
 }
 
 #define __KVM_HAVE_ARCH_VM_FREE
index ab9b947dbf4f9cd8fe97af0cbecfe540ccffc82c..412b543ed7c66355aa4500e2b8c2008782680ef4 100644 (file)
@@ -5662,6 +5662,8 @@ static int __init svm_init(void)
 {
        int r;
 
+       KVM_SANITY_CHECK_VM_STRUCT_SIZE(kvm_svm);
+
        __unused_size_checks();
 
        if (!kvm_is_svm_supported())
index ddd7bbeabf259d10e15436ea89b9b1d2020924de..8190db9b7b5b821ca3904f0e06da59662421cd75 100644 (file)
@@ -3630,6 +3630,8 @@ success_disable_tdx:
 
 void __init tdx_hardware_setup(void)
 {
+       KVM_SANITY_CHECK_VM_STRUCT_SIZE(kvm_tdx);
+
        /*
         * Note, if the TDX module can't be loaded, KVM TDX support will be
         * disabled but KVM will continue loading (see tdx_bringup()).
index 4953846cb30d1758f2eda294796c5a50ddb9408c..a6326b1e5d623738206b4cc8db9a8646759027a7 100644 (file)
@@ -8650,6 +8650,8 @@ int __init vmx_init(void)
 {
        int r, cpu;
 
+       KVM_SANITY_CHECK_VM_STRUCT_SIZE(kvm_vmx);
+
        if (!kvm_is_vmx_supported())
                return -EOPNOTSUPP;
 
index 832f0faf47791886e19a8978db33fca267582143..db4e6a90e83df00245d38c651d05152f266f14e8 100644 (file)
@@ -55,6 +55,28 @@ struct kvm_host_values {
 
 void kvm_spurious_fault(void);
 
+#define SIZE_OF_MEMSLOTS_HASHTABLE \
+       (sizeof(((struct kvm_memslots *)0)->id_hash) * 2 * KVM_MAX_NR_ADDRESS_SPACES)
+
+/* Sanity check the size of the memslot hash tables. */
+static_assert(SIZE_OF_MEMSLOTS_HASHTABLE ==
+             (1024 * (1 + IS_ENABLED(CONFIG_X86_64)) * (1 + IS_ENABLED(CONFIG_KVM_SMM))));
+
+/*
+ * Assert that "struct kvm_{svm,vmx,tdx}" is an order-0 or order-1 allocation.
+ * Spilling over to an order-2 allocation isn't fundamentally problematic, but
+ * isn't expected to happen in the foreseeable future (O(years)).  Assert that
+ * the size is an order-0 allocation when ignoring the memslot hash tables, to
+ * help detect and debug unexpected size increases.
+ */
+#define KVM_SANITY_CHECK_VM_STRUCT_SIZE(x)                                             \
+do {                                                                                   \
+       BUILD_BUG_ON(get_order(sizeof(struct x) - SIZE_OF_MEMSLOTS_HASHTABLE) &&        \
+                    !IS_ENABLED(CONFIG_DEBUG_KERNEL) && !IS_ENABLED(CONFIG_KASAN));    \
+       BUILD_BUG_ON(get_order(sizeof(struct x)) > 1 &&                                 \
+                    !IS_ENABLED(CONFIG_DEBUG_KERNEL) && !IS_ENABLED(CONFIG_KASAN));    \
+} while (0)
+
 #define KVM_NESTED_VMENTER_CONSISTENCY_CHECK(consistency_check)                \
 ({                                                                     \
        bool failed = (consistency_check);                              \