]> err.no Git - linux-2.6/commitdiff
[ARM] 4078/1: Fix ARM copypage cache coherency problems
authorRichard Purdie <rpurdie@rpsys.net>
Sat, 30 Dec 2006 15:08:50 +0000 (16:08 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 30 Dec 2006 17:05:08 +0000 (17:05 +0000)
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 for 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 <rpurdie@rpsys.net>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mm/copypage-v4mc.c
arch/arm/mm/copypage-v6.c
arch/arm/mm/copypage-xscale.c
include/asm-arm/cacheflush.h

index 408b05ae6b9b63dddec06afadf96f0780c089fa7..ded0e96d069d01994786f0afa39fe6734f513b50 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
 
 #include "mm.h"
 
@@ -69,6 +70,11 @@ mc_copy_user_page(void *from, void *to)
 
 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_ext(TOP_PTE(0xffff8000), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot), 0);
index 865777dec161d3d27fa3c931b56e75965afa97ab..3adb79257f43527339b9c891974d3f2a58e84ece 100644 (file)
@@ -53,6 +53,10 @@ static void v6_copy_user_page_aliasing(void *kto, const void *kfrom, unsigned lo
 {
        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 aea5da723596727ada083f15ea141fa82cb57870..2e455f82a4d50fbdc390100f6cbcf77c11e1ac4b 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
 
 #include "mm.h"
 
@@ -91,6 +92,11 @@ mc_copy_user_page(void *from, void *to)
 
 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_ext(TOP_PTE(COPYPAGE_MINICACHE), pfn_pte(__pa(kfrom) >> PAGE_SHIFT, minicache_pgprot), 0);
index 378a3a2ce8d93ea717dd1a64009153fd6aa5e96b..d51049522cd0f764bc3f120e64032090f0626024 100644 (file)
@@ -355,6 +355,8 @@ extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
  */
 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) \