Commit 1f98f2bd authored by David Matlack's avatar David Matlack Committed by Paolo Bonzini

KVM: x86/mmu: Change tdp_mmu to a read-only parameter

Change tdp_mmu to a read-only parameter and drop the per-vm
tdp_mmu_enabled. For 32-bit KVM, make tdp_mmu_enabled a macro that is
always false so that the compiler can continue omitting cals to the TDP
MMU.

The TDP MMU was introduced in 5.10 and has been enabled by default since
5.15. At this point there are no known functionality gaps between the
TDP MMU and the shadow MMU, and the TDP MMU uses less memory and scales
better with the number of vCPUs. In other words, there is no good reason
to disable the TDP MMU on a live system.

Purposely do not drop tdp_mmu=N support (i.e. do not force 64-bit KVM to
always use the TDP MMU) since tdp_mmu=N is still used to get test
coverage of KVM's shadow MMU TDP support, which is used in 32-bit KVM.
Signed-off-by: default avatarDavid Matlack <dmatlack@google.com>
Reviewed-by: default avatarKai Huang <kai.huang@intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Message-Id: <20220921173546.2674386-2-dmatlack@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 79edd550
...@@ -1341,21 +1341,12 @@ struct kvm_arch { ...@@ -1341,21 +1341,12 @@ struct kvm_arch {
struct task_struct *nx_huge_page_recovery_thread; struct task_struct *nx_huge_page_recovery_thread;
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
/*
* Whether the TDP MMU is enabled for this VM. This contains a
* snapshot of the TDP MMU module parameter from when the VM was
* created and remains unchanged for the life of the VM. If this is
* true, TDP MMU handler functions will run for various MMU
* operations.
*/
bool tdp_mmu_enabled;
/* The number of TDP MMU pages across all roots. */ /* The number of TDP MMU pages across all roots. */
atomic64_t tdp_mmu_pages; atomic64_t tdp_mmu_pages;
/* /*
* List of kvm_mmu_page structs being used as roots. * List of struct kvm_mmu_pages being used as roots.
* All kvm_mmu_page structs in the list should have * All struct kvm_mmu_pages in the list should have
* tdp_mmu_page set. * tdp_mmu_page set.
* *
* For reads, this list is protected by: * For reads, this list is protected by:
......
...@@ -230,14 +230,14 @@ static inline bool kvm_shadow_root_allocated(struct kvm *kvm) ...@@ -230,14 +230,14 @@ static inline bool kvm_shadow_root_allocated(struct kvm *kvm)
} }
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
static inline bool is_tdp_mmu_enabled(struct kvm *kvm) { return kvm->arch.tdp_mmu_enabled; } extern bool tdp_mmu_enabled;
#else #else
static inline bool is_tdp_mmu_enabled(struct kvm *kvm) { return false; } #define tdp_mmu_enabled false
#endif #endif
static inline bool kvm_memslots_have_rmaps(struct kvm *kvm) static inline bool kvm_memslots_have_rmaps(struct kvm *kvm)
{ {
return !is_tdp_mmu_enabled(kvm) || kvm_shadow_root_allocated(kvm); return !tdp_mmu_enabled || kvm_shadow_root_allocated(kvm);
} }
static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level) static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level)
......
...@@ -99,6 +99,13 @@ module_param_named(flush_on_reuse, force_flush_and_sync_on_reuse, bool, 0644); ...@@ -99,6 +99,13 @@ module_param_named(flush_on_reuse, force_flush_and_sync_on_reuse, bool, 0644);
*/ */
bool tdp_enabled = false; bool tdp_enabled = false;
bool __ro_after_init tdp_mmu_allowed;
#ifdef CONFIG_X86_64
bool __read_mostly tdp_mmu_enabled = true;
module_param_named(tdp_mmu, tdp_mmu_enabled, bool, 0444);
#endif
static int max_huge_page_level __read_mostly; static int max_huge_page_level __read_mostly;
static int tdp_root_level __read_mostly; static int tdp_root_level __read_mostly;
static int max_tdp_level __read_mostly; static int max_tdp_level __read_mostly;
...@@ -1279,7 +1286,7 @@ static void kvm_mmu_write_protect_pt_masked(struct kvm *kvm, ...@@ -1279,7 +1286,7 @@ static void kvm_mmu_write_protect_pt_masked(struct kvm *kvm,
{ {
struct kvm_rmap_head *rmap_head; struct kvm_rmap_head *rmap_head;
if (is_tdp_mmu_enabled(kvm)) if (tdp_mmu_enabled)
kvm_tdp_mmu_clear_dirty_pt_masked(kvm, slot, kvm_tdp_mmu_clear_dirty_pt_masked(kvm, slot,
slot->base_gfn + gfn_offset, mask, true); slot->base_gfn + gfn_offset, mask, true);
...@@ -1312,7 +1319,7 @@ static void kvm_mmu_clear_dirty_pt_masked(struct kvm *kvm, ...@@ -1312,7 +1319,7 @@ static void kvm_mmu_clear_dirty_pt_masked(struct kvm *kvm,
{ {
struct kvm_rmap_head *rmap_head; struct kvm_rmap_head *rmap_head;
if (is_tdp_mmu_enabled(kvm)) if (tdp_mmu_enabled)
kvm_tdp_mmu_clear_dirty_pt_masked(kvm, slot, kvm_tdp_mmu_clear_dirty_pt_masked(kvm, slot,
slot->base_gfn + gfn_offset, mask, false); slot->base_gfn + gfn_offset, mask, false);
...@@ -1395,7 +1402,7 @@ bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm, ...@@ -1395,7 +1402,7 @@ bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm,
} }
} }
if (is_tdp_mmu_enabled(kvm)) if (tdp_mmu_enabled)
write_protected |= write_protected |=
kvm_tdp_mmu_write_protect_gfn(kvm, slot, gfn, min_level); kvm_tdp_mmu_write_protect_gfn(kvm, slot, gfn, min_level);
...@@ -1558,7 +1565,7 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range) ...@@ -1558,7 +1565,7 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
if (kvm_memslots_have_rmaps(kvm)) if (kvm_memslots_have_rmaps(kvm))
flush = kvm_handle_gfn_range(kvm, range, kvm_zap_rmap); flush = kvm_handle_gfn_range(kvm, range, kvm_zap_rmap);
if (is_tdp_mmu_enabled(kvm)) if (tdp_mmu_enabled)
flush = kvm_tdp_mmu_unmap_gfn_range(kvm, range, flush); flush = kvm_tdp_mmu_unmap_gfn_range(kvm, range, flush);
return flush; return flush;
...@@ -1571,7 +1578,7 @@ bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range) ...@@ -1571,7 +1578,7 @@ bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
if (kvm_memslots_have_rmaps(kvm)) if (kvm_memslots_have_rmaps(kvm))
flush = kvm_handle_gfn_range(kvm, range, kvm_set_pte_rmap); flush = kvm_handle_gfn_range(kvm, range, kvm_set_pte_rmap);
if (is_tdp_mmu_enabled(kvm)) if (tdp_mmu_enabled)
flush |= kvm_tdp_mmu_set_spte_gfn(kvm, range); flush |= kvm_tdp_mmu_set_spte_gfn(kvm, range);
return flush; return flush;
...@@ -1646,7 +1653,7 @@ bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) ...@@ -1646,7 +1653,7 @@ bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
if (kvm_memslots_have_rmaps(kvm)) if (kvm_memslots_have_rmaps(kvm))
young = kvm_handle_gfn_range(kvm, range, kvm_age_rmap); young = kvm_handle_gfn_range(kvm, range, kvm_age_rmap);
if (is_tdp_mmu_enabled(kvm)) if (tdp_mmu_enabled)
young |= kvm_tdp_mmu_age_gfn_range(kvm, range); young |= kvm_tdp_mmu_age_gfn_range(kvm, range);
return young; return young;
...@@ -1659,7 +1666,7 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) ...@@ -1659,7 +1666,7 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
if (kvm_memslots_have_rmaps(kvm)) if (kvm_memslots_have_rmaps(kvm))
young = kvm_handle_gfn_range(kvm, range, kvm_test_age_rmap); young = kvm_handle_gfn_range(kvm, range, kvm_test_age_rmap);
if (is_tdp_mmu_enabled(kvm)) if (tdp_mmu_enabled)
young |= kvm_tdp_mmu_test_age_gfn(kvm, range); young |= kvm_tdp_mmu_test_age_gfn(kvm, range);
return young; return young;
...@@ -3604,7 +3611,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) ...@@ -3604,7 +3611,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
if (r < 0) if (r < 0)
goto out_unlock; goto out_unlock;
if (is_tdp_mmu_enabled(vcpu->kvm)) { if (tdp_mmu_enabled) {
root = kvm_tdp_mmu_get_vcpu_root_hpa(vcpu); root = kvm_tdp_mmu_get_vcpu_root_hpa(vcpu);
mmu->root.hpa = root; mmu->root.hpa = root;
} else if (shadow_root_level >= PT64_ROOT_4LEVEL) { } else if (shadow_root_level >= PT64_ROOT_4LEVEL) {
...@@ -5727,6 +5734,9 @@ void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level, ...@@ -5727,6 +5734,9 @@ void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level,
tdp_root_level = tdp_forced_root_level; tdp_root_level = tdp_forced_root_level;
max_tdp_level = tdp_max_root_level; max_tdp_level = tdp_max_root_level;
#ifdef CONFIG_X86_64
tdp_mmu_enabled = tdp_mmu_allowed && tdp_enabled;
#endif
/* /*
* max_huge_page_level reflects KVM's MMU capabilities irrespective * max_huge_page_level reflects KVM's MMU capabilities irrespective
* of kernel support, e.g. KVM may be capable of using 1GB pages when * of kernel support, e.g. KVM may be capable of using 1GB pages when
...@@ -5974,7 +5984,7 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm) ...@@ -5974,7 +5984,7 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm)
* write and in the same critical section as making the reload request, * write and in the same critical section as making the reload request,
* e.g. before kvm_zap_obsolete_pages() could drop mmu_lock and yield. * e.g. before kvm_zap_obsolete_pages() could drop mmu_lock and yield.
*/ */
if (is_tdp_mmu_enabled(kvm)) if (tdp_mmu_enabled)
kvm_tdp_mmu_invalidate_all_roots(kvm); kvm_tdp_mmu_invalidate_all_roots(kvm);
/* /*
...@@ -5999,7 +6009,7 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm) ...@@ -5999,7 +6009,7 @@ static void kvm_mmu_zap_all_fast(struct kvm *kvm)
* Deferring the zap until the final reference to the root is put would * Deferring the zap until the final reference to the root is put would
* lead to use-after-free. * lead to use-after-free.
*/ */
if (is_tdp_mmu_enabled(kvm)) if (tdp_mmu_enabled)
kvm_tdp_mmu_zap_invalidated_roots(kvm); kvm_tdp_mmu_zap_invalidated_roots(kvm);
} }
...@@ -6111,7 +6121,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) ...@@ -6111,7 +6121,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
flush = kvm_rmap_zap_gfn_range(kvm, gfn_start, gfn_end); flush = kvm_rmap_zap_gfn_range(kvm, gfn_start, gfn_end);
if (is_tdp_mmu_enabled(kvm)) { if (tdp_mmu_enabled) {
for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++)
flush = kvm_tdp_mmu_zap_leafs(kvm, i, gfn_start, flush = kvm_tdp_mmu_zap_leafs(kvm, i, gfn_start,
gfn_end, true, flush); gfn_end, true, flush);
...@@ -6144,7 +6154,7 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, ...@@ -6144,7 +6154,7 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
write_unlock(&kvm->mmu_lock); write_unlock(&kvm->mmu_lock);
} }
if (is_tdp_mmu_enabled(kvm)) { if (tdp_mmu_enabled) {
read_lock(&kvm->mmu_lock); read_lock(&kvm->mmu_lock);
kvm_tdp_mmu_wrprot_slot(kvm, memslot, start_level); kvm_tdp_mmu_wrprot_slot(kvm, memslot, start_level);
read_unlock(&kvm->mmu_lock); read_unlock(&kvm->mmu_lock);
...@@ -6387,7 +6397,7 @@ void kvm_mmu_try_split_huge_pages(struct kvm *kvm, ...@@ -6387,7 +6397,7 @@ void kvm_mmu_try_split_huge_pages(struct kvm *kvm,
u64 start, u64 end, u64 start, u64 end,
int target_level) int target_level)
{ {
if (!is_tdp_mmu_enabled(kvm)) if (!tdp_mmu_enabled)
return; return;
if (kvm_memslots_have_rmaps(kvm)) if (kvm_memslots_have_rmaps(kvm))
...@@ -6408,7 +6418,7 @@ void kvm_mmu_slot_try_split_huge_pages(struct kvm *kvm, ...@@ -6408,7 +6418,7 @@ void kvm_mmu_slot_try_split_huge_pages(struct kvm *kvm,
u64 start = memslot->base_gfn; u64 start = memslot->base_gfn;
u64 end = start + memslot->npages; u64 end = start + memslot->npages;
if (!is_tdp_mmu_enabled(kvm)) if (!tdp_mmu_enabled)
return; return;
if (kvm_memslots_have_rmaps(kvm)) { if (kvm_memslots_have_rmaps(kvm)) {
...@@ -6491,7 +6501,7 @@ void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm, ...@@ -6491,7 +6501,7 @@ void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm,
write_unlock(&kvm->mmu_lock); write_unlock(&kvm->mmu_lock);
} }
if (is_tdp_mmu_enabled(kvm)) { if (tdp_mmu_enabled) {
read_lock(&kvm->mmu_lock); read_lock(&kvm->mmu_lock);
kvm_tdp_mmu_zap_collapsible_sptes(kvm, slot); kvm_tdp_mmu_zap_collapsible_sptes(kvm, slot);
read_unlock(&kvm->mmu_lock); read_unlock(&kvm->mmu_lock);
...@@ -6526,7 +6536,7 @@ void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm, ...@@ -6526,7 +6536,7 @@ void kvm_mmu_slot_leaf_clear_dirty(struct kvm *kvm,
write_unlock(&kvm->mmu_lock); write_unlock(&kvm->mmu_lock);
} }
if (is_tdp_mmu_enabled(kvm)) { if (tdp_mmu_enabled) {
read_lock(&kvm->mmu_lock); read_lock(&kvm->mmu_lock);
kvm_tdp_mmu_clear_dirty_slot(kvm, memslot); kvm_tdp_mmu_clear_dirty_slot(kvm, memslot);
read_unlock(&kvm->mmu_lock); read_unlock(&kvm->mmu_lock);
...@@ -6561,7 +6571,7 @@ void kvm_mmu_zap_all(struct kvm *kvm) ...@@ -6561,7 +6571,7 @@ void kvm_mmu_zap_all(struct kvm *kvm)
kvm_mmu_commit_zap_page(kvm, &invalid_list); kvm_mmu_commit_zap_page(kvm, &invalid_list);
if (is_tdp_mmu_enabled(kvm)) if (tdp_mmu_enabled)
kvm_tdp_mmu_zap_all(kvm); kvm_tdp_mmu_zap_all(kvm);
write_unlock(&kvm->mmu_lock); write_unlock(&kvm->mmu_lock);
...@@ -6726,6 +6736,13 @@ void __init kvm_mmu_x86_module_init(void) ...@@ -6726,6 +6736,13 @@ void __init kvm_mmu_x86_module_init(void)
if (nx_huge_pages == -1) if (nx_huge_pages == -1)
__set_nx_huge_pages(get_nx_auto_mode()); __set_nx_huge_pages(get_nx_auto_mode());
/*
* Snapshot userspace's desire to enable the TDP MMU. Whether or not the
* TDP MMU is actually enabled is determined in kvm_configure_mmu()
* when the vendor module is loaded.
*/
tdp_mmu_allowed = tdp_mmu_enabled;
kvm_mmu_spte_module_init(); kvm_mmu_spte_module_init();
} }
......
...@@ -10,23 +10,18 @@ ...@@ -10,23 +10,18 @@
#include <asm/cmpxchg.h> #include <asm/cmpxchg.h>
#include <trace/events/kvm.h> #include <trace/events/kvm.h>
static bool __read_mostly tdp_mmu_enabled = true;
module_param_named(tdp_mmu, tdp_mmu_enabled, bool, 0644);
/* Initializes the TDP MMU for the VM, if enabled. */ /* Initializes the TDP MMU for the VM, if enabled. */
int kvm_mmu_init_tdp_mmu(struct kvm *kvm) int kvm_mmu_init_tdp_mmu(struct kvm *kvm)
{ {
struct workqueue_struct *wq; struct workqueue_struct *wq;
if (!tdp_enabled || !READ_ONCE(tdp_mmu_enabled)) if (!tdp_mmu_enabled)
return 0; return 0;
wq = alloc_workqueue("kvm", WQ_UNBOUND|WQ_MEM_RECLAIM|WQ_CPU_INTENSIVE, 0); wq = alloc_workqueue("kvm", WQ_UNBOUND|WQ_MEM_RECLAIM|WQ_CPU_INTENSIVE, 0);
if (!wq) if (!wq)
return -ENOMEM; return -ENOMEM;
/* This should not be changed for the lifetime of the VM. */
kvm->arch.tdp_mmu_enabled = true;
INIT_LIST_HEAD(&kvm->arch.tdp_mmu_roots); INIT_LIST_HEAD(&kvm->arch.tdp_mmu_roots);
spin_lock_init(&kvm->arch.tdp_mmu_pages_lock); spin_lock_init(&kvm->arch.tdp_mmu_pages_lock);
kvm->arch.tdp_mmu_zap_wq = wq; kvm->arch.tdp_mmu_zap_wq = wq;
...@@ -47,7 +42,7 @@ static __always_inline bool kvm_lockdep_assert_mmu_lock_held(struct kvm *kvm, ...@@ -47,7 +42,7 @@ static __always_inline bool kvm_lockdep_assert_mmu_lock_held(struct kvm *kvm,
void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm) void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm)
{ {
if (!kvm->arch.tdp_mmu_enabled) if (!tdp_mmu_enabled)
return; return;
/* Also waits for any queued work items. */ /* Also waits for any queued work items. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment