On Tue, 1 May 2007, Benjamin Herrenschmidt wrote:


At present, update_mmu_cache() and lazy_mmu_prot_update() are always
called when ptep_set_access_flags() is called so why not move them into
ptep_set_access_flags() and change ptep_set_access_flags() to have an
additional boolean parameter (__update) that would when set, cause
update_mmu_cache() and lazy_mmu_prot_update() to be called.

Well, ptep_set_access_flags() is a low level arch hook, I'd rather not
start hiding update_mmu_cache() calls in it ...

Ben.



I have attached a patch (so pine does not mangle it) for linux-2.6.20.9.
Is this what you had in mind?

For linux-2.6.21, more work will be needed as it has more code calling ptep_set_access_flags.

Regards
        Mark Fortescue.
diff -ruNpd linux-2.6.20.9/include/asm-generic/pgtable.h 
linux-test/include/asm-generic/pgtable.h
--- linux-2.6.20.9/include/asm-generic/pgtable.h        2007-05-01 
12:57:56.000000000 +0100
+++ linux-test/include/asm-generic/pgtable.h    2007-05-01 14:20:05.000000000 
+0100
@@ -29,11 +29,16 @@ do {                                                        
                \
  * to a "more permissive" setting, which allows most architectures
  * to optimize this.
  */
-#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
-do {                                                                     \
-       set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry);         \
-       flush_tlb_page(__vma, __address);                                 \
-} while (0)
+#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty, 
__update) \
+({                                                                             
    \
+       if (__update) {                                                         
    \
+               set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry);       
    \
+               flush_tlb_page(__vma, __address);                               
    \
+       } else if (__dirty) {                                                   
    \
+               flush_tlb_page(__vma, __address);                               
    \
+       }                                                                       
    \
+       __update;                                                               
    \
+})
 #endif
 
 #ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
diff -ruNpd linux-2.6.20.9/include/asm-i386/pgtable.h 
linux-test/include/asm-i386/pgtable.h
--- linux-2.6.20.9/include/asm-i386/pgtable.h   2007-05-01 12:57:56.000000000 
+0100
+++ linux-test/include/asm-i386/pgtable.h       2007-05-01 13:43:38.000000000 
+0100
@@ -273,14 +273,17 @@ static inline pte_t pte_mkhuge(pte_t pte
  * bit at the same time.
  */
 #define  __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-#define ptep_set_access_flags(vma, address, ptep, entry, dirty)                
\
-do {                                                                   \
-       if (dirty) {                                                    \
-               (ptep)->pte_low = (entry).pte_low;                      \
-               pte_update_defer((vma)->vm_mm, (address), (ptep));      \
-               flush_tlb_page(vma, address);                           \
-       }                                                               \
-} while (0)
+#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty, 
__update)    \
+({                                                                             
        \
+       if (__dirty) {                                                          
        \
+               if (__update) {                                                 
        \
+                       (__ptep)->pte_low = (__entry).pte_low;                  
        \
+                       pte_update_defer((__vma)->vm_mm, (__address), 
(__ptep));        \
+               }                                                               
        \
+               flush_tlb_page(__vma, __address);                               
        \
+       }                                                                       
        \
+       __update;                                                               
        \
+})
 
 /*
  * We don't actually have these, but we want to advertise them so that
diff -ruNpd linux-2.6.20.9/include/asm-ia64/pgtable.h 
linux-test/include/asm-ia64/pgtable.h
--- linux-2.6.20.9/include/asm-ia64/pgtable.h   2007-04-30 19:04:59.000000000 
+0100
+++ linux-test/include/asm-ia64/pgtable.h       2007-05-01 13:48:07.000000000 
+0100
@@ -537,16 +537,25 @@ extern void lazy_mmu_prot_update (pte_t 
  * daccess_bit in ivt.S).
  */
 #ifdef CONFIG_SMP
-# define ptep_set_access_flags(__vma, __addr, __ptep, __entry, 
__safely_writable)      \
-do {                                                                           
        \
-       if (__safely_writable) {                                                
        \
-               set_pte(__ptep, __entry);                                       
        \
+# define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty, 
__update)      \
+({                                                                             
        \
+       if (__dirty) {                                                          
        \
+               if (__update)                                                   
        \
+                       set_pte(__ptep, __entry);                               
        \
                flush_tlb_page(__vma, __addr);                                  
        \
        }                                                                       
        \
-} while (0)
+       __update;                                                               
        \
+})
 #else
-# define ptep_set_access_flags(__vma, __addr, __ptep, __entry, 
__safely_writable)      \
-       ptep_establish(__vma, __addr, __ptep, __entry)
+# define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty, 
__update)      \
+({                                                                             
        \
+       if (__update)                                                           
        \
+               ptep_establish(__vma, __addr, __ptep, __entry);                 
        \
+       else if (__dirty)                                                       
        \
+               flush_tlb_page(__vma, __addr);                                  
        \
+       }                                                                       
        \
+       __update;                                                               
        \
+})
 #endif
 
 #  ifdef CONFIG_VIRTUAL_MEM_MAP
diff -ruNpd linux-2.6.20.9/include/asm-powerpc/pgtable.h 
linux-test/include/asm-powerpc/pgtable.h
--- linux-2.6.20.9/include/asm-powerpc/pgtable.h        2007-05-01 
12:57:56.000000000 +0100
+++ linux-test/include/asm-powerpc/pgtable.h    2007-05-01 13:58:56.000000000 
+0100
@@ -437,11 +437,15 @@ static inline void __ptep_set_access_fla
        :"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
        :"cc");
 }
-#define  ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
-       do {                                                               \
-               __ptep_set_access_flags(__ptep, __entry, __dirty);         \
-               flush_tlb_page_nohash(__vma, __address);                   \
-       } while(0)
+#define  ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty, 
__update) \
+({                                                                             
     \
+       if (__update) {                                                         
     \
+               __ptep_set_access_flags(__ptep, __entry, __dirty);              
     \
+               flush_tlb_page_nohash(__vma, __address);                        
     \
+       } else if (__dirty)                                                     
     \
+               flush_tlb_page(__vma, __address);                               
     \
+       __update;                                                               
     \
+})
 
 /*
  * Macro to mark a page protection value as "uncacheable".
diff -ruNpd linux-2.6.20.9/include/asm-ppc/pgtable.h 
linux-test/include/asm-ppc/pgtable.h
--- linux-2.6.20.9/include/asm-ppc/pgtable.h    2007-04-30 19:05:00.000000000 
+0100
+++ linux-test/include/asm-ppc/pgtable.h        2007-05-01 13:50:30.000000000 
+0100
@@ -693,11 +693,15 @@ static inline void __ptep_set_access_fla
        pte_update(ptep, 0, bits);
 }
 
-#define  ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
-       do {                                                               \
-               __ptep_set_access_flags(__ptep, __entry, __dirty);         \
-               flush_tlb_page_nohash(__vma, __address);                   \
-       } while(0)
+#define  ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty, 
__update) \
+({                                                                             
     \
+       if (__update) {                                                         
     \
+               __ptep_set_access_flags(__ptep, __entry, __dirty);              
     \
+               flush_tlb_page_nohash(__vma, __address);                        
     \
+       } else if (__dirty)                                                     
     \
+               flush_tlb_page(__vma, __address);                               
     \
+       __update;                                                               
     \
+})
 
 /*
  * Macro to mark a page protection value as "uncacheable".
diff -ruNpd linux-2.6.20.9/include/asm-s390/pgtable.h 
linux-test/include/asm-s390/pgtable.h
--- linux-2.6.20.9/include/asm-s390/pgtable.h   2007-05-01 12:57:56.000000000 
+0100
+++ linux-test/include/asm-s390/pgtable.h       2007-05-01 14:23:24.000000000 
+0100
@@ -628,8 +628,14 @@ ptep_establish(struct vm_area_struct *vm
        set_pte(ptep, entry);
 }
 
-#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
-       ptep_establish(__vma, __address, __ptep, __entry)
+#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty, 
__update) \
+       ({                                                                      
    \
+               if (__update)                                                   
    \
+                       ptep_establish(__vma, __address, __ptep, __entry);      
    \
+               else if (__dirty)                                               
    \
+                       flush_tlb_page(__vma, __address);                       
    \
+               __update;                                                       
    \
+       })
 
 /*
  * Test and clear dirty bit in storage key.
diff -ruNpd linux-2.6.20.9/include/asm-sparc/pgtable.h 
linux-test/include/asm-sparc/pgtable.h
--- linux-2.6.20.9/include/asm-sparc/pgtable.h  2007-04-30 19:05:01.000000000 
+0100
+++ linux-test/include/asm-sparc/pgtable.h      2007-05-01 14:32:35.000000000 
+0100
@@ -446,6 +446,27 @@ extern int io_remap_pfn_range(struct vm_
 #define GET_IOSPACE(pfn)               (pfn >> (BITS_PER_LONG - 4))
 #define GET_PFN(pfn)                   (pfn & 0x0fffffffUL)
 
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty, 
__update) \
+({                                                                             
    \
+       int __ret;                                                              
    \
+                                                                               
    \
+       if (sparc_cpu_model == sun4c) {                                         
    \
+               set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry);       
    \
+               flush_tlb_page(__vma, __address);                               
    \
+               __ret = 1;                                                      
    \
+       } else {                                                                
    \
+               if (__update) {                                                 
    \
+                       set_pte_at((__vma)->vm_mm, (__address), __ptep, 
__entry);   \
+                       flush_tlb_page(__vma, __address);                       
    \
+               } else if (__dirty) {                                           
    \
+                       flush_tlb_page(__vma, __address);                       
    \
+               }                                                               
    \
+               __ret = __update;                                               
    \
+       }                                                                       
    \
+       __ret;                                                                  
    \
+})
+
 #include <asm-generic/pgtable.h>
 
 #endif /* !(__ASSEMBLY__) */
diff -ruNpd linux-2.6.20.9/include/asm-x86_64/pgtable.h 
linux-test/include/asm-x86_64/pgtable.h
--- linux-2.6.20.9/include/asm-x86_64/pgtable.h 2007-05-01 12:57:57.000000000 
+0100
+++ linux-test/include/asm-x86_64/pgtable.h     2007-05-01 13:37:08.000000000 
+0100
@@ -396,13 +396,15 @@ static inline pte_t pte_modify(pte_t pte
  * race with other CPU's that might be updating the dirty
  * bit at the same time. */
 #define  __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
-       do {                                                              \
-               if (__dirty) {                                            \
-                       set_pte(__ptep, __entry);                         \
-                       flush_tlb_page(__vma, __address);                 \
-               }                                                         \
-       } while (0)
+#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty, 
__update) \
+       ({                                                                      
    \
+               if (__dirty) {                                                  
    \
+                       if (__update)                                           
    \
+                               set_pte(__ptep, __entry);                       
    \
+                       flush_tlb_page(__vma, __address);                       
    \
+               }                                                               
    \
+               __update;                                                       
    \
+       })
 
 /* Encode and de-code a swap entry */
 #define __swp_type(x)                  (((x).val >> 1) & 0x3f)
diff -ruNpd linux-2.6.20.9/mm/hugetlb.c linux-test/mm/hugetlb.c
--- linux-2.6.20.9/mm/hugetlb.c 2007-05-01 13:01:10.000000000 +0100
+++ linux-test/mm/hugetlb.c     2007-05-01 13:17:26.000000000 +0100
@@ -313,9 +313,10 @@ static void set_huge_ptep_writable(struc
        pte_t entry;
 
        entry = pte_mkwrite(pte_mkdirty(*ptep));
-       ptep_set_access_flags(vma, address, ptep, entry, 1);
-       update_mmu_cache(vma, address, entry);
-       lazy_mmu_prot_update(entry);
+       if (ptep_set_access_flags(vma, address, ptep, entry, 1, 1)) {
+               update_mmu_cache(vma, address, entry);
+               lazy_mmu_prot_update(entry);
+       }
 }
 
 
diff -ruNpd linux-2.6.20.9/mm/memory.c linux-test/mm/memory.c
--- linux-2.6.20.9/mm/memory.c  2007-05-01 12:57:57.000000000 +0100
+++ linux-test/mm/memory.c      2007-05-01 14:26:38.000000000 +0100
@@ -1553,9 +1553,11 @@ static int do_wp_page(struct mm_struct *
                flush_cache_page(vma, address, pte_pfn(orig_pte));
                entry = pte_mkyoung(orig_pte);
                entry = maybe_mkwrite(pte_mkdirty(entry), vma);
-               ptep_set_access_flags(vma, address, page_table, entry, 1);
-               update_mmu_cache(vma, address, entry);
-               lazy_mmu_prot_update(entry);
+               if (ptep_set_access_flags(vma, address, page_table,
+                                         entry, 1, 1)) {
+                       update_mmu_cache(vma, address, entry);
+                       lazy_mmu_prot_update(entry);
+               }
                ret |= VM_FAULT_WRITE;
                goto unlock;
        }
@@ -2423,19 +2425,10 @@ static inline int handle_pte_fault(struc
                entry = pte_mkdirty(entry);
        }
        entry = pte_mkyoung(entry);
-       if (!pte_same(old_entry, entry)) {
-               ptep_set_access_flags(vma, address, pte, entry, write_access);
+       if (ptep_set_access_flags(vma, address, pte, entry, write_access,
+                                 !pte_same(old_entry, entry))) {
                update_mmu_cache(vma, address, entry);
                lazy_mmu_prot_update(entry);
-       } else {
-               /*
-                * This is needed only for protection faults but the arch code
-                * is not yet telling us if this is a protection fault or not.
-                * This still avoids useless tlb flushes for .text page faults
-                * with threads.
-                */
-               if (write_access)
-                       flush_tlb_page(vma, address);
        }
 unlock:
        pte_unmap_unlock(pte, ptl);

Reply via email to