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 /mm | |
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 'mm')
-rw-r--r-- | mm/mmu_notifier.c | 5 | ||||
-rw-r--r-- | mm/rmap.c | 6 |
2 files changed, 8 insertions, 3 deletions
diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c index 950813b1eb36..2c8da9825fe3 100644 --- a/mm/mmu_notifier.c +++ b/mm/mmu_notifier.c | |||
@@ -107,7 +107,8 @@ void __mmu_notifier_release(struct mm_struct *mm) | |||
107 | * existed or not. | 107 | * existed or not. |
108 | */ | 108 | */ |
109 | int __mmu_notifier_clear_flush_young(struct mm_struct *mm, | 109 | int __mmu_notifier_clear_flush_young(struct mm_struct *mm, |
110 | unsigned long address) | 110 | unsigned long start, |
111 | unsigned long end) | ||
111 | { | 112 | { |
112 | struct mmu_notifier *mn; | 113 | struct mmu_notifier *mn; |
113 | int young = 0, id; | 114 | int young = 0, id; |
@@ -115,7 +116,7 @@ int __mmu_notifier_clear_flush_young(struct mm_struct *mm, | |||
115 | id = srcu_read_lock(&srcu); | 116 | id = srcu_read_lock(&srcu); |
116 | hlist_for_each_entry_rcu(mn, &mm->mmu_notifier_mm->list, hlist) { | 117 | hlist_for_each_entry_rcu(mn, &mm->mmu_notifier_mm->list, hlist) { |
117 | if (mn->ops->clear_flush_young) | 118 | if (mn->ops->clear_flush_young) |
118 | young |= mn->ops->clear_flush_young(mn, mm, address); | 119 | young |= mn->ops->clear_flush_young(mn, mm, start, end); |
119 | } | 120 | } |
120 | srcu_read_unlock(&srcu, id); | 121 | srcu_read_unlock(&srcu, id); |
121 | 122 | ||
@@ -1355,7 +1355,11 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount, | |||
1355 | continue; /* don't unmap */ | 1355 | continue; /* don't unmap */ |
1356 | } | 1356 | } |
1357 | 1357 | ||
1358 | if (ptep_clear_flush_young_notify(vma, address, pte)) | 1358 | /* |
1359 | * No need for _notify because we're within an | ||
1360 | * mmu_notifier_invalidate_range_ {start|end} scope. | ||
1361 | */ | ||
1362 | if (ptep_clear_flush_young(vma, address, pte)) | ||
1359 | continue; | 1363 | continue; |
1360 | 1364 | ||
1361 | /* Nuke the page table entry. */ | 1365 | /* Nuke the page table entry. */ |