aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAtsushi Nemoto <anemo@mba.ocn.ne.jp>2006-12-12 12:14:54 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-13 12:27:07 -0500
commit77fff4ae2b7bba6d66a8287d9ab948e2b6c16145 (patch)
treef05dca9b28a3b3de384c4eadb12f0691c88de794
parent1fb8cacc19dfe408a5dd758235561c58cadea174 (diff)
[PATCH] Fix COW D-cache aliasing on fork
Problem: 1. There is a process containing two thread (T1 and T2). The thread T1 calls fork(). Then dup_mmap() function called on T1 context. static inline int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) ... flush_cache_mm(current->mm); ... /* A */ (write-protect all Copy-On-Write pages) ... /* B */ flush_tlb_mm(current->mm); ... 2. When preemption happens between A and B (or on SMP kernel), the thread T2 can run and modify data on COW pages without page fault (modified data will stay in cache). 3. Some time after fork() completed, the thread T2 may cause a page fault by write-protect on a COW page. 4. Then data of the COW page will be copied to newly allocated physical page (copy_cow_page()). It reads data via kernel mapping. The kernel mapping can have different 'color' with user space mapping of the thread T2 (dcache aliasing). Therefore copy_cow_page() will copy stale data. Then the modified data in cache will be lost. In order to allow architecture code to deal with this problem allow architecture code to override copy_user_highpage() by defining __HAVE_ARCH_COPY_USER_HIGHPAGE in <asm/page.h>. The main part of this patch was originally written by Ralf Baechle; Atushi Nemoto did the the debugging. Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp> Signed-off-by: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/highmem.h4
1 files changed, 4 insertions, 0 deletions
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 3d8768b619e9..ea5780b518ef 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -96,6 +96,8 @@ static inline void memclear_highpage_flush(struct page *page, unsigned int offse
96 kunmap_atomic(kaddr, KM_USER0); 96 kunmap_atomic(kaddr, KM_USER0);
97} 97}
98 98
99#ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE
100
99static inline void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr) 101static inline void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr)
100{ 102{
101 char *vfrom, *vto; 103 char *vfrom, *vto;
@@ -109,6 +111,8 @@ static inline void copy_user_highpage(struct page *to, struct page *from, unsign
109 smp_wmb(); 111 smp_wmb();
110} 112}
111 113
114#endif
115
112static inline void copy_highpage(struct page *to, struct page *from) 116static inline void copy_highpage(struct page *to, struct page *from)
113{ 117{
114 char *vfrom, *vto; 118 char *vfrom, *vto;