Skip to content

Commit

Permalink
[PATCH] Optimize D-cache alias handling on fork
Browse files Browse the repository at this point in the history
Virtually index, physically tagged cache architectures can get away
without cache flushing when forking.  This patch adds a new cache
flushing function flush_cache_dup_mm(struct mm_struct *) which for the
moment I've implemented to do the same thing on all architectures
except on MIPS where it's a no-op.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
Ralf Baechle authored and Linus Torvalds committed Dec 13, 2006
1 parent bcd0228 commit ec8c044
Show file tree
Hide file tree
Showing 27 changed files with 54 additions and 7 deletions.
23 changes: 17 additions & 6 deletions Documentation/cachetlb.txt
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,21 @@ Here are the routines, one by one:
lines associated with 'mm'.

This interface is used to handle whole address space
page table operations such as what happens during
fork, exit, and exec.
page table operations such as what happens during exit and exec.

2) void flush_cache_dup_mm(struct mm_struct *mm)

This interface flushes an entire user address space from
the caches. That is, after running, there will be no cache
lines associated with 'mm'.

This interface is used to handle whole address space
page table operations such as what happens during fork.

This option is separate from flush_cache_mm to allow some
optimizations for VIPT caches.

2) void flush_cache_range(struct vm_area_struct *vma,
3) void flush_cache_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)

Here we are flushing a specific range of (user) virtual
Expand All @@ -199,7 +210,7 @@ Here are the routines, one by one:
call flush_cache_page (see below) for each entry which may be
modified.

3) void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)
4) void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn)

This time we need to remove a PAGE_SIZE sized range
from the cache. The 'vma' is the backing structure used by
Expand All @@ -220,7 +231,7 @@ Here are the routines, one by one:

This is used primarily during fault processing.

4) void flush_cache_kmaps(void)
5) void flush_cache_kmaps(void)

This routine need only be implemented if the platform utilizes
highmem. It will be called right before all of the kmaps
Expand All @@ -232,7 +243,7 @@ Here are the routines, one by one:

This routing should be implemented in asm/highmem.h

5) void flush_cache_vmap(unsigned long start, unsigned long end)
6) void flush_cache_vmap(unsigned long start, unsigned long end)
void flush_cache_vunmap(unsigned long start, unsigned long end)

Here in these two interfaces we are flushing a specific range
Expand Down
1 change: 1 addition & 0 deletions include/asm-alpha/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
/* Caches aren't brain-dead on the Alpha. */
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
Expand Down
2 changes: 2 additions & 0 deletions include/asm-arm/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,8 @@ extern void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
unsigned long len, int write);
#endif

#define flush_cache_dup_mm(mm) flush_cache_mm(mm)

/*
* flush_cache_user_range is used when we want to ensure that the
* Harvard caches are synchronised for the user space address range.
Expand Down
1 change: 1 addition & 0 deletions include/asm-arm26/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma,start,end) do { } while (0)
#define flush_cache_page(vma,vmaddr,pfn) do { } while (0)
#define flush_cache_vmap(start, end) do { } while (0)
Expand Down
1 change: 1 addition & 0 deletions include/asm-avr32/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ void invalidate_icache_region(void *start, size_t len);
*/
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_cache_vmap(start, end) do { } while (0)
Expand Down
1 change: 1 addition & 0 deletions include/asm-cris/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
Expand Down
1 change: 1 addition & 0 deletions include/asm-frv/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
*/
#define flush_cache_all() do {} while(0)
#define flush_cache_mm(mm) do {} while(0)
#define flush_cache_dup_mm(mm) do {} while(0)
#define flush_cache_range(mm, start, end) do {} while(0)
#define flush_cache_page(vma, vmaddr, pfn) do {} while(0)
#define flush_cache_vmap(start, end) do {} while(0)
Expand Down
1 change: 1 addition & 0 deletions include/asm-h8300/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#define flush_cache_all()
#define flush_cache_mm(mm)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma,a,b)
#define flush_cache_page(vma,p,pfn)
#define flush_dcache_page(page)
Expand Down
1 change: 1 addition & 0 deletions include/asm-i386/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
/* Caches aren't brain-dead on the intel. */
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
Expand Down
1 change: 1 addition & 0 deletions include/asm-ia64/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_icache_page(vma,page) do { } while (0)
Expand Down
3 changes: 3 additions & 0 deletions include/asm-m32r/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extern void _flush_cache_copyback_all(void);
#if defined(CONFIG_CHIP_M32700) || defined(CONFIG_CHIP_OPSP) || defined(CONFIG_CHIP_M32104)
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
Expand All @@ -29,6 +30,7 @@ extern void smp_flush_cache_all(void);
#elif defined(CONFIG_CHIP_M32102)
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
Expand All @@ -41,6 +43,7 @@ extern void smp_flush_cache_all(void);
#else
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
Expand Down
2 changes: 2 additions & 0 deletions include/asm-m68k/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ static inline void flush_cache_mm(struct mm_struct *mm)
__flush_cache_030();
}

#define flush_cache_dup_mm(mm) flush_cache_mm(mm)

/* flush_cache_range/flush_cache_page must be macros to avoid
a dependency on linux/mm.h, which includes this file... */
static inline void flush_cache_range(struct vm_area_struct *vma,
Expand Down
1 change: 1 addition & 0 deletions include/asm-m68knommu/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#define flush_cache_all() __flush_cache_all()
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) __flush_cache_all()
#define flush_cache_page(vma, vmaddr) do { } while (0)
#define flush_dcache_range(start,len) __flush_cache_all()
Expand Down
2 changes: 2 additions & 0 deletions include/asm-mips/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*
* - flush_cache_all() flushes entire cache
* - flush_cache_mm(mm) flushes the specified mm context's cache lines
* - flush_cache_dup mm(mm) handles cache flushing when forking
* - flush_cache_page(mm, vmaddr, pfn) flushes a single page
* - flush_cache_range(vma, start, end) flushes a range of pages
* - flush_icache_range(start, end) flush a range of instructions
Expand All @@ -31,6 +32,7 @@
extern void (*flush_cache_all)(void);
extern void (*__flush_cache_all)(void);
extern void (*flush_cache_mm)(struct mm_struct *mm);
#define flush_cache_dup_mm(mm) do { (void) (mm); } while (0)
extern void (*flush_cache_range)(struct vm_area_struct *vma,
unsigned long start, unsigned long end);
extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn);
Expand Down
2 changes: 2 additions & 0 deletions include/asm-parisc/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#define flush_cache_mm(mm) flush_cache_all_local()
#endif

#define flush_cache_dup_mm(mm) flush_cache_mm(mm)

#define flush_kernel_dcache_range(start,size) \
flush_kernel_dcache_range_asm((start), (start)+(size));

Expand Down
1 change: 1 addition & 0 deletions include/asm-powerpc/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_icache_page(vma, page) do { } while (0)
Expand Down
1 change: 1 addition & 0 deletions include/asm-s390/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
/* Caches aren't brain-dead on the s390. */
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
Expand Down
2 changes: 2 additions & 0 deletions include/asm-sh/cpu-sh2/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*
* - flush_cache_all() flushes entire cache
* - flush_cache_mm(mm) flushes the specified mm context's cache lines
* - flush_cache_dup mm(mm) handles cache flushing when forking
* - flush_cache_page(mm, vmaddr, pfn) flushes a single page
* - flush_cache_range(vma, start, end) flushes a range of pages
*
Expand All @@ -27,6 +28,7 @@
*/
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
Expand Down
3 changes: 3 additions & 0 deletions include/asm-sh/cpu-sh3/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*
* - flush_cache_all() flushes entire cache
* - flush_cache_mm(mm) flushes the specified mm context's cache lines
* - flush_cache_dup mm(mm) handles cache flushing when forking
* - flush_cache_page(mm, vmaddr, pfn) flushes a single page
* - flush_cache_range(vma, start, end) flushes a range of pages
*
Expand All @@ -39,6 +40,7 @@

void flush_cache_all(void);
void flush_cache_mm(struct mm_struct *mm);
#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end);
void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
Expand All @@ -48,6 +50,7 @@ void flush_icache_page(struct vm_area_struct *vma, struct page *page);
#else
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
Expand Down
1 change: 1 addition & 0 deletions include/asm-sh/cpu-sh4/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
void flush_cache_all(void);
void flush_cache_mm(struct mm_struct *mm);
#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end);
void flush_cache_page(struct vm_area_struct *vma, unsigned long addr,
Expand Down
2 changes: 2 additions & 0 deletions include/asm-sh64/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ extern void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long addr,
int len);

#define flush_cache_dup_mm(mm) flush_cache_mm(mm)

#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)

Expand Down
1 change: 1 addition & 0 deletions include/asm-sparc/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long)

#define flush_cache_all() BTFIXUP_CALL(flush_cache_all)()
#define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm)
#define flush_cache_dup_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm)
#define flush_cache_range(vma,start,end) BTFIXUP_CALL(flush_cache_range)(vma,start,end)
#define flush_cache_page(vma,addr,pfn) BTFIXUP_CALL(flush_cache_page)(vma,addr)
#define flush_icache_range(start, end) do { } while (0)
Expand Down
1 change: 1 addition & 0 deletions include/asm-sparc64/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
/* These are the same regardless of whether this is an SMP kernel or not. */
#define flush_cache_mm(__mm) \
do { if ((__mm) == current->mm) flushw_user(); } while(0)
#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
#define flush_cache_range(vma, start, end) \
flush_cache_mm((vma)->vm_mm)
#define flush_cache_page(vma, page, pfn) \
Expand Down
1 change: 1 addition & 0 deletions include/asm-v850/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
systems with MMUs, so we don't need them. */
#define flush_cache_all() ((void)0)
#define flush_cache_mm(mm) ((void)0)
#define flush_cache_dup_mm(mm) ((void)0)
#define flush_cache_range(vma, start, end) ((void)0)
#define flush_cache_page(vma, vmaddr, pfn) ((void)0)
#define flush_dcache_page(page) ((void)0)
Expand Down
1 change: 1 addition & 0 deletions include/asm-x86_64/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
/* Caches aren't brain-dead on the intel. */
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
Expand Down
2 changes: 2 additions & 0 deletions include/asm-xtensa/cacheflush.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);

#define flush_cache_all() __flush_invalidate_cache_all();
#define flush_cache_mm(mm) __flush_invalidate_cache_all();
#define flush_cache_dup_mm(mm) __flush_invalidate_cache_all();

#define flush_cache_vmap(start,end) __flush_invalidate_cache_all();
#define flush_cache_vunmap(start,end) __flush_invalidate_cache_all();
Expand All @@ -88,6 +89,7 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon

#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_dup_mm(mm) do { } while (0)

#define flush_cache_vmap(start,end) do { } while (0)
#define flush_cache_vunmap(start,end) do { } while (0)
Expand Down
2 changes: 1 addition & 1 deletion kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ static inline int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
struct mempolicy *pol;

down_write(&oldmm->mmap_sem);
flush_cache_mm(oldmm);
flush_cache_dup_mm(oldmm);
/*
* Not linked in yet - no deadlock potential:
*/
Expand Down

0 comments on commit ec8c044

Please sign in to comment.