aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-09-20 00:52:52 -0400
committerAlexander Graf <agraf@suse.de>2013-10-17 08:49:35 -0400
commitd78bca72961ae816181b386ff6b347419dfcd5cf (patch)
treef0faa9e3e9c8de42869ac3351402b83bf813deaf /arch/powerpc
parent93b159b466bdc9753bba5c3c51b40d7ddbbcc07c (diff)
KVM: PPC: Book3S PR: Use mmu_notifier_retry() in kvmppc_mmu_map_page()
When the MM code is invalidating a range of pages, it calls the KVM kvm_mmu_notifier_invalidate_range_start() notifier function, which calls kvm_unmap_hva_range(), which arranges to flush all the existing host HPTEs for guest pages. However, the Linux PTEs for the range being flushed are still valid at that point. We are not supposed to establish any new references to pages in the range until the ...range_end() notifier gets called. The PPC-specific KVM code doesn't get any explicit notification of that; instead, we are supposed to use mmu_notifier_retry() to test whether we are or have been inside a range flush notifier pair while we have been getting a page and instantiating a host HPTE for the page. This therefore adds a call to mmu_notifier_retry inside kvmppc_mmu_map_page(). This call is inside a region locked with kvm->mmu_lock, which is the same lock that is called by the KVM MMU notifier functions, thus ensuring that no new notification can proceed while we are in the locked region. Inside this region we also create the host HPTE and link the corresponding hpte_cache structure into the lists used to find it later. We cannot allocate the hpte_cache structure inside this locked region because that can lead to deadlock, so we allocate it outside the region and free it if we end up not using it. This also moves the updates of vcpu3s->hpte_cache_count inside the regions locked with vcpu3s->mmu_lock, and does the increment in kvmppc_mmu_hpte_cache_map() when the pte is added to the cache rather than when it is allocated, in order that the hpte_cache_count is accurate. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/kvm_book3s.h1
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_host.c37
-rw-r--r--arch/powerpc/kvm/book3s_mmu_hpte.c14
3 files changed, 39 insertions, 13 deletions
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index a07bd7e7d4a4..0ec00f4fef91 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -142,6 +142,7 @@ extern long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr,
142 142
143extern void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte); 143extern void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte);
144extern struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu); 144extern struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu);
145extern void kvmppc_mmu_hpte_cache_free(struct hpte_cache *pte);
145extern void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu); 146extern void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu);
146extern int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu); 147extern int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu);
147extern void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte); 148extern void kvmppc_mmu_invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte);
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c
index cc9fb89b8884..307e6e838e0d 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_host.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_host.c
@@ -93,6 +93,13 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte,
93 int r = 0; 93 int r = 0;
94 int hpsize = MMU_PAGE_4K; 94 int hpsize = MMU_PAGE_4K;
95 bool writable; 95 bool writable;
96 unsigned long mmu_seq;
97 struct kvm *kvm = vcpu->kvm;
98 struct hpte_cache *cpte;
99
100 /* used to check for invalidations in progress */
101 mmu_seq = kvm->mmu_notifier_seq;
102 smp_rmb();
96 103
97 /* Get host physical address for gpa */ 104 /* Get host physical address for gpa */
98 hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT, 105 hpaddr = kvmppc_gfn_to_pfn(vcpu, orig_pte->raddr >> PAGE_SHIFT,
@@ -143,6 +150,14 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte,
143 150
144 hash = hpt_hash(vpn, mmu_psize_defs[hpsize].shift, MMU_SEGSIZE_256M); 151 hash = hpt_hash(vpn, mmu_psize_defs[hpsize].shift, MMU_SEGSIZE_256M);
145 152
153 cpte = kvmppc_mmu_hpte_cache_next(vcpu);
154
155 spin_lock(&kvm->mmu_lock);
156 if (!cpte || mmu_notifier_retry(kvm, mmu_seq)) {
157 r = -EAGAIN;
158 goto out_unlock;
159 }
160
146map_again: 161map_again:
147 hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); 162 hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
148 163
@@ -150,7 +165,7 @@ map_again:
150 if (attempt > 1) 165 if (attempt > 1)
151 if (ppc_md.hpte_remove(hpteg) < 0) { 166 if (ppc_md.hpte_remove(hpteg) < 0) {
152 r = -1; 167 r = -1;
153 goto out; 168 goto out_unlock;
154 } 169 }
155 170
156 ret = ppc_md.hpte_insert(hpteg, vpn, hpaddr, rflags, vflags, 171 ret = ppc_md.hpte_insert(hpteg, vpn, hpaddr, rflags, vflags,
@@ -163,8 +178,6 @@ map_again:
163 attempt++; 178 attempt++;
164 goto map_again; 179 goto map_again;
165 } else { 180 } else {
166 struct hpte_cache *pte = kvmppc_mmu_hpte_cache_next(vcpu);
167
168 trace_kvm_book3s_64_mmu_map(rflags, hpteg, 181 trace_kvm_book3s_64_mmu_map(rflags, hpteg,
169 vpn, hpaddr, orig_pte); 182 vpn, hpaddr, orig_pte);
170 183
@@ -175,15 +188,21 @@ map_again:
175 hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); 188 hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
176 } 189 }
177 190
178 pte->slot = hpteg + (ret & 7); 191 cpte->slot = hpteg + (ret & 7);
179 pte->host_vpn = vpn; 192 cpte->host_vpn = vpn;
180 pte->pte = *orig_pte; 193 cpte->pte = *orig_pte;
181 pte->pfn = hpaddr >> PAGE_SHIFT; 194 cpte->pfn = hpaddr >> PAGE_SHIFT;
182 pte->pagesize = hpsize; 195 cpte->pagesize = hpsize;
183 196
184 kvmppc_mmu_hpte_cache_map(vcpu, pte); 197 kvmppc_mmu_hpte_cache_map(vcpu, cpte);
198 cpte = NULL;
185 } 199 }
200
201out_unlock:
202 spin_unlock(&kvm->mmu_lock);
186 kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT); 203 kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT);
204 if (cpte)
205 kvmppc_mmu_hpte_cache_free(cpte);
187 206
188out: 207out:
189 return r; 208 return r;
diff --git a/arch/powerpc/kvm/book3s_mmu_hpte.c b/arch/powerpc/kvm/book3s_mmu_hpte.c
index d2d280b16778..6b79bfc44ba5 100644
--- a/arch/powerpc/kvm/book3s_mmu_hpte.c
+++ b/arch/powerpc/kvm/book3s_mmu_hpte.c
@@ -98,6 +98,8 @@ void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
98 &vcpu3s->hpte_hash_vpte_64k[index]); 98 &vcpu3s->hpte_hash_vpte_64k[index]);
99#endif 99#endif
100 100
101 vcpu3s->hpte_cache_count++;
102
101 spin_unlock(&vcpu3s->mmu_lock); 103 spin_unlock(&vcpu3s->mmu_lock);
102} 104}
103 105
@@ -131,10 +133,10 @@ static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
131#ifdef CONFIG_PPC_BOOK3S_64 133#ifdef CONFIG_PPC_BOOK3S_64
132 hlist_del_init_rcu(&pte->list_vpte_64k); 134 hlist_del_init_rcu(&pte->list_vpte_64k);
133#endif 135#endif
136 vcpu3s->hpte_cache_count--;
134 137
135 spin_unlock(&vcpu3s->mmu_lock); 138 spin_unlock(&vcpu3s->mmu_lock);
136 139
137 vcpu3s->hpte_cache_count--;
138 call_rcu(&pte->rcu_head, free_pte_rcu); 140 call_rcu(&pte->rcu_head, free_pte_rcu);
139} 141}
140 142
@@ -331,15 +333,19 @@ struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
331 struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); 333 struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
332 struct hpte_cache *pte; 334 struct hpte_cache *pte;
333 335
334 pte = kmem_cache_zalloc(hpte_cache, GFP_KERNEL);
335 vcpu3s->hpte_cache_count++;
336
337 if (vcpu3s->hpte_cache_count == HPTEG_CACHE_NUM) 336 if (vcpu3s->hpte_cache_count == HPTEG_CACHE_NUM)
338 kvmppc_mmu_pte_flush_all(vcpu); 337 kvmppc_mmu_pte_flush_all(vcpu);
339 338
339 pte = kmem_cache_zalloc(hpte_cache, GFP_KERNEL);
340
340 return pte; 341 return pte;
341} 342}
342 343
344void kvmppc_mmu_hpte_cache_free(struct hpte_cache *pte)
345{
346 kmem_cache_free(hpte_cache, pte);
347}
348
343void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu) 349void kvmppc_mmu_hpte_destroy(struct kvm_vcpu *vcpu)
344{ 350{
345 kvmppc_mmu_pte_flush(vcpu, 0, 0); 351 kvmppc_mmu_pte_flush(vcpu, 0, 0);