aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2014-03-24 19:47:06 -0400
committerPaul Mackerras <paulus@samba.org>2014-03-29 04:58:35 -0400
commit797f9c07eb4cbc2d0ff27fac165a0b885da38840 (patch)
treeca135c3f5a5b2f37c702e69b55352b766764d4a6
parent739e2425fea6349ac674e93648953b3a08985f2f (diff)
KVM: PPC: Book3S HV: Don't use kvm_memslots() in real mode
With HV KVM, some high-frequency hypercalls such as H_ENTER are handled in real mode, and need to access the memslots array for the guest. Accessing the memslots array is safe, because we hold the SRCU read lock for the whole time that a guest vcpu is running. However, the checks that kvm_memslots() does when lockdep is enabled are potentially unsafe in real mode, when only the linear mapping is available. Furthermore, kvm_memslots() can be called from a secondary CPU thread, which is an offline CPU from the point of view of the host kernel, and is not running the task which holds the SRCU read lock. To avoid false positives in the checks in kvm_memslots(), and to avoid possible side effects from doing the checks in real mode, this replaces kvm_memslots() with kvm_memslots_raw() in all the places that execute in real mode. kvm_memslots_raw() is a new function that is like kvm_memslots() but uses rcu_dereference_raw_notrace() instead of kvm_dereference_check(). Signed-off-by: Paul Mackerras <paulus@samba.org> Acked-by: Scott Wood <scottwood@freescale.com>
-rw-r--r--arch/powerpc/include/asm/kvm_book3s_64.h12
-rw-r--r--arch/powerpc/kvm/book3s_hv_rm_mmu.c6
2 files changed, 15 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/kvm_book3s_64.h b/arch/powerpc/include/asm/kvm_book3s_64.h
index bf0fa8b0a883..51388befeddb 100644
--- a/arch/powerpc/include/asm/kvm_book3s_64.h
+++ b/arch/powerpc/include/asm/kvm_book3s_64.h
@@ -289,6 +289,18 @@ static inline void note_hpte_modification(struct kvm *kvm,
289 if (atomic_read(&kvm->arch.hpte_mod_interest)) 289 if (atomic_read(&kvm->arch.hpte_mod_interest))
290 rev->guest_rpte |= HPTE_GR_MODIFIED; 290 rev->guest_rpte |= HPTE_GR_MODIFIED;
291} 291}
292
293/*
294 * Like kvm_memslots(), but for use in real mode when we can't do
295 * any RCU stuff (since the secondary threads are offline from the
296 * kernel's point of view), and we can't print anything.
297 * Thus we use rcu_dereference_raw() rather than rcu_dereference_check().
298 */
299static inline struct kvm_memslots *kvm_memslots_raw(struct kvm *kvm)
300{
301 return rcu_dereference_raw_notrace(kvm->memslots);
302}
303
292#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */ 304#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
293 305
294#endif /* __ASM_KVM_BOOK3S_64_H__ */ 306#endif /* __ASM_KVM_BOOK3S_64_H__ */
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
index 37fb3caa4c80..1d6c56ad5b60 100644
--- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
+++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
@@ -111,7 +111,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index,
111 rcbits = hpte_r & (HPTE_R_R | HPTE_R_C); 111 rcbits = hpte_r & (HPTE_R_R | HPTE_R_C);
112 ptel = rev->guest_rpte |= rcbits; 112 ptel = rev->guest_rpte |= rcbits;
113 gfn = hpte_rpn(ptel, hpte_page_size(hpte_v, ptel)); 113 gfn = hpte_rpn(ptel, hpte_page_size(hpte_v, ptel));
114 memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn); 114 memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
115 if (!memslot) 115 if (!memslot)
116 return; 116 return;
117 117
@@ -192,7 +192,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
192 /* Find the memslot (if any) for this address */ 192 /* Find the memslot (if any) for this address */
193 gpa = (ptel & HPTE_R_RPN) & ~(psize - 1); 193 gpa = (ptel & HPTE_R_RPN) & ~(psize - 1);
194 gfn = gpa >> PAGE_SHIFT; 194 gfn = gpa >> PAGE_SHIFT;
195 memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn); 195 memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
196 pa = 0; 196 pa = 0;
197 is_io = ~0ul; 197 is_io = ~0ul;
198 rmap = NULL; 198 rmap = NULL;
@@ -670,7 +670,7 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
670 670
671 psize = hpte_page_size(v, r); 671 psize = hpte_page_size(v, r);
672 gfn = ((r & HPTE_R_RPN) & ~(psize - 1)) >> PAGE_SHIFT; 672 gfn = ((r & HPTE_R_RPN) & ~(psize - 1)) >> PAGE_SHIFT;
673 memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn); 673 memslot = __gfn_to_memslot(kvm_memslots_raw(kvm), gfn);
674 if (memslot) { 674 if (memslot) {
675 hva = __gfn_to_hva_memslot(memslot, gfn); 675 hva = __gfn_to_hva_memslot(memslot, gfn);
676 pte = lookup_linux_pte_and_update(pgdir, hva, 676 pte = lookup_linux_pte_and_update(pgdir, hva,