diff options
author | Andres Lagar-Cavilla <andreslc@google.com> | 2014-09-22 17:54:42 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-09-24 08:07:58 -0400 |
commit | 57128468080a8b6ea452223036d3e417f748af55 (patch) | |
tree | e89cfc349a9c39710cfab4e387119365a0d64958 /virt/kvm/kvm_main.c | |
parent | 8a9522d2fe6a1b643d3aef5ab7f097f73c601e7a (diff) |
kvm: Fix page ageing bugs
1. We were calling clear_flush_young_notify in unmap_one, but we are
within an mmu notifier invalidate range scope. The spte exists no more
(due to range_start) and the accessed bit info has already been
propagated (due to kvm_pfn_set_accessed). Simply call
clear_flush_young.
2. We clear_flush_young on a primary MMU PMD, but this may be mapped
as a collection of PTEs by the secondary MMU (e.g. during log-dirty).
This required expanding the interface of the clear_flush_young mmu
notifier, so a lot of code has been trivially touched.
3. In the absence of shadow_accessed_mask (e.g. EPT A bit), we emulate
the access bit by blowing the spte. This requires proper synchronizing
with MMU notifier consumers, like every other removal of spte's does.
Signed-off-by: Andres Lagar-Cavilla <andreslc@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'virt/kvm/kvm_main.c')
-rw-r--r-- | virt/kvm/kvm_main.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index ff42b11d2b9c..0316314d48f4 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -369,7 +369,8 @@ static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn, | |||
369 | 369 | ||
370 | static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn, | 370 | static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn, |
371 | struct mm_struct *mm, | 371 | struct mm_struct *mm, |
372 | unsigned long address) | 372 | unsigned long start, |
373 | unsigned long end) | ||
373 | { | 374 | { |
374 | struct kvm *kvm = mmu_notifier_to_kvm(mn); | 375 | struct kvm *kvm = mmu_notifier_to_kvm(mn); |
375 | int young, idx; | 376 | int young, idx; |
@@ -377,7 +378,7 @@ static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn, | |||
377 | idx = srcu_read_lock(&kvm->srcu); | 378 | idx = srcu_read_lock(&kvm->srcu); |
378 | spin_lock(&kvm->mmu_lock); | 379 | spin_lock(&kvm->mmu_lock); |
379 | 380 | ||
380 | young = kvm_age_hva(kvm, address); | 381 | young = kvm_age_hva(kvm, start, end); |
381 | if (young) | 382 | if (young) |
382 | kvm_flush_remote_tlbs(kvm); | 383 | kvm_flush_remote_tlbs(kvm); |
383 | 384 | ||