If PG_dcache_dirty is set for a page, we need to flush the source page before performing any copypage operation using a different virtual address. This fixes the copypage implementations on XScale, StrongARM and ARMv6. This patch fixes segmentation faults seen in the dynamic linker under the usage patterns in glibc 2.4/2.5. Signed-off-by: Richard Purdie --- arch/arm/mm/copypage-v4mc.c | 6 ++++++ arch/arm/mm/copypage-v6.c | 4 ++++ arch/arm/mm/copypage-xscale.c | 6 ++++++ include/asm-arm/cacheflush.h | 2 ++ 4 files changed, 18 insertions(+) Index: linux-2.6.16/arch/arm/mm/copypage-xscale.c =================================================================== --- linux-2.6.16.orig/arch/arm/mm/copypage-xscale.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16/arch/arm/mm/copypage-xscale.c 2007-02-21 20:15:44.000000000 +0100 @@ -19,6 +19,7 @@ #include #include #include +#include /* * 0xffff8000 to 0xffffffff is reserved for any ARM architecture @@ -91,6 +92,11 @@ void xscale_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) { + struct page *page = virt_to_page(kfrom); + + if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) + __flush_dcache_page(page_mapping(page), page); + spin_lock(&minicache_lock); set_pte(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot)); Index: linux-2.6.16/arch/arm/mm/copypage-v4mc.c =================================================================== --- linux-2.6.16.orig/arch/arm/mm/copypage-v4mc.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16/arch/arm/mm/copypage-v4mc.c 2007-02-21 20:15:44.000000000 +0100 @@ -19,6 +19,7 @@ #include #include #include +#include /* * 0xffff8000 to 0xffffffff is reserved for any ARM architecture @@ -69,6 +70,11 @@ void v4_mc_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr) { + struct page *page = virt_to_page(kfrom); + + if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) + __flush_dcache_page(page_mapping(page), page); + spin_lock(&minicache_lock); set_pte(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot)); Index: linux-2.6.16/arch/arm/mm/copypage-v6.c =================================================================== --- linux-2.6.16.orig/arch/arm/mm/copypage-v6.c 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16/arch/arm/mm/copypage-v6.c 2007-02-21 20:15:44.000000000 +0100 @@ -53,6 +53,10 @@ { unsigned int offset = CACHE_COLOUR(vaddr); unsigned long from, to; + struct page *page = virt_to_page(kfrom); + + if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) + __flush_dcache_page(page_mapping(page), page); /* * Discard data in the kernel mapping for the new page. Index: linux-2.6.16/include/asm-arm/cacheflush.h =================================================================== --- linux-2.6.16.orig/include/asm-arm/cacheflush.h 2006-03-20 06:53:29.000000000 +0100 +++ linux-2.6.16/include/asm-arm/cacheflush.h 2007-02-21 20:15:44.000000000 +0100 @@ -318,6 +318,8 @@ */ extern void flush_dcache_page(struct page *); +extern void __flush_dcache_page(struct address_space *mapping, struct page *page); + #define flush_dcache_mmap_lock(mapping) \ write_lock_irq(&(mapping)->tree_lock) #define flush_dcache_mmap_unlock(mapping) \