unsigned long fault_status)
 {
        int ret;
-       bool write_fault, exec_fault, writable, force_pte = false;
+       bool write_fault, writable, force_pte = false;
+       bool exec_fault, needs_exec;
        unsigned long mmu_seq;
        gfn_t gfn = fault_ipa >> PAGE_SHIFT;
        struct kvm *kvm = vcpu->kvm;
        if (exec_fault)
                invalidate_icache_guest_page(pfn, vma_pagesize);
 
+       /*
+        * If we took an execution fault we have made the
+        * icache/dcache coherent above and should now let the s2
+        * mapping be executable.
+        *
+        * Write faults (!exec_fault && FSC_PERM) are orthogonal to
+        * execute permissions, and we preserve whatever we have.
+        */
+       needs_exec = exec_fault ||
+               (fault_status == FSC_PERM && stage2_is_exec(kvm, fault_ipa));
+
        if (vma_pagesize == PMD_SIZE) {
                pmd_t new_pmd = pfn_pmd(pfn, mem_type);
                new_pmd = pmd_mkhuge(new_pmd);
                if (writable)
                        new_pmd = kvm_s2pmd_mkwrite(new_pmd);
 
-               if (exec_fault) {
+               if (needs_exec)
                        new_pmd = kvm_s2pmd_mkexec(new_pmd);
-               } else if (fault_status == FSC_PERM) {
-                       /* Preserve execute if XN was already cleared */
-                       if (stage2_is_exec(kvm, fault_ipa))
-                               new_pmd = kvm_s2pmd_mkexec(new_pmd);
-               }
 
                ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
        } else {
                        mark_page_dirty(kvm, gfn);
                }
 
-               if (exec_fault) {
+               if (needs_exec)
                        new_pte = kvm_s2pte_mkexec(new_pte);
-               } else if (fault_status == FSC_PERM) {
-                       /* Preserve execute if XN was already cleared */
-                       if (stage2_is_exec(kvm, fault_ipa))
-                               new_pte = kvm_s2pte_mkexec(new_pte);
-               }
 
                ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte, flags);
        }