Skip to content

Commit c13fda2

Browse files
sean-jcbonzini
authored andcommitted
KVM: Assert that notifier count is elevated in .change_pte()
In KVM's .change_pte() notification callback, replace the notifier sequence bump with a WARN_ON assertion that the notifier count is elevated. An elevated count provides stricter protections than bumping the sequence, and the sequence is guarnateed to be bumped before the count hits zero. When .change_pte() was added by commit 828502d ("ksm: add mmu_notifier set_pte_at_notify()"), bumping the sequence was necessary as .change_pte() would be invoked without any surrounding notifications. However, since commit 6bdb913 ("mm: wrap calls to set_pte_at_notify with invalidate_range_start and invalidate_range_end"), all calls to .change_pte() are guaranteed to be surrounded by start() and end(), and so are guaranteed to run with an elevated notifier count. Note, wrapping .change_pte() with .invalidate_range_{start,end}() is a bug of sorts, as invalidating the secondary MMU's (KVM's) PTE defeats the purpose of .change_pte(). Every arch's kvm_set_spte_hva() assumes .change_pte() is called when the relevant SPTE is present in KVM's MMU, as the original goal was to accelerate Kernel Samepage Merging (KSM) by updating KVM's SPTEs without requiring a VM-Exit (due to invalidating the SPTE). I.e. it means that .change_pte() is effectively dead code on _all_ architectures. x86 and MIPS are clearcut nops if the old SPTE is not-present, and that is guaranteed due to the prior invalidation. PPC simply unmaps the SPTE, which again should be a nop due to the invalidation. arm64 is a bit murky, but it's also likely a nop because kvm_pgtable_stage2_map() is called without a cache pointer, which means it will map an entry if and only if an existing PTE was found. For now, take advantage of the bug to simplify future consolidation of KVMs's MMU notifier code. Doing so will not greatly complicate fixing .change_pte(), assuming it's even worth fixing. .change_pte() has been broken for 8+ years and no one has complained. Even if there are KSM+KVM users that care deeply about its performance, the benefits of avoiding VM-Exits via .change_pte() need to be reevaluated to justify the added complexity and testing burden. Ripping out .change_pte() entirely would be a lot easier. Signed-off-by: Sean Christopherson <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent fe9a5b0 commit c13fda2

File tree

1 file changed

+7
-2
lines changed

1 file changed

+7
-2
lines changed

virt/kvm/kvm_main.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,12 +461,17 @@ static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn,
461461

462462
trace_kvm_set_spte_hva(address);
463463

464+
/*
465+
* .change_pte() must be surrounded by .invalidate_range_{start,end}(),
466+
* and so always runs with an elevated notifier count. This obviates
467+
* the need to bump the sequence count.
468+
*/
469+
WARN_ON_ONCE(!kvm->mmu_notifier_count);
470+
464471
idx = srcu_read_lock(&kvm->srcu);
465472

466473
KVM_MMU_LOCK(kvm);
467474

468-
kvm->mmu_notifier_seq++;
469-
470475
if (kvm_set_spte_hva(kvm, address, pte))
471476
kvm_flush_remote_tlbs(kvm);
472477

0 commit comments

Comments
 (0)