static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
                    unsigned pte_access, int user_fault,
-                   int write_fault, int dirty, int level,
+                   int write_fault, int level,
                    gfn_t gfn, pfn_t pfn, bool speculative,
                    bool can_unsync, bool host_writable)
 {
        spte = PT_PRESENT_MASK;
        if (!speculative)
                spte |= shadow_accessed_mask;
-       if (!dirty)
-               pte_access &= ~ACC_WRITE_MASK;
+
        if (pte_access & ACC_EXEC_MASK)
                spte |= shadow_x_mask;
        else
 
 static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
                         unsigned pt_access, unsigned pte_access,
-                        int user_fault, int write_fault, int dirty,
+                        int user_fault, int write_fault,
                         int *ptwrite, int level, gfn_t gfn,
                         pfn_t pfn, bool speculative,
                         bool host_writable)
        }
 
        if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault,
-                     dirty, level, gfn, pfn, speculative, true,
+                     level, gfn, pfn, speculative, true,
                      host_writable)) {
                if (write_fault)
                        *ptwrite = 1;
 
        for (i = 0; i < ret; i++, gfn++, start++)
                mmu_set_spte(vcpu, start, ACC_ALL,
-                            access, 0, 0, 1, NULL,
+                            access, 0, 0, NULL,
                             sp->role.level, gfn,
                             page_to_pfn(pages[i]), true, true);
 
                        unsigned pte_access = ACC_ALL;
 
                        mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, pte_access,
-                                    0, write, 1, &pt_write,
+                                    0, write, &pt_write,
                                     level, gfn, pfn, prefault, map_writable);
                        direct_pte_prefetch(vcpu, iterator.sptep);
                        ++vcpu->stat.pf_fixed;
 
        return (ret != orig_pte);
 }
 
-static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte)
+static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte,
+                                  bool last)
 {
        unsigned access;
 
        access = (gpte & (PT_WRITABLE_MASK | PT_USER_MASK)) | ACC_EXEC_MASK;
+       if (last && !is_dirty_gpte(gpte))
+               access &= ~ACC_WRITE_MASK;
+
 #if PTTYPE == 64
        if (vcpu->arch.mmu.nx)
                access &= ~(gpte >> PT64_NX_SHIFT);
                        pte |= PT_ACCESSED_MASK;
                }
 
-               pte_access = pt_access & FNAME(gpte_access)(vcpu, pte);
-
                walker->ptes[walker->level - 1] = pte;
 
                if (FNAME(is_last_gpte)(walker, vcpu, mmu, pte)) {
                        break;
                }
 
-               pt_access = pte_access;
+               pt_access &= FNAME(gpte_access)(vcpu, pte, false);
                --walker->level;
        }
 
                walker->ptes[walker->level - 1] = pte;
        }
 
+       pte_access = pt_access & FNAME(gpte_access)(vcpu, pte, true);
        walker->pt_access = pt_access;
        walker->pte_access = pte_access;
        pgprintk("%s: pte %llx pte_access %x pt_access %x\n",
                return;
 
        pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
-       pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
+       pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte, true);
        pfn = gfn_to_pfn_atomic(vcpu->kvm, gpte_to_gfn(gpte));
        if (is_error_pfn(pfn)) {
                kvm_release_pfn_clean(pfn);
         * vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1).
         */
        mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
-                    is_dirty_gpte(gpte), NULL, PT_PAGE_TABLE_LEVEL,
+                    NULL, PT_PAGE_TABLE_LEVEL,
                     gpte_to_gfn(gpte), pfn, true, true);
 }
 
                unsigned pte_access;
                gfn_t gfn;
                pfn_t pfn;
-               bool dirty;
 
                if (spte == sptep)
                        continue;
                if (FNAME(prefetch_invalid_gpte)(vcpu, sp, spte, gpte))
                        continue;
 
-               pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
+               pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte,
+                                                                 true);
                gfn = gpte_to_gfn(gpte);
-               dirty = is_dirty_gpte(gpte);
                pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn,
-                                     (pte_access & ACC_WRITE_MASK) && dirty);
+                                     pte_access & ACC_WRITE_MASK);
                if (is_error_pfn(pfn)) {
                        kvm_release_pfn_clean(pfn);
                        break;
                }
 
                mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
-                            dirty, NULL, PT_PAGE_TABLE_LEVEL, gfn,
+                            NULL, PT_PAGE_TABLE_LEVEL, gfn,
                             pfn, true, true);
        }
 }
 {
        unsigned access = gw->pt_access;
        struct kvm_mmu_page *sp = NULL;
-       bool dirty = is_dirty_gpte(gw->ptes[gw->level - 1]);
        int top_level;
        unsigned direct_access;
        struct kvm_shadow_walk_iterator it;
                return NULL;
 
        direct_access = gw->pt_access & gw->pte_access;
-       if (!dirty)
-               direct_access &= ~ACC_WRITE_MASK;
 
        top_level = vcpu->arch.mmu.root_level;
        if (top_level == PT32E_ROOT_LEVEL)
        }
 
        mmu_set_spte(vcpu, it.sptep, access, gw->pte_access & access,
-                    user_fault, write_fault, dirty, ptwrite, it.level,
+                    user_fault, write_fault, ptwrite, it.level,
                     gw->gfn, pfn, prefault, map_writable);
        FNAME(pte_prefetch)(vcpu, gw, it.sptep);
 
                return 0;
 
        /* mmio */
-       if (is_error_pfn(pfn)) {
-               unsigned access = walker.pte_access;
-               bool dirty = is_dirty_gpte(walker.ptes[walker.level - 1]);
-
-               if (!dirty)
-                       access &= ~ACC_WRITE_MASK;
-
+       if (is_error_pfn(pfn))
                return kvm_handle_bad_page(vcpu, mmu_is_nested(vcpu) ? 0 :
-                                          addr, access, walker.gfn, pfn);
-       }
-
+                                     addr, walker.pte_access, walker.gfn, pfn);
        spin_lock(&vcpu->kvm->mmu_lock);
        if (mmu_notifier_retry(vcpu, mmu_seq))
                goto out_unlock;
                }
 
                nr_present++;
-               pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
+               pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte,
+                                                                 true);
                host_writable = sp->spt[i] & SPTE_HOST_WRITEABLE;
 
                set_spte(vcpu, &sp->spt[i], pte_access, 0, 0,
-                        is_dirty_gpte(gpte), PT_PAGE_TABLE_LEVEL, gfn,
+                        PT_PAGE_TABLE_LEVEL, gfn,
                         spte_to_pfn(sp->spt[i]), true, false,
                         host_writable);
        }