aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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 /arch
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 'arch')
-rw-r--r--arch/arm/include/asm/kvm_host.h3
-rw-r--r--arch/arm64/include/asm/kvm_host.h3
-rw-r--r--arch/powerpc/include/asm/kvm_host.h2
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h2
-rw-r--r--arch/powerpc/kvm/book3s.c4
-rw-r--r--arch/powerpc/kvm/book3s.h3
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_hv.c4
-rw-r--r--arch/powerpc/kvm/book3s_pr.c3
-rw-r--r--arch/powerpc/kvm/e500_mmu_host.c2
-rw-r--r--arch/x86/include/asm/kvm_host.h2
-rw-r--r--arch/x86/kvm/mmu.c38
11 files changed, 39 insertions, 27 deletions
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 032a8538318a..8c3f7eb62b54 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -170,7 +170,8 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
170int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices); 170int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
171 171
172/* We do not have shadow page tables, hence the empty hooks */ 172/* We do not have shadow page tables, hence the empty hooks */
173static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva) 173static inline int kvm_age_hva(struct kvm *kvm, unsigned long start,
174 unsigned long end)
174{ 175{
175 return 0; 176 return 0;
176} 177}
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index be9970a59497..a3c671b3acc9 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -180,7 +180,8 @@ int kvm_unmap_hva_range(struct kvm *kvm,
180void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); 180void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
181 181
182/* We do not have shadow page tables, hence the empty hooks */ 182/* We do not have shadow page tables, hence the empty hooks */
183static inline int kvm_age_hva(struct kvm *kvm, unsigned long hva) 183static inline int kvm_age_hva(struct kvm *kvm, unsigned long start,
184 unsigned long end)
184{ 185{
185 return 0; 186 return 0;
186} 187}
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 604000882352..d329bc5543a2 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -56,7 +56,7 @@
56extern int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); 56extern int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
57extern int kvm_unmap_hva_range(struct kvm *kvm, 57extern int kvm_unmap_hva_range(struct kvm *kvm,
58 unsigned long start, unsigned long end); 58 unsigned long start, unsigned long end);
59extern int kvm_age_hva(struct kvm *kvm, unsigned long hva); 59extern int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
60extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva); 60extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
61extern void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); 61extern void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
62 62
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index fb86a2299d8a..d4a92d7cea6a 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -243,7 +243,7 @@ struct kvmppc_ops {
243 int (*unmap_hva)(struct kvm *kvm, unsigned long hva); 243 int (*unmap_hva)(struct kvm *kvm, unsigned long hva);
244 int (*unmap_hva_range)(struct kvm *kvm, unsigned long start, 244 int (*unmap_hva_range)(struct kvm *kvm, unsigned long start,
245 unsigned long end); 245 unsigned long end);
246 int (*age_hva)(struct kvm *kvm, unsigned long hva); 246 int (*age_hva)(struct kvm *kvm, unsigned long start, unsigned long end);
247 int (*test_age_hva)(struct kvm *kvm, unsigned long hva); 247 int (*test_age_hva)(struct kvm *kvm, unsigned long hva);
248 void (*set_spte_hva)(struct kvm *kvm, unsigned long hva, pte_t pte); 248 void (*set_spte_hva)(struct kvm *kvm, unsigned long hva, pte_t pte);
249 void (*mmu_destroy)(struct kvm_vcpu *vcpu); 249 void (*mmu_destroy)(struct kvm_vcpu *vcpu);
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index dd03f6b299ba..c16cfbfeb781 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -851,9 +851,9 @@ int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
851 return kvm->arch.kvm_ops->unmap_hva_range(kvm, start, end); 851 return kvm->arch.kvm_ops->unmap_hva_range(kvm, start, end);
852} 852}
853 853
854int kvm_age_hva(struct kvm *kvm, unsigned long hva) 854int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
855{ 855{
856 return kvm->arch.kvm_ops->age_hva(kvm, hva); 856 return kvm->arch.kvm_ops->age_hva(kvm, start, end);
857} 857}
858 858
859int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) 859int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
diff --git a/arch/powerpc/kvm/book3s.h b/arch/powerpc/kvm/book3s.h
index 4bf956cf94d6..d2b3ec088b8c 100644
--- a/arch/powerpc/kvm/book3s.h
+++ b/arch/powerpc/kvm/book3s.h
@@ -17,7 +17,8 @@ extern void kvmppc_core_flush_memslot_hv(struct kvm *kvm,
17extern int kvm_unmap_hva_hv(struct kvm *kvm, unsigned long hva); 17extern int kvm_unmap_hva_hv(struct kvm *kvm, unsigned long hva);
18extern int kvm_unmap_hva_range_hv(struct kvm *kvm, unsigned long start, 18extern int kvm_unmap_hva_range_hv(struct kvm *kvm, unsigned long start,
19 unsigned long end); 19 unsigned long end);
20extern int kvm_age_hva_hv(struct kvm *kvm, unsigned long hva); 20extern int kvm_age_hva_hv(struct kvm *kvm, unsigned long start,
21 unsigned long end);
21extern int kvm_test_age_hva_hv(struct kvm *kvm, unsigned long hva); 22extern int kvm_test_age_hva_hv(struct kvm *kvm, unsigned long hva);
22extern void kvm_set_spte_hva_hv(struct kvm *kvm, unsigned long hva, pte_t pte); 23extern void kvm_set_spte_hva_hv(struct kvm *kvm, unsigned long hva, pte_t pte);
23 24
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 72c20bb16d26..81460c5359c0 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -1002,11 +1002,11 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
1002 return ret; 1002 return ret;
1003} 1003}
1004 1004
1005int kvm_age_hva_hv(struct kvm *kvm, unsigned long hva) 1005int kvm_age_hva_hv(struct kvm *kvm, unsigned long start, unsigned long end)
1006{ 1006{
1007 if (!kvm->arch.using_mmu_notifiers) 1007 if (!kvm->arch.using_mmu_notifiers)
1008 return 0; 1008 return 0;
1009 return kvm_handle_hva(kvm, hva, kvm_age_rmapp); 1009 return kvm_handle_hva_range(kvm, start, end, kvm_age_rmapp);
1010} 1010}
1011 1011
1012static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp, 1012static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index faffb27badd9..852fcd8951c4 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -295,7 +295,8 @@ static int kvm_unmap_hva_range_pr(struct kvm *kvm, unsigned long start,
295 return 0; 295 return 0;
296} 296}
297 297
298static int kvm_age_hva_pr(struct kvm *kvm, unsigned long hva) 298static int kvm_age_hva_pr(struct kvm *kvm, unsigned long start,
299 unsigned long end)
299{ 300{
300 /* XXX could be more clever ;) */ 301 /* XXX could be more clever ;) */
301 return 0; 302 return 0;
diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c
index 08f14bb57897..b1f3f630315e 100644
--- a/arch/powerpc/kvm/e500_mmu_host.c
+++ b/arch/powerpc/kvm/e500_mmu_host.c
@@ -732,7 +732,7 @@ int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
732 return 0; 732 return 0;
733} 733}
734 734
735int kvm_age_hva(struct kvm *kvm, unsigned long hva) 735int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
736{ 736{
737 /* XXX could be more clever ;) */ 737 /* XXX could be more clever ;) */
738 return 0; 738 return 0;
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index eeeb573fcf6f..763d273cab1d 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1035,7 +1035,7 @@ asmlinkage void kvm_spurious_fault(void);
1035#define KVM_ARCH_WANT_MMU_NOTIFIER 1035#define KVM_ARCH_WANT_MMU_NOTIFIER
1036int kvm_unmap_hva(struct kvm *kvm, unsigned long hva); 1036int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
1037int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end); 1037int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end);
1038int kvm_age_hva(struct kvm *kvm, unsigned long hva); 1038int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end);
1039int kvm_test_age_hva(struct kvm *kvm, unsigned long hva); 1039int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
1040void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte); 1040void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
1041int cpuid_maxphyaddr(struct kvm_vcpu *vcpu); 1041int cpuid_maxphyaddr(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 47d534066325..3201e93ebd07 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -1417,18 +1417,7 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
1417 struct rmap_iterator uninitialized_var(iter); 1417 struct rmap_iterator uninitialized_var(iter);
1418 int young = 0; 1418 int young = 0;
1419 1419
1420 /* 1420 BUG_ON(!shadow_accessed_mask);
1421 * In case of absence of EPT Access and Dirty Bits supports,
1422 * emulate the accessed bit for EPT, by checking if this page has
1423 * an EPT mapping, and clearing it if it does. On the next access,
1424 * a new EPT mapping will be established.
1425 * This has some overhead, but not as much as the cost of swapping
1426 * out actively used pages or breaking up actively used hugepages.
1427 */
1428 if (!shadow_accessed_mask) {
1429 young = kvm_unmap_rmapp(kvm, rmapp, slot, gfn, level, data);
1430 goto out;
1431 }
1432 1421
1433 for (sptep = rmap_get_first(*rmapp, &iter); sptep; 1422 for (sptep = rmap_get_first(*rmapp, &iter); sptep;
1434 sptep = rmap_get_next(&iter)) { 1423 sptep = rmap_get_next(&iter)) {
@@ -1440,7 +1429,6 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
1440 (unsigned long *)sptep); 1429 (unsigned long *)sptep);
1441 } 1430 }
1442 } 1431 }
1443out:
1444 trace_kvm_age_page(gfn, level, slot, young); 1432 trace_kvm_age_page(gfn, level, slot, young);
1445 return young; 1433 return young;
1446} 1434}
@@ -1489,9 +1477,29 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
1489 kvm_flush_remote_tlbs(vcpu->kvm); 1477 kvm_flush_remote_tlbs(vcpu->kvm);
1490} 1478}
1491 1479
1492int kvm_age_hva(struct kvm *kvm, unsigned long hva) 1480int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
1493{ 1481{
1494 return kvm_handle_hva(kvm, hva, 0, kvm_age_rmapp); 1482 /*
1483 * In case of absence of EPT Access and Dirty Bits supports,
1484 * emulate the accessed bit for EPT, by checking if this page has
1485 * an EPT mapping, and clearing it if it does. On the next access,
1486 * a new EPT mapping will be established.
1487 * This has some overhead, but not as much as the cost of swapping
1488 * out actively used pages or breaking up actively used hugepages.
1489 */
1490 if (!shadow_accessed_mask) {
1491 /*
1492 * We are holding the kvm->mmu_lock, and we are blowing up
1493 * shadow PTEs. MMU notifier consumers need to be kept at bay.
1494 * This is correct as long as we don't decouple the mmu_lock
1495 * protected regions (like invalidate_range_start|end does).
1496 */
1497 kvm->mmu_notifier_seq++;
1498 return kvm_handle_hva_range(kvm, start, end, 0,
1499 kvm_unmap_rmapp);
1500 }
1501
1502 return kvm_handle_hva_range(kvm, start, end, 0, kvm_age_rmapp);
1495} 1503}
1496 1504
1497int kvm_test_age_hva(struct kvm *kvm, unsigned long hva) 1505int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)