diff options
-rw-r--r-- | include/asm-generic/tlb.h | 135 | ||||
-rw-r--r-- | mm/memory.c | 124 |
2 files changed, 135 insertions, 124 deletions
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h index 5a946a08ff9d..e58fa777fa09 100644 --- a/include/asm-generic/tlb.h +++ b/include/asm-generic/tlb.h | |||
@@ -96,134 +96,25 @@ struct mmu_gather { | |||
96 | struct page *__pages[MMU_GATHER_BUNDLE]; | 96 | struct page *__pages[MMU_GATHER_BUNDLE]; |
97 | }; | 97 | }; |
98 | 98 | ||
99 | /* | 99 | #define HAVE_GENERIC_MMU_GATHER |
100 | * For UP we don't need to worry about TLB flush | ||
101 | * and page free order so much.. | ||
102 | */ | ||
103 | #ifdef CONFIG_SMP | ||
104 | #define tlb_fast_mode(tlb) (tlb->fast_mode) | ||
105 | #else | ||
106 | #define tlb_fast_mode(tlb) 1 | ||
107 | #endif | ||
108 | 100 | ||
109 | static inline int tlb_next_batch(struct mmu_gather *tlb) | 101 | static inline int tlb_fast_mode(struct mmu_gather *tlb) |
110 | { | 102 | { |
111 | struct mmu_gather_batch *batch; | 103 | #ifdef CONFIG_SMP |
112 | 104 | return tlb->fast_mode; | |
113 | batch = tlb->active; | 105 | #else |
114 | if (batch->next) { | 106 | /* |
115 | tlb->active = batch->next; | 107 | * For UP we don't need to worry about TLB flush |
116 | return 1; | 108 | * and page free order so much.. |
117 | } | 109 | */ |
118 | |||
119 | batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0); | ||
120 | if (!batch) | ||
121 | return 0; | ||
122 | |||
123 | batch->next = NULL; | ||
124 | batch->nr = 0; | ||
125 | batch->max = MAX_GATHER_BATCH; | ||
126 | |||
127 | tlb->active->next = batch; | ||
128 | tlb->active = batch; | ||
129 | |||
130 | return 1; | 110 | return 1; |
131 | } | ||
132 | |||
133 | /* tlb_gather_mmu | ||
134 | * Called to initialize an (on-stack) mmu_gather structure for page-table | ||
135 | * tear-down from @mm. The @fullmm argument is used when @mm is without | ||
136 | * users and we're going to destroy the full address space (exit/execve). | ||
137 | */ | ||
138 | static inline void | ||
139 | tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm) | ||
140 | { | ||
141 | tlb->mm = mm; | ||
142 | |||
143 | tlb->fullmm = fullmm; | ||
144 | tlb->need_flush = 0; | ||
145 | tlb->fast_mode = (num_possible_cpus() == 1); | ||
146 | tlb->local.next = NULL; | ||
147 | tlb->local.nr = 0; | ||
148 | tlb->local.max = ARRAY_SIZE(tlb->__pages); | ||
149 | tlb->active = &tlb->local; | ||
150 | |||
151 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | ||
152 | tlb->batch = NULL; | ||
153 | #endif | 111 | #endif |
154 | } | 112 | } |
155 | 113 | ||
156 | static inline void | 114 | void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm); |
157 | tlb_flush_mmu(struct mmu_gather *tlb) | 115 | void tlb_flush_mmu(struct mmu_gather *tlb); |
158 | { | 116 | void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end); |
159 | struct mmu_gather_batch *batch; | 117 | int __tlb_remove_page(struct mmu_gather *tlb, struct page *page); |
160 | |||
161 | if (!tlb->need_flush) | ||
162 | return; | ||
163 | tlb->need_flush = 0; | ||
164 | tlb_flush(tlb); | ||
165 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | ||
166 | tlb_table_flush(tlb); | ||
167 | #endif | ||
168 | |||
169 | if (tlb_fast_mode(tlb)) | ||
170 | return; | ||
171 | |||
172 | for (batch = &tlb->local; batch; batch = batch->next) { | ||
173 | free_pages_and_swap_cache(batch->pages, batch->nr); | ||
174 | batch->nr = 0; | ||
175 | } | ||
176 | tlb->active = &tlb->local; | ||
177 | } | ||
178 | |||
179 | /* tlb_finish_mmu | ||
180 | * Called at the end of the shootdown operation to free up any resources | ||
181 | * that were required. | ||
182 | */ | ||
183 | static inline void | ||
184 | tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) | ||
185 | { | ||
186 | struct mmu_gather_batch *batch, *next; | ||
187 | |||
188 | tlb_flush_mmu(tlb); | ||
189 | |||
190 | /* keep the page table cache within bounds */ | ||
191 | check_pgt_cache(); | ||
192 | |||
193 | for (batch = tlb->local.next; batch; batch = next) { | ||
194 | next = batch->next; | ||
195 | free_pages((unsigned long)batch, 0); | ||
196 | } | ||
197 | tlb->local.next = NULL; | ||
198 | } | ||
199 | |||
200 | /* __tlb_remove_page | ||
201 | * Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while | ||
202 | * handling the additional races in SMP caused by other CPUs caching valid | ||
203 | * mappings in their TLBs. Returns the number of free page slots left. | ||
204 | * When out of page slots we must call tlb_flush_mmu(). | ||
205 | */ | ||
206 | static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) | ||
207 | { | ||
208 | struct mmu_gather_batch *batch; | ||
209 | |||
210 | tlb->need_flush = 1; | ||
211 | |||
212 | if (tlb_fast_mode(tlb)) { | ||
213 | free_page_and_swap_cache(page); | ||
214 | return 1; /* avoid calling tlb_flush_mmu() */ | ||
215 | } | ||
216 | |||
217 | batch = tlb->active; | ||
218 | batch->pages[batch->nr++] = page; | ||
219 | VM_BUG_ON(batch->nr > batch->max); | ||
220 | if (batch->nr == batch->max) { | ||
221 | if (!tlb_next_batch(tlb)) | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | return batch->max - batch->nr; | ||
226 | } | ||
227 | 118 | ||
228 | /* tlb_remove_page | 119 | /* tlb_remove_page |
229 | * Similar to __tlb_remove_page but will call tlb_flush_mmu() itself when | 120 | * Similar to __tlb_remove_page but will call tlb_flush_mmu() itself when |
diff --git a/mm/memory.c b/mm/memory.c index 7bbe4d3df756..b73f677f0bb1 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -182,7 +182,7 @@ void sync_mm_rss(struct task_struct *task, struct mm_struct *mm) | |||
182 | { | 182 | { |
183 | __sync_task_rss_stat(task, mm); | 183 | __sync_task_rss_stat(task, mm); |
184 | } | 184 | } |
185 | #else | 185 | #else /* SPLIT_RSS_COUNTING */ |
186 | 186 | ||
187 | #define inc_mm_counter_fast(mm, member) inc_mm_counter(mm, member) | 187 | #define inc_mm_counter_fast(mm, member) inc_mm_counter(mm, member) |
188 | #define dec_mm_counter_fast(mm, member) dec_mm_counter(mm, member) | 188 | #define dec_mm_counter_fast(mm, member) dec_mm_counter(mm, member) |
@@ -191,8 +191,128 @@ static void check_sync_rss_stat(struct task_struct *task) | |||
191 | { | 191 | { |
192 | } | 192 | } |
193 | 193 | ||
194 | #endif /* SPLIT_RSS_COUNTING */ | ||
195 | |||
196 | #ifdef HAVE_GENERIC_MMU_GATHER | ||
197 | |||
198 | static int tlb_next_batch(struct mmu_gather *tlb) | ||
199 | { | ||
200 | struct mmu_gather_batch *batch; | ||
201 | |||
202 | batch = tlb->active; | ||
203 | if (batch->next) { | ||
204 | tlb->active = batch->next; | ||
205 | return 1; | ||
206 | } | ||
207 | |||
208 | batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0); | ||
209 | if (!batch) | ||
210 | return 0; | ||
211 | |||
212 | batch->next = NULL; | ||
213 | batch->nr = 0; | ||
214 | batch->max = MAX_GATHER_BATCH; | ||
215 | |||
216 | tlb->active->next = batch; | ||
217 | tlb->active = batch; | ||
218 | |||
219 | return 1; | ||
220 | } | ||
221 | |||
222 | /* tlb_gather_mmu | ||
223 | * Called to initialize an (on-stack) mmu_gather structure for page-table | ||
224 | * tear-down from @mm. The @fullmm argument is used when @mm is without | ||
225 | * users and we're going to destroy the full address space (exit/execve). | ||
226 | */ | ||
227 | void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm) | ||
228 | { | ||
229 | tlb->mm = mm; | ||
230 | |||
231 | tlb->fullmm = fullmm; | ||
232 | tlb->need_flush = 0; | ||
233 | tlb->fast_mode = (num_possible_cpus() == 1); | ||
234 | tlb->local.next = NULL; | ||
235 | tlb->local.nr = 0; | ||
236 | tlb->local.max = ARRAY_SIZE(tlb->__pages); | ||
237 | tlb->active = &tlb->local; | ||
238 | |||
239 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | ||
240 | tlb->batch = NULL; | ||
241 | #endif | ||
242 | } | ||
243 | |||
244 | void tlb_flush_mmu(struct mmu_gather *tlb) | ||
245 | { | ||
246 | struct mmu_gather_batch *batch; | ||
247 | |||
248 | if (!tlb->need_flush) | ||
249 | return; | ||
250 | tlb->need_flush = 0; | ||
251 | tlb_flush(tlb); | ||
252 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | ||
253 | tlb_table_flush(tlb); | ||
194 | #endif | 254 | #endif |
195 | 255 | ||
256 | if (tlb_fast_mode(tlb)) | ||
257 | return; | ||
258 | |||
259 | for (batch = &tlb->local; batch; batch = batch->next) { | ||
260 | free_pages_and_swap_cache(batch->pages, batch->nr); | ||
261 | batch->nr = 0; | ||
262 | } | ||
263 | tlb->active = &tlb->local; | ||
264 | } | ||
265 | |||
266 | /* tlb_finish_mmu | ||
267 | * Called at the end of the shootdown operation to free up any resources | ||
268 | * that were required. | ||
269 | */ | ||
270 | void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) | ||
271 | { | ||
272 | struct mmu_gather_batch *batch, *next; | ||
273 | |||
274 | tlb_flush_mmu(tlb); | ||
275 | |||
276 | /* keep the page table cache within bounds */ | ||
277 | check_pgt_cache(); | ||
278 | |||
279 | for (batch = tlb->local.next; batch; batch = next) { | ||
280 | next = batch->next; | ||
281 | free_pages((unsigned long)batch, 0); | ||
282 | } | ||
283 | tlb->local.next = NULL; | ||
284 | } | ||
285 | |||
286 | /* __tlb_remove_page | ||
287 | * Must perform the equivalent to __free_pte(pte_get_and_clear(ptep)), while | ||
288 | * handling the additional races in SMP caused by other CPUs caching valid | ||
289 | * mappings in their TLBs. Returns the number of free page slots left. | ||
290 | * When out of page slots we must call tlb_flush_mmu(). | ||
291 | */ | ||
292 | int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) | ||
293 | { | ||
294 | struct mmu_gather_batch *batch; | ||
295 | |||
296 | tlb->need_flush = 1; | ||
297 | |||
298 | if (tlb_fast_mode(tlb)) { | ||
299 | free_page_and_swap_cache(page); | ||
300 | return 1; /* avoid calling tlb_flush_mmu() */ | ||
301 | } | ||
302 | |||
303 | batch = tlb->active; | ||
304 | batch->pages[batch->nr++] = page; | ||
305 | if (batch->nr == batch->max) { | ||
306 | if (!tlb_next_batch(tlb)) | ||
307 | return 0; | ||
308 | } | ||
309 | VM_BUG_ON(batch->nr > batch->max); | ||
310 | |||
311 | return batch->max - batch->nr; | ||
312 | } | ||
313 | |||
314 | #endif /* HAVE_GENERIC_MMU_GATHER */ | ||
315 | |||
196 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE | 316 | #ifdef CONFIG_HAVE_RCU_TABLE_FREE |
197 | 317 | ||
198 | /* | 318 | /* |
@@ -268,7 +388,7 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table) | |||
268 | tlb_table_flush(tlb); | 388 | tlb_table_flush(tlb); |
269 | } | 389 | } |
270 | 390 | ||
271 | #endif | 391 | #endif /* CONFIG_HAVE_RCU_TABLE_FREE */ |
272 | 392 | ||
273 | /* | 393 | /* |
274 | * If a p?d_bad entry is found while walking page tables, report | 394 | * If a p?d_bad entry is found while walking page tables, report |