Skip to content

Commit 8df9f1a

Browse files
sean-jcbonzini
authored andcommitted
KVM: x86/mmu: Skip !MMU-present SPTEs when removing SP in exclusive mode
If mmu_lock is held for write, don't bother setting !PRESENT SPTEs to REMOVED_SPTE when recursively zapping SPTEs as part of shadow page removal. The concurrent write protections provided by REMOVED_SPTE are not needed, there are no backing page side effects to record, and MMIO SPTEs can be left as is since they are protected by the memslot generation, not by ensuring that the MMIO SPTE is unreachable (which is racy with respect to lockless walks regardless of zapping behavior). Skipping !PRESENT drastically reduces the number of updates needed to tear down sparsely populated MMUs, e.g. when tearing down a 6gb VM that didn't touch much memory, 6929/7168 (~96.6%) of SPTEs were '0' and could be skipped. Avoiding the write itself is likely close to a wash, but avoiding __handle_changed_spte() is a clear-cut win as that involves saving and restoring all non-volatile GPRs (it's a subtly big function), as well as several conditional branches before bailing out. Cc: Ben Gardon <[email protected]> Signed-off-by: Sean Christopherson <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent d7eb79c commit 8df9f1a

File tree

1 file changed

+11
-0
lines changed

1 file changed

+11
-0
lines changed

arch/x86/kvm/mmu/tdp_mmu.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,18 @@ static void handle_removed_tdp_mmu_page(struct kvm *kvm, u64 *pt,
337337
cpu_relax();
338338
}
339339
} else {
340+
/*
341+
* If the SPTE is not MMU-present, there is no backing
342+
* page associated with the SPTE and so no side effects
343+
* that need to be recorded, and exclusive ownership of
344+
* mmu_lock ensures the SPTE can't be made present.
345+
* Note, zapping MMIO SPTEs is also unnecessary as they
346+
* are guarded by the memslots generation, not by being
347+
* unreachable.
348+
*/
340349
old_child_spte = READ_ONCE(*sptep);
350+
if (!is_shadow_present_pte(old_child_spte))
351+
continue;
341352

342353
/*
343354
* Marking the SPTE as a removed SPTE is not

0 commit comments

Comments
 (0)