KVM: x86/mmu: Don't acquire mmu_lock when using indirect_shadow_pages as a heuristic
authorMingwei Zhang <mizhang@google.com>
Sat, 3 Feb 2024 00:23:40 +0000 (16:23 -0800)
committerSean Christopherson <seanjc@google.com>
Fri, 23 Feb 2024 00:19:06 +0000 (16:19 -0800)
commit474b99ed703b7e4031f3925adacf19e7c8af2075
treeb0de9c5f96fe94b08ba4559af846d4c758e34175
parent0dbd054699661dfffbc1c148664f8d03fd132569
KVM: x86/mmu: Don't acquire mmu_lock when using indirect_shadow_pages as a heuristic

Drop KVM's completely pointless acquisition of mmu_lock when deciding
whether or not to unprotect any shadow pages residing at the gfn before
resuming the guest to let it retry an instruction that KVM failed to
emulated.  In this case, indirect_shadow_pages is used as a coarse-grained
heuristic to check if there is any chance of there being a relevant shadow
page to unprotected.  But acquiring mmu_lock largely defeats any benefit
to the heuristic, as taking mmu_lock for write is likely far more costly
to the VM as a whole than unnecessarily walking mmu_page_hash.

Furthermore, the current code is already prone to false negatives and
false positives, as it drops mmu_lock before checking the flag and
unprotecting shadow pages.  And as evidenced by the lack of bug reports,
neither false positives nor false negatives are problematic.  A false
positive simply means that KVM will try to unprotect shadow pages that
have already been zapped.  And a false negative means that KVM will
resume the guest without unprotecting the gfn, i.e. if a shadow page was
_just_ created, the vCPU will hit the same page fault and do the whole
dance all over again, and detect and unprotect the shadow page the second
time around (or not, if something else zaps it first).

Reported-by: Jim Mattson <jmattson@google.com>
Signed-off-by: Mingwei Zhang <mizhang@google.com>
[sean: drop READ_ONCE() and comment change, rewrite changelog]
Link: https://lore.kernel.org/r/20240203002343.383056-2-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/x86.c