]> Pileus Git - ~andy/linux/blobdiff - arch/powerpc/kvm/book3s_hv_rm_mmu.c
Merge branch 'kvm-ppc-next' of git://github.com/agraf/linux-2.6 into kvm-queue
[~andy/linux] / arch / powerpc / kvm / book3s_hv_rm_mmu.c
index 9c515440ad1ae7e0451d3b3b67dd029ab06a0ebb..37fb3caa4c80a59c5162b92943e1d7878991b8f1 100644 (file)
@@ -134,7 +134,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index,
        unlock_rmap(rmap);
 }
 
-static pte_t lookup_linux_pte(pgd_t *pgdir, unsigned long hva,
+static pte_t lookup_linux_pte_and_update(pgd_t *pgdir, unsigned long hva,
                              int writing, unsigned long *pte_sizep)
 {
        pte_t *ptep;
@@ -225,26 +225,28 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
                is_io = pa & (HPTE_R_I | HPTE_R_W);
                pte_size = PAGE_SIZE << (pa & KVMPPC_PAGE_ORDER_MASK);
                pa &= PAGE_MASK;
+               pa |= gpa & ~PAGE_MASK;
        } else {
                /* Translate to host virtual address */
                hva = __gfn_to_hva_memslot(memslot, gfn);
 
                /* Look up the Linux PTE for the backing page */
                pte_size = psize;
-               pte = lookup_linux_pte(pgdir, hva, writing, &pte_size);
+               pte = lookup_linux_pte_and_update(pgdir, hva, writing,
+                                                 &pte_size);
                if (pte_present(pte)) {
                        if (writing && !pte_write(pte))
                                /* make the actual HPTE be read-only */
                                ptel = hpte_make_readonly(ptel);
                        is_io = hpte_cache_bits(pte_val(pte));
                        pa = pte_pfn(pte) << PAGE_SHIFT;
+                       pa |= hva & (pte_size - 1);
+                       pa |= gpa & ~PAGE_MASK;
                }
        }
 
        if (pte_size < psize)
                return H_PARAMETER;
-       if (pa && pte_size > psize)
-               pa |= gpa & (pte_size - 1);
 
        ptel &= ~(HPTE_R_PP0 - psize);
        ptel |= pa;
@@ -671,7 +673,8 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
                        memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
                        if (memslot) {
                                hva = __gfn_to_hva_memslot(memslot, gfn);
-                               pte = lookup_linux_pte(pgdir, hva, 1, &psize);
+                               pte = lookup_linux_pte_and_update(pgdir, hva,
+                                                                 1, &psize);
                                if (pte_present(pte) && !pte_write(pte))
                                        r = hpte_make_readonly(r);
                        }
@@ -749,6 +752,10 @@ static int slb_base_page_shift[4] = {
        20,     /* 1M, unsupported */
 };
 
+/* When called from virtmode, this func should be protected by
+ * preempt_disable(), otherwise, the holding of HPTE_V_HVLOCK
+ * can trigger deadlock issue.
+ */
 long kvmppc_hv_find_lock_hpte(struct kvm *kvm, gva_t eaddr, unsigned long slb_v,
                              unsigned long valid)
 {