[PATCH] KVM: fix bogus pagefault on writable pages
[powerpc.git] / drivers / kvm / paging_tmpl.h
index 03c474a..6bc4195 100644 (file)
@@ -271,9 +271,10 @@ static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu,
        pt_element_t *guest_ent;
        int writable_shadow;
        gfn_t gfn;
+       struct kvm_mmu_page *page;
 
        if (is_writeble_pte(*shadow_ent))
-               return 0;
+               return !user || (*shadow_ent & PT_USER_MASK);
 
        writable_shadow = *shadow_ent & PT_SHADOW_WRITABLE_MASK;
        if (user) {
@@ -303,16 +304,27 @@ static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu,
        }
 
        gfn = walker->gfn;
-       if (kvm_mmu_lookup_page(vcpu, gfn)) {
+
+       if (user) {
+               /*
+                * Usermode page faults won't be for page table updates.
+                */
+               while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
+                       pgprintk("%s: zap %lx %x\n",
+                                __FUNCTION__, gfn, page->role.word);
+                       kvm_mmu_zap_page(vcpu, page);
+               }
+       } else if (kvm_mmu_lookup_page(vcpu, gfn)) {
                pgprintk("%s: found shadow page for %lx, marking ro\n",
                         __FUNCTION__, gfn);
+               *guest_ent |= PT_DIRTY_MASK;
                *write_pt = 1;
                return 0;
        }
        mark_page_dirty(vcpu->kvm, gfn);
        *shadow_ent |= PT_WRITABLE_MASK;
        *guest_ent |= PT_DIRTY_MASK;
-       rmap_add(vcpu->kvm, shadow_ent);
+       rmap_add(vcpu, shadow_ent);
 
        return 1;
 }
@@ -328,7 +340,8 @@ static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu,
  *   - normal guest page fault due to the guest pte marked not present, not
  *     writable, or not executable
  *
- *  Returns: 1 if we need to emulate the instruction, 0 otherwise
+ *  Returns: 1 if we need to emulate the instruction, 0 otherwise, or
+ *           a negative value on error.
  */
 static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
                               u32 error_code)
@@ -340,8 +353,15 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
        u64 *shadow_pte;
        int fixed;
        int write_pt = 0;
+       int r;
 
        pgprintk("%s: addr %lx err %x\n", __FUNCTION__, addr, error_code);
+       kvm_mmu_audit(vcpu, "pre page fault");
+
+       r = mmu_topup_memory_caches(vcpu);
+       if (r)
+               return r;
+
        /*
         * Look up the shadow pte for the faulting address.
         */
@@ -384,6 +404,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
                pgprintk("%s: io work, no access\n", __FUNCTION__);
                inject_page_fault(vcpu, addr,
                                  error_code | PFERR_PRESENT_MASK);
+               kvm_mmu_audit(vcpu, "post page fault (io)");
                return 0;
        }
 
@@ -392,10 +413,12 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
         */
        if (pte_present && !fixed && !write_pt) {
                inject_page_fault(vcpu, addr, error_code);
+               kvm_mmu_audit(vcpu, "post page fault (guest)");
                return 0;
        }
 
        ++kvm_stat.pf_fixed;
+       kvm_mmu_audit(vcpu, "post page fault (fixed)");
 
        return write_pt;
 }