diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2011-05-24 20:12:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-25 11:39:16 -0400 |
commit | 267239116987d64850ad2037d8e0f3071dc3b5ce (patch) | |
tree | 142595897f7fc7bb673b791891dcc2fab31f6e91 /include/asm-generic | |
parent | 1c395176962176660bb108f90e97e1686cfe0d85 (diff) |
mm, powerpc: move the RCU page-table freeing into generic code
In case other architectures require RCU freed page-tables to implement
gup_fast() and software filled hashes and similar things, provide the
means to do so by moving the logic into generic code.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Requested-by: David Miller <davem@davemloft.net>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Richard Weinberger <richard@nod.at>
Cc: Tony Luck <tony.luck@intel.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Mel Gorman <mel@csn.ul.ie>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Nick Piggin <npiggin@kernel.dk>
Cc: Namhyung Kim <namhyung@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/asm-generic')
-rw-r--r-- | include/asm-generic/tlb.h | 56 |
1 files changed, 51 insertions, 5 deletions
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index 2d3547c84235..74f80f6b6cf1 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h | |||
@@ -29,6 +29,49 @@ | |||
29 | #define tlb_fast_mode(tlb) 1 | 29 | #define tlb_fast_mode(tlb) 1 |
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | ||
33 | /* | ||
34 | * Semi RCU freeing of the page directories. | ||
35 | * | ||
36 | * This is needed by some architectures to implement software pagetable walkers. | ||
37 | * | ||
38 | * gup_fast() and other software pagetable walkers do a lockless page-table | ||
39 | * walk and therefore needs some synchronization with the freeing of the page | ||
40 | * directories. The chosen means to accomplish that is by disabling IRQs over | ||
41 | * the walk. | ||
42 | * | ||
43 | * Architectures that use IPIs to flush TLBs will then automagically DTRT, | ||
44 | * since we unlink the page, flush TLBs, free the page. Since the disabling of | ||
45 | * IRQs delays the completion of the TLB flush we can never observe an already | ||
46 | * freed page. | ||
47 | * | ||
48 | * Architectures that do not have this (PPC) need to delay the freeing by some | ||
49 | * other means, this is that means. | ||
50 | * | ||
51 | * What we do is batch the freed directory pages (tables) and RCU free them. | ||
52 | * We use the sched RCU variant, as that guarantees that IRQ/preempt disabling | ||
53 | * holds off grace periods. | ||
54 | * | ||
55 | * However, in order to batch these pages we need to allocate storage, this | ||
56 | * allocation is deep inside the MM code and can thus easily fail on memory | ||
57 | * pressure. To guarantee progress we fall back to single table freeing, see | ||
58 | * the implementation of tlb_remove_table_one(). | ||
59 | * | ||
60 | */ | ||
61 | struct mmu_table_batch { | ||
62 | struct rcu_head rcu; | ||
63 | unsigned int nr; | ||
64 | void *tables[0]; | ||
65 | }; | ||
66 | |||
67 | #define MAX_TABLE_BATCH \ | ||
68 | ((PAGE_SIZE - sizeof(struct mmu_table_batch)) / sizeof(void *)) | ||
69 | |||
70 | extern void tlb_table_flush(struct mmu_gather *tlb); | ||
71 | extern void tlb_remove_table(struct mmu_gather *tlb, void *table); | ||
72 | |||
73 | #endif | ||
74 | |||
32 | /* | 75 | /* |
33 | * If we can't allocate a page to make a big batch of page pointers | 76 | * If we can't allocate a page to make a big batch of page pointers |
34 | * to work on, then just handle a few from the on-stack structure. | 77 | * to work on, then just handle a few from the on-stack structure. |
@@ -40,13 +83,13 @@ | |||
40 | */ | 83 | */ |
41 | struct mmu_gather { | 84 | struct mmu_gather { |
42 | struct mm_struct *mm; | 85 | struct mm_struct *mm; |
86 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | ||
87 | struct mmu_table_batch *batch; | ||
88 | #endif | ||
43 | unsigned int nr; /* set to ~0U means fast mode */ | 89 | unsigned int nr; /* set to ~0U means fast mode */ |
44 | unsigned int max; /* nr < max */ | 90 | unsigned int max; /* nr < max */ |
45 | unsigned int need_flush;/* Really unmapped some ptes? */ | 91 | unsigned int need_flush;/* Really unmapped some ptes? */ |
46 | unsigned int fullmm; /* non-zero means full mm flush */ | 92 | unsigned int fullmm; /* non-zero means full mm flush */ |
47 | #ifdef HAVE_ARCH_MMU_GATHER | ||
48 | struct arch_mmu_gather arch; | ||
49 | #endif | ||
50 | struct page **pages; | 93 | struct page **pages; |
51 | struct page *local[MMU_GATHER_BUNDLE]; | 94 | struct page *local[MMU_GATHER_BUNDLE]; |
52 | }; | 95 | }; |
@@ -82,8 +125,8 @@ tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm) | |||
82 | 125 | ||
83 | tlb->fullmm = fullmm; | 126 | tlb->fullmm = fullmm; |
84 | 127 | ||
85 | #ifdef HAVE_ARCH_MMU_GATHER | 128 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE |
86 | tlb->arch = ARCH_MMU_GATHER_INIT; | 129 | tlb->batch = NULL; |
87 | #endif | 130 | #endif |
88 | } | 131 | } |
89 | 132 | ||
@@ -94,6 +137,9 @@ tlb_flush_mmu(struct mmu_gather *tlb) | |||
94 | return; | 137 | return; |
95 | tlb->need_flush = 0; | 138 | tlb->need_flush = 0; |
96 | tlb_flush(tlb); | 139 | tlb_flush(tlb); |
140 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | ||
141 | tlb_table_flush(tlb); | ||
142 | #endif | ||
97 | if (!tlb_fast_mode(tlb)) { | 143 | if (!tlb_fast_mode(tlb)) { |
98 | free_pages_and_swap_cache(tlb->pages, tlb->nr); | 144 | free_pages_and_swap_cache(tlb->pages, tlb->nr); |
99 | tlb->nr = 0; | 145 | tlb->nr = 0; |