From: Nick Piggin Move the ZERO_PAGE remapping complexity to the move_pte macro in asm-generic, have it conditionally depend on __HAVE_ARCH_MULTIPLE_ZERO_PAGE, which gets defined for MIPS. For architectures without __HAVE_ARCH_MULTIPLE_ZERO_PAGE, move_pte becomes a noop. Signed-off-by: Nick Piggin Cc: Hugh Dickins Signed-off-by: Andrew Morton --- include/asm-generic/pgtable.h | 12 ++++++++++++ include/asm-mips/pgtable.h | 2 ++ mm/mremap.c | 6 +++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff -puN include/asm-generic/pgtable.h~mm-move_pte-to-remap-zero_page include/asm-generic/pgtable.h --- 25/include/asm-generic/pgtable.h~mm-move_pte-to-remap-zero_page Fri Sep 9 17:19:52 2005 +++ 25-akpm/include/asm-generic/pgtable.h Fri Sep 9 17:19:52 2005 @@ -158,6 +158,18 @@ static inline void ptep_set_wrprotect(st #define lazy_mmu_prot_update(pte) do { } while (0) #endif +#ifndef __HAVE_ARCH_MULTIPLE_ZERO_PAGE +#define move_pte(pte, prot, old_addr, new_addr) (pte) +#else +#define move_pte(pte, prot, old_addr, new_addr) \ +({ \ + pte_t newpte = (pte); \ + if (pfn_valid(pte_pfn(pte)) && pte_page(pte) == ZERO_PAGE(old_addr)) \ + newpte = mk_pte(ZERO_PAGE(new_addr), (prot))); \ + newpte; \ +}) +#endif + /* * When walking page tables, get the address of the next boundary, * or the end address of the range if that comes earlier. Although no diff -puN include/asm-mips/pgtable.h~mm-move_pte-to-remap-zero_page include/asm-mips/pgtable.h --- 25/include/asm-mips/pgtable.h~mm-move_pte-to-remap-zero_page Fri Sep 9 17:19:52 2005 +++ 25-akpm/include/asm-mips/pgtable.h Fri Sep 9 17:19:52 2005 @@ -68,6 +68,8 @@ extern unsigned long zero_page_mask; #define ZERO_PAGE(vaddr) \ (virt_to_page(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask))) +#define __HAVE_ARCH_MULTIPLE_ZERO_PAGE + extern void paging_init(void); /* diff -puN mm/mremap.c~mm-move_pte-to-remap-zero_page mm/mremap.c --- 25/mm/mremap.c~mm-move_pte-to-remap-zero_page Fri Sep 9 17:19:52 2005 +++ 25-akpm/mm/mremap.c Fri Sep 9 17:19:52 2005 @@ -141,10 +141,10 @@ move_one_page(struct vm_area_struct *vma if (dst) { pte_t pte; pte = ptep_clear_flush(vma, old_addr, src); + /* ZERO_PAGE can be dependant on virtual addr */ - if (pfn_valid(pte_pfn(pte)) && - pte_page(pte) == ZERO_PAGE(old_addr)) - pte = pte_wrprotect(mk_pte(ZERO_PAGE(new_addr), new_vma->vm_page_prot)); + pte = move_pte(pte, new_vma->vm_page_prot, + old_addr, new_addr); set_pte_at(mm, new_addr, dst, pte); } else error = -ENOMEM; _