From: Sean Christopherson seanjc@google.com
Introduce the basic infrastructure to allow per-VM memory attribute tracking to be disabled. This will be built-upon in a later patch, where a module param can disable per-VM memory attribute tracking.
Split the Kconfig option into a base KVM_MEMORY_ATTRIBUTES and the existing KVM_VM_MEMORY_ATTRIBUTES. The base option provides the core plumbing, while the latter enables the full per-VM tracking via an xarray and the associated ioctls.
kvm_get_memory_attributes() now performs a static call that either looks up kvm->mem_attr_array with CONFIG_KVM_VM_MEMORY_ATTRIBUTES is enabled, or just returns 0 otherwise. The static call can be patched depending on whether per-VM tracking is enabled by the CONFIG.
No functional change intended.
Signed-off-by: Sean Christopherson seanjc@google.com --- arch/x86/include/asm/kvm_host.h | 2 +- include/linux/kvm_host.h | 23 ++++++++++------- virt/kvm/Kconfig | 6 ++++- virt/kvm/kvm_main.c | 44 ++++++++++++++++++++++++++++++++- 4 files changed, 63 insertions(+), 12 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index efb0b2e1808d5..197b28ae0e28c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2301,7 +2301,7 @@ void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level, int tdp_max_root_level, int tdp_huge_page_level);
-#ifdef CONFIG_KVM_VM_MEMORY_ATTRIBUTES +#ifdef CONFIG_KVM_MEMORY_ATTRIBUTES #define kvm_arch_has_private_mem(kvm) ((kvm)->arch.has_private_mem) #endif
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 21bf30e8d3cc1..512febf47c265 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -2514,19 +2514,15 @@ static inline bool kvm_memslot_is_gmem_only(const struct kvm_memory_slot *slot) return slot->flags & KVM_MEMSLOT_GMEM_ONLY; }
-#ifdef CONFIG_KVM_VM_MEMORY_ATTRIBUTES +#ifdef CONFIG_KVM_MEMORY_ATTRIBUTES +typedef unsigned long (kvm_get_memory_attributes_t)(struct kvm *kvm, gfn_t gfn); +DECLARE_STATIC_CALL(__kvm_get_memory_attributes, kvm_get_memory_attributes_t); + static inline unsigned long kvm_get_memory_attributes(struct kvm *kvm, gfn_t gfn) { - return xa_to_value(xa_load(&kvm->mem_attr_array, gfn)); + return static_call(__kvm_get_memory_attributes)(kvm, gfn); }
-bool kvm_range_has_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t end, - unsigned long mask, unsigned long attrs); -bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm, - struct kvm_gfn_range *range); -bool kvm_arch_post_set_memory_attributes(struct kvm *kvm, - struct kvm_gfn_range *range); - static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn) { return kvm_get_memory_attributes(kvm, gfn) & KVM_MEMORY_ATTRIBUTE_PRIVATE; @@ -2536,6 +2532,15 @@ static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn) { return false; } +#endif + +#ifdef CONFIG_KVM_VM_MEMORY_ATTRIBUTES +bool kvm_range_has_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t end, + unsigned long mask, unsigned long attrs); +bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm, + struct kvm_gfn_range *range); +bool kvm_arch_post_set_memory_attributes(struct kvm *kvm, + struct kvm_gfn_range *range); #endif /* CONFIG_KVM_VM_MEMORY_ATTRIBUTES */
#ifdef CONFIG_KVM_GUEST_MEMFD diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index 9dd7873114b59..395996977fe5a 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -108,10 +108,14 @@ config KVM_MMU_LOCKLESS_AGING depends on KVM_GENERIC_MMU_NOTIFIER bool
-config KVM_VM_MEMORY_ATTRIBUTES +config KVM_MEMORY_ATTRIBUTES depends on KVM_GENERIC_MMU_NOTIFIER bool
+config KVM_VM_MEMORY_ATTRIBUTES + select KVM_MEMORY_ATTRIBUTES + bool + config KVM_GUEST_MEMFD depends on KVM_GENERIC_MMU_NOTIFIER select XARRAY_MULTI diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 591795a3fa124..6c29770dfa7c8 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -101,6 +101,17 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(halt_poll_ns_shrink); static bool allow_unsafe_mappings; module_param(allow_unsafe_mappings, bool, 0444);
+#ifdef CONFIG_KVM_MEMORY_ATTRIBUTES +#ifdef CONFIG_KVM_VM_MEMORY_ATTRIBUTES +static bool vm_memory_attributes = true; +#else +#define vm_memory_attributes false +#endif +DEFINE_STATIC_CALL_RET0(__kvm_get_memory_attributes, kvm_get_memory_attributes_t); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(STATIC_CALL_KEY(__kvm_get_memory_attributes)); +EXPORT_SYMBOL_FOR_KVM_INTERNAL(STATIC_CALL_TRAMP(__kvm_get_memory_attributes)); +#endif + /* * Ordering of locks: * @@ -2425,7 +2436,7 @@ static int kvm_vm_ioctl_clear_dirty_log(struct kvm *kvm, } #endif /* CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT */
-#ifdef CONFIG_KVM_VM_MEMORY_ATTRIBUTES +#ifdef CONFIG_KVM_MEMORY_ATTRIBUTES static u64 kvm_supported_mem_attributes(struct kvm *kvm) { #ifdef kvm_arch_has_private_mem @@ -2436,6 +2447,12 @@ static u64 kvm_supported_mem_attributes(struct kvm *kvm) return 0; }
+#ifdef CONFIG_KVM_VM_MEMORY_ATTRIBUTES +static unsigned long kvm_get_vm_memory_attributes(struct kvm *kvm, gfn_t gfn) +{ + return xa_to_value(xa_load(&kvm->mem_attr_array, gfn)); +} + /* * Returns true if _all_ gfns in the range [@start, @end) have attributes * such that the bits in @mask match @attrs. @@ -2632,7 +2649,24 @@ static int kvm_vm_ioctl_set_mem_attributes(struct kvm *kvm,
return kvm_vm_set_mem_attributes(kvm, start, end, attrs->attributes); } +#else /* CONFIG_KVM_VM_MEMORY_ATTRIBUTES */ +static unsigned long kvm_get_vm_memory_attributes(struct kvm *kvm, gfn_t gfn) +{ + BUILD_BUG_ON(1); +} #endif /* CONFIG_KVM_VM_MEMORY_ATTRIBUTES */ +static void kvm_init_memory_attributes(void) +{ + if (vm_memory_attributes) + static_call_update(__kvm_get_memory_attributes, + kvm_get_vm_memory_attributes); + else + static_call_update(__kvm_get_memory_attributes, + (void *)__static_call_return0); +} +#else /* CONFIG_KVM_MEMORY_ATTRIBUTES */ +static void kvm_init_memory_attributes(void) { } +#endif /* CONFIG_KVM_MEMORY_ATTRIBUTES */
struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn) { @@ -4925,6 +4959,9 @@ static int kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg) return 1; #ifdef CONFIG_KVM_VM_MEMORY_ATTRIBUTES case KVM_CAP_MEMORY_ATTRIBUTES: + if (!vm_memory_attributes) + return 0; + return kvm_supported_mem_attributes(kvm); #endif #ifdef CONFIG_KVM_GUEST_MEMFD @@ -5331,6 +5368,10 @@ static long kvm_vm_ioctl(struct file *filp, case KVM_SET_MEMORY_ATTRIBUTES: { struct kvm_memory_attributes attrs;
+ r = -ENOTTY; + if (!vm_memory_attributes) + goto out; + r = -EFAULT; if (copy_from_user(&attrs, argp, sizeof(attrs))) goto out; @@ -6513,6 +6554,7 @@ int kvm_init(unsigned vcpu_size, unsigned vcpu_align, struct module *module) kvm_preempt_ops.sched_in = kvm_sched_in; kvm_preempt_ops.sched_out = kvm_sched_out;
+ kvm_init_memory_attributes(); kvm_init_debug();
r = kvm_vfio_ops_init();