Skip to content

Commit ac777fb

Browse files
committed
KVM: x86: Use kvzalloc() to allocate VM struct
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>
1 parent 039ef33 commit ac777fb

5 files changed

Lines changed: 29 additions & 1 deletion

File tree

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1962,7 +1962,7 @@ void kvm_x86_vendor_exit(void);
19621962
#define __KVM_HAVE_ARCH_VM_ALLOC
19631963
static inline struct kvm *kvm_arch_alloc_vm(void)
19641964
{
1965-
return __vmalloc(kvm_x86_ops.vm_size, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
1965+
return kvzalloc(kvm_x86_ops.vm_size, GFP_KERNEL_ACCOUNT);
19661966
}
19671967

19681968
#define __KVM_HAVE_ARCH_VM_FREE

arch/x86/kvm/svm/svm.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5662,6 +5662,8 @@ static int __init svm_init(void)
56625662
{
56635663
int r;
56645664

5665+
KVM_SANITY_CHECK_VM_STRUCT_SIZE(kvm_svm);
5666+
56655667
__unused_size_checks();
56665668

56675669
if (!kvm_is_svm_supported())

arch/x86/kvm/vmx/tdx.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3630,6 +3630,8 @@ int __init tdx_bringup(void)
36303630

36313631
void __init tdx_hardware_setup(void)
36323632
{
3633+
KVM_SANITY_CHECK_VM_STRUCT_SIZE(kvm_tdx);
3634+
36333635
/*
36343636
* Note, if the TDX module can't be loaded, KVM TDX support will be
36353637
* disabled but KVM will continue loading (see tdx_bringup()).

arch/x86/kvm/vmx/vmx.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8650,6 +8650,8 @@ int __init vmx_init(void)
86508650
{
86518651
int r, cpu;
86528652

8653+
KVM_SANITY_CHECK_VM_STRUCT_SIZE(kvm_vmx);
8654+
86538655
if (!kvm_is_vmx_supported())
86548656
return -EOPNOTSUPP;
86558657

arch/x86/kvm/x86.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,28 @@ struct kvm_host_values {
5555

5656
void kvm_spurious_fault(void);
5757

58+
#define SIZE_OF_MEMSLOTS_HASHTABLE \
59+
(sizeof(((struct kvm_memslots *)0)->id_hash) * 2 * KVM_MAX_NR_ADDRESS_SPACES)
60+
61+
/* Sanity check the size of the memslot hash tables. */
62+
static_assert(SIZE_OF_MEMSLOTS_HASHTABLE ==
63+
(1024 * (1 + IS_ENABLED(CONFIG_X86_64)) * (1 + IS_ENABLED(CONFIG_KVM_SMM))));
64+
65+
/*
66+
* Assert that "struct kvm_{svm,vmx,tdx}" is an order-0 or order-1 allocation.
67+
* Spilling over to an order-2 allocation isn't fundamentally problematic, but
68+
* isn't expected to happen in the foreseeable future (O(years)). Assert that
69+
* the size is an order-0 allocation when ignoring the memslot hash tables, to
70+
* help detect and debug unexpected size increases.
71+
*/
72+
#define KVM_SANITY_CHECK_VM_STRUCT_SIZE(x) \
73+
do { \
74+
BUILD_BUG_ON(get_order(sizeof(struct x) - SIZE_OF_MEMSLOTS_HASHTABLE) && \
75+
!IS_ENABLED(CONFIG_DEBUG_KERNEL) && !IS_ENABLED(CONFIG_KASAN)); \
76+
BUILD_BUG_ON(get_order(sizeof(struct x)) > 1 && \
77+
!IS_ENABLED(CONFIG_DEBUG_KERNEL) && !IS_ENABLED(CONFIG_KASAN)); \
78+
} while (0)
79+
5880
#define KVM_NESTED_VMENTER_CONSISTENCY_CHECK(consistency_check) \
5981
({ \
6082
bool failed = (consistency_check); \

0 commit comments

Comments
 (0)