Skip to content

Commit

Permalink
Rework ptep_set_access_flags and fix sun4c
Browse files Browse the repository at this point in the history
Some changes done a while ago to avoid pounding on ptep_set_access_flags and
update_mmu_cache in some race situations break sun4c which requires
update_mmu_cache() to always be called on minor faults.

This patch reworks ptep_set_access_flags() semantics, implementations and
callers so that it's now responsible for returning whether an update is
necessary or not (basically whether the PTE actually changed).  This allow
fixing the sparc implementation to always return 1 on sun4c.

[[email protected]: fixes, cleanups]
Signed-off-by: Benjamin Herrenschmidt <[email protected]>
Cc: Hugh Dickins <[email protected]>
Cc: David Miller <[email protected]>
Cc: Mark Fortescue <[email protected]>
Acked-by: William Lee Irwin III <[email protected]>
Cc: "Luck, Tony" <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
ozbenh authored and Linus Torvalds committed Jun 16, 2007
1 parent 679ce0a commit 8dab524
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 46 deletions.
17 changes: 12 additions & 5 deletions include/asm-generic/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,20 @@ do { \
* Largely same as above, but only sets the access flags (dirty,
* accessed, and writable). Furthermore, we know it always gets set
* to a "more permissive" setting, which allows most architectures
* to optimize this.
* to optimize this. We return whether the PTE actually changed, which
* in turn instructs the caller to do things like update__mmu_cache.
* This used to be done in the caller, but sparc needs minor faults to
* force that call on sun4c so we changed this macro slightly
*/
#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)
({ \
int __changed = !pte_same(*(__ptep), __entry); \
if (__changed) { \
set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \
flush_tlb_page(__vma, __address); \
} \
__changed; \
})
#endif

#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
Expand Down
8 changes: 5 additions & 3 deletions include/asm-i386/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,15 @@ static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
*/
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
#define ptep_set_access_flags(vma, address, ptep, entry, dirty) \
do { \
if (dirty) { \
({ \
int __changed = !pte_same(*(ptep), entry); \
if (__changed && dirty) { \
(ptep)->pte_low = (entry).pte_low; \
pte_update_defer((vma)->vm_mm, (address), (ptep)); \
flush_tlb_page(vma, address); \
} \
} while (0)
__changed; \
})

#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define ptep_test_and_clear_dirty(vma, addr, ptep) ({ \
Expand Down
25 changes: 16 additions & 9 deletions include/asm-ia64/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,16 +533,23 @@ extern void lazy_mmu_prot_update (pte_t pte);
* 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); \
flush_tlb_page(__vma, __addr); \
} \
} while (0)
# define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __safely_writable) \
({ \
int __changed = !pte_same(*(__ptep), __entry); \
if (__changed && __safely_writable) { \
set_pte(__ptep, __entry); \
flush_tlb_page(__vma, __addr); \
} \
__changed; \
})
#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, __safely_writable) \
({ \
int __changed = !pte_same(*(__ptep), __entry); \
if (__changed) \
ptep_establish(__vma, __addr, __ptep, __entry); \
__changed; \
})
#endif

# ifdef CONFIG_VIRTUAL_MEM_MAP
Expand Down
12 changes: 8 additions & 4 deletions include/asm-powerpc/pgtable-ppc32.h
Original file line number Diff line number Diff line change
Expand Up @@ -673,10 +673,14 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
}

#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)
({ \
int __changed = !pte_same(*(__ptep), __entry); \
if (__changed) { \
__ptep_set_access_flags(__ptep, __entry, __dirty); \
flush_tlb_page_nohash(__vma, __address); \
} \
__changed; \
})

/*
* Macro to mark a page protection value as "uncacheable".
Expand Down
12 changes: 8 additions & 4 deletions include/asm-powerpc/pgtable-ppc64.h
Original file line number Diff line number Diff line change
Expand Up @@ -413,10 +413,14 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
:"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)
({ \
int __changed = !pte_same(*(__ptep), __entry); \
if (__changed) { \
__ptep_set_access_flags(__ptep, __entry, __dirty); \
flush_tlb_page_nohash(__vma, __address); \
} \
__changed; \
})

/*
* Macro to mark a page protection value as "uncacheable".
Expand Down
12 changes: 8 additions & 4 deletions include/asm-ppc/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -694,10 +694,14 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
}

#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)
({ \
int __changed = !pte_same(*(__ptep), __entry); \
if (__changed) { \
__ptep_set_access_flags(__ptep, __entry, __dirty); \
flush_tlb_page_nohash(__vma, __address); \
} \
__changed; \
})

/*
* Macro to mark a page protection value as "uncacheable".
Expand Down
7 changes: 6 additions & 1 deletion include/asm-s390/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,12 @@ ptep_establish(struct vm_area_struct *vma,
}

#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
ptep_establish(__vma, __address, __ptep, __entry)
({ \
int __changed = !pte_same(*(__ptep), __entry); \
if (__changed) \
ptep_establish(__vma, __address, __ptep, __entry); \
__changed; \
})

/*
* Test and clear dirty bit in storage key.
Expand Down
11 changes: 11 additions & 0 deletions include/asm-sparc/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,17 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma,
#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) \
({ \
int __changed = !pte_same(*(__ptep), __entry); \
if (__changed) { \
set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \
flush_tlb_page(__vma, __address); \
} \
(sparc_cpu_model == sun4c) || __changed; \
})

#include <asm-generic/pgtable.h>

#endif /* !(__ASSEMBLY__) */
Expand Down
14 changes: 8 additions & 6 deletions include/asm-x86_64/pgtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,12 +395,14 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
* 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)
({ \
int __changed = !pte_same(*(__ptep), __entry); \
if (__changed && __dirty) { \
set_pte(__ptep, __entry); \
flush_tlb_page(__vma, __address); \
} \
__changed; \
})

/* Encode and de-code a swap entry */
#define __swp_type(x) (((x).val >> 1) & 0x3f)
Expand Down
7 changes: 4 additions & 3 deletions mm/hugetlb.c
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,10 @@ static void set_huge_ptep_writable(struct vm_area_struct *vma,
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)) {
update_mmu_cache(vma, address, entry);
lazy_mmu_prot_update(entry);
}
}


Expand Down
13 changes: 6 additions & 7 deletions mm/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -1691,9 +1691,10 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
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)) {
update_mmu_cache(vma, address, entry);
lazy_mmu_prot_update(entry);
}
ret |= VM_FAULT_WRITE;
goto unlock;
}
Expand Down Expand Up @@ -2525,10 +2526,9 @@ static inline int handle_pte_fault(struct mm_struct *mm,
pte_t *pte, pmd_t *pmd, int write_access)
{
pte_t entry;
pte_t old_entry;
spinlock_t *ptl;

old_entry = entry = *pte;
entry = *pte;
if (!pte_present(entry)) {
if (pte_none(entry)) {
if (vma->vm_ops) {
Expand Down Expand Up @@ -2561,8 +2561,7 @@ static inline int handle_pte_fault(struct mm_struct *mm,
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)) {
update_mmu_cache(vma, address, entry);
lazy_mmu_prot_update(entry);
} else {
Expand Down

0 comments on commit 8dab524

Please sign in to comment.