aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorAndres Lagar-Cavilla <andreslc@google.com>2014-09-22 17:54:42 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2014-09-24 08:07:58 -0400
commit57128468080a8b6ea452223036d3e417f748af55 (patch)
treee89cfc349a9c39710cfab4e387119365a0d64958 /mm
parent8a9522d2fe6a1b643d3aef5ab7f097f73c601e7a (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.c5
-rw-r--r--mm/rmap.c6
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 */
109int __mmu_notifier_clear_flush_young(struct mm_struct *mm, 109int __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
diff --git a/mm/rmap.c b/mm/rmap.c
index 3e8491c504f8..bc74e0012809 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -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. */