diff options
Diffstat (limited to 'mm/percpu-vm.c')
-rw-r--r-- | mm/percpu-vm.c | 162 |
1 files changed, 35 insertions, 127 deletions
diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c index 51108165f829..538998a137d2 100644 --- a/mm/percpu-vm.c +++ b/mm/percpu-vm.c | |||
@@ -20,46 +20,25 @@ static struct page *pcpu_chunk_page(struct pcpu_chunk *chunk, | |||
20 | } | 20 | } |
21 | 21 | ||
22 | /** | 22 | /** |
23 | * pcpu_get_pages_and_bitmap - get temp pages array and bitmap | 23 | * pcpu_get_pages - get temp pages array |
24 | * @chunk: chunk of interest | 24 | * @chunk: chunk of interest |
25 | * @bitmapp: output parameter for bitmap | ||
26 | * @may_alloc: may allocate the array | ||
27 | * | 25 | * |
28 | * Returns pointer to array of pointers to struct page and bitmap, | 26 | * Returns pointer to array of pointers to struct page which can be indexed |
29 | * both of which can be indexed with pcpu_page_idx(). The returned | 27 | * with pcpu_page_idx(). Note that there is only one array and accesses |
30 | * array is cleared to zero and *@bitmapp is copied from | 28 | * should be serialized by pcpu_alloc_mutex. |
31 | * @chunk->populated. Note that there is only one array and bitmap | ||
32 | * and access exclusion is the caller's responsibility. | ||
33 | * | ||
34 | * CONTEXT: | ||
35 | * pcpu_alloc_mutex and does GFP_KERNEL allocation if @may_alloc. | ||
36 | * Otherwise, don't care. | ||
37 | * | 29 | * |
38 | * RETURNS: | 30 | * RETURNS: |
39 | * Pointer to temp pages array on success, NULL on failure. | 31 | * Pointer to temp pages array on success. |
40 | */ | 32 | */ |
41 | static struct page **pcpu_get_pages_and_bitmap(struct pcpu_chunk *chunk, | 33 | static struct page **pcpu_get_pages(struct pcpu_chunk *chunk_alloc) |
42 | unsigned long **bitmapp, | ||
43 | bool may_alloc) | ||
44 | { | 34 | { |
45 | static struct page **pages; | 35 | static struct page **pages; |
46 | static unsigned long *bitmap; | ||
47 | size_t pages_size = pcpu_nr_units * pcpu_unit_pages * sizeof(pages[0]); | 36 | size_t pages_size = pcpu_nr_units * pcpu_unit_pages * sizeof(pages[0]); |
48 | size_t bitmap_size = BITS_TO_LONGS(pcpu_unit_pages) * | ||
49 | sizeof(unsigned long); | ||
50 | |||
51 | if (!pages || !bitmap) { | ||
52 | if (may_alloc && !pages) | ||
53 | pages = pcpu_mem_zalloc(pages_size); | ||
54 | if (may_alloc && !bitmap) | ||
55 | bitmap = pcpu_mem_zalloc(bitmap_size); | ||
56 | if (!pages || !bitmap) | ||
57 | return NULL; | ||
58 | } | ||
59 | 37 | ||
60 | bitmap_copy(bitmap, chunk->populated, pcpu_unit_pages); | 38 | lockdep_assert_held(&pcpu_alloc_mutex); |
61 | 39 | ||
62 | *bitmapp = bitmap; | 40 | if (!pages) |
41 | pages = pcpu_mem_zalloc(pages_size); | ||
63 | return pages; | 42 | return pages; |
64 | } | 43 | } |
65 | 44 | ||
@@ -67,7 +46,6 @@ static struct page **pcpu_get_pages_and_bitmap(struct pcpu_chunk *chunk, | |||
67 | * pcpu_free_pages - free pages which were allocated for @chunk | 46 | * pcpu_free_pages - free pages which were allocated for @chunk |
68 | * @chunk: chunk pages were allocated for | 47 | * @chunk: chunk pages were allocated for |
69 | * @pages: array of pages to be freed, indexed by pcpu_page_idx() | 48 | * @pages: array of pages to be freed, indexed by pcpu_page_idx() |
70 | * @populated: populated bitmap | ||
71 | * @page_start: page index of the first page to be freed | 49 | * @page_start: page index of the first page to be freed |
72 | * @page_end: page index of the last page to be freed + 1 | 50 | * @page_end: page index of the last page to be freed + 1 |
73 | * | 51 | * |
@@ -75,8 +53,7 @@ static struct page **pcpu_get_pages_and_bitmap(struct pcpu_chunk *chunk, | |||
75 | * The pages were allocated for @chunk. | 53 | * The pages were allocated for @chunk. |
76 | */ | 54 | */ |
77 | static void pcpu_free_pages(struct pcpu_chunk *chunk, | 55 | static void pcpu_free_pages(struct pcpu_chunk *chunk, |
78 | struct page **pages, unsigned long *populated, | 56 | struct page **pages, int page_start, int page_end) |
79 | int page_start, int page_end) | ||
80 | { | 57 | { |
81 | unsigned int cpu; | 58 | unsigned int cpu; |
82 | int i; | 59 | int i; |
@@ -95,7 +72,6 @@ static void pcpu_free_pages(struct pcpu_chunk *chunk, | |||
95 | * pcpu_alloc_pages - allocates pages for @chunk | 72 | * pcpu_alloc_pages - allocates pages for @chunk |
96 | * @chunk: target chunk | 73 | * @chunk: target chunk |
97 | * @pages: array to put the allocated pages into, indexed by pcpu_page_idx() | 74 | * @pages: array to put the allocated pages into, indexed by pcpu_page_idx() |
98 | * @populated: populated bitmap | ||
99 | * @page_start: page index of the first page to be allocated | 75 | * @page_start: page index of the first page to be allocated |
100 | * @page_end: page index of the last page to be allocated + 1 | 76 | * @page_end: page index of the last page to be allocated + 1 |
101 | * | 77 | * |
@@ -104,8 +80,7 @@ static void pcpu_free_pages(struct pcpu_chunk *chunk, | |||
104 | * content of @pages and will pass it verbatim to pcpu_map_pages(). | 80 | * content of @pages and will pass it verbatim to pcpu_map_pages(). |
105 | */ | 81 | */ |
106 | static int pcpu_alloc_pages(struct pcpu_chunk *chunk, | 82 | static int pcpu_alloc_pages(struct pcpu_chunk *chunk, |
107 | struct page **pages, unsigned long *populated, | 83 | struct page **pages, int page_start, int page_end) |
108 | int page_start, int page_end) | ||
109 | { | 84 | { |
110 | const gfp_t gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD; | 85 | const gfp_t gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_COLD; |
111 | unsigned int cpu, tcpu; | 86 | unsigned int cpu, tcpu; |
@@ -164,7 +139,6 @@ static void __pcpu_unmap_pages(unsigned long addr, int nr_pages) | |||
164 | * pcpu_unmap_pages - unmap pages out of a pcpu_chunk | 139 | * pcpu_unmap_pages - unmap pages out of a pcpu_chunk |
165 | * @chunk: chunk of interest | 140 | * @chunk: chunk of interest |
166 | * @pages: pages array which can be used to pass information to free | 141 | * @pages: pages array which can be used to pass information to free |
167 | * @populated: populated bitmap | ||
168 | * @page_start: page index of the first page to unmap | 142 | * @page_start: page index of the first page to unmap |
169 | * @page_end: page index of the last page to unmap + 1 | 143 | * @page_end: page index of the last page to unmap + 1 |
170 | * | 144 | * |
@@ -175,8 +149,7 @@ static void __pcpu_unmap_pages(unsigned long addr, int nr_pages) | |||
175 | * proper pre/post flush functions. | 149 | * proper pre/post flush functions. |
176 | */ | 150 | */ |
177 | static void pcpu_unmap_pages(struct pcpu_chunk *chunk, | 151 | static void pcpu_unmap_pages(struct pcpu_chunk *chunk, |
178 | struct page **pages, unsigned long *populated, | 152 | struct page **pages, int page_start, int page_end) |
179 | int page_start, int page_end) | ||
180 | { | 153 | { |
181 | unsigned int cpu; | 154 | unsigned int cpu; |
182 | int i; | 155 | int i; |
@@ -192,8 +165,6 @@ static void pcpu_unmap_pages(struct pcpu_chunk *chunk, | |||
192 | __pcpu_unmap_pages(pcpu_chunk_addr(chunk, cpu, page_start), | 165 | __pcpu_unmap_pages(pcpu_chunk_addr(chunk, cpu, page_start), |
193 | page_end - page_start); | 166 | page_end - page_start); |
194 | } | 167 | } |
195 | |||
196 | bitmap_clear(populated, page_start, page_end - page_start); | ||
197 | } | 168 | } |
198 | 169 | ||
199 | /** | 170 | /** |
@@ -228,7 +199,6 @@ static int __pcpu_map_pages(unsigned long addr, struct page **pages, | |||
228 | * pcpu_map_pages - map pages into a pcpu_chunk | 199 | * pcpu_map_pages - map pages into a pcpu_chunk |
229 | * @chunk: chunk of interest | 200 | * @chunk: chunk of interest |
230 | * @pages: pages array containing pages to be mapped | 201 | * @pages: pages array containing pages to be mapped |
231 | * @populated: populated bitmap | ||
232 | * @page_start: page index of the first page to map | 202 | * @page_start: page index of the first page to map |
233 | * @page_end: page index of the last page to map + 1 | 203 | * @page_end: page index of the last page to map + 1 |
234 | * | 204 | * |
@@ -236,13 +206,11 @@ static int __pcpu_map_pages(unsigned long addr, struct page **pages, | |||
236 | * caller is responsible for calling pcpu_post_map_flush() after all | 206 | * caller is responsible for calling pcpu_post_map_flush() after all |
237 | * mappings are complete. | 207 | * mappings are complete. |
238 | * | 208 | * |
239 | * This function is responsible for setting corresponding bits in | 209 | * This function is responsible for setting up whatever is necessary for |
240 | * @chunk->populated bitmap and whatever is necessary for reverse | 210 | * reverse lookup (addr -> chunk). |
241 | * lookup (addr -> chunk). | ||
242 | */ | 211 | */ |
243 | static int pcpu_map_pages(struct pcpu_chunk *chunk, | 212 | static int pcpu_map_pages(struct pcpu_chunk *chunk, |
244 | struct page **pages, unsigned long *populated, | 213 | struct page **pages, int page_start, int page_end) |
245 | int page_start, int page_end) | ||
246 | { | 214 | { |
247 | unsigned int cpu, tcpu; | 215 | unsigned int cpu, tcpu; |
248 | int i, err; | 216 | int i, err; |
@@ -253,18 +221,12 @@ static int pcpu_map_pages(struct pcpu_chunk *chunk, | |||
253 | page_end - page_start); | 221 | page_end - page_start); |
254 | if (err < 0) | 222 | if (err < 0) |
255 | goto err; | 223 | goto err; |
256 | } | ||
257 | 224 | ||
258 | /* mapping successful, link chunk and mark populated */ | 225 | for (i = page_start; i < page_end; i++) |
259 | for (i = page_start; i < page_end; i++) { | ||
260 | for_each_possible_cpu(cpu) | ||
261 | pcpu_set_page_chunk(pages[pcpu_page_idx(cpu, i)], | 226 | pcpu_set_page_chunk(pages[pcpu_page_idx(cpu, i)], |
262 | chunk); | 227 | chunk); |
263 | __set_bit(i, populated); | ||
264 | } | 228 | } |
265 | |||
266 | return 0; | 229 | return 0; |
267 | |||
268 | err: | 230 | err: |
269 | for_each_possible_cpu(tcpu) { | 231 | for_each_possible_cpu(tcpu) { |
270 | if (tcpu == cpu) | 232 | if (tcpu == cpu) |
@@ -299,123 +261,69 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk, | |||
299 | /** | 261 | /** |
300 | * pcpu_populate_chunk - populate and map an area of a pcpu_chunk | 262 | * pcpu_populate_chunk - populate and map an area of a pcpu_chunk |
301 | * @chunk: chunk of interest | 263 | * @chunk: chunk of interest |
302 | * @off: offset to the area to populate | 264 | * @page_start: the start page |
303 | * @size: size of the area to populate in bytes | 265 | * @page_end: the end page |
304 | * | 266 | * |
305 | * For each cpu, populate and map pages [@page_start,@page_end) into | 267 | * For each cpu, populate and map pages [@page_start,@page_end) into |
306 | * @chunk. The area is cleared on return. | 268 | * @chunk. |
307 | * | 269 | * |
308 | * CONTEXT: | 270 | * CONTEXT: |
309 | * pcpu_alloc_mutex, does GFP_KERNEL allocation. | 271 | * pcpu_alloc_mutex, does GFP_KERNEL allocation. |
310 | */ | 272 | */ |
311 | static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size) | 273 | static int pcpu_populate_chunk(struct pcpu_chunk *chunk, |
274 | int page_start, int page_end) | ||
312 | { | 275 | { |
313 | int page_start = PFN_DOWN(off); | ||
314 | int page_end = PFN_UP(off + size); | ||
315 | int free_end = page_start, unmap_end = page_start; | ||
316 | struct page **pages; | 276 | struct page **pages; |
317 | unsigned long *populated; | ||
318 | unsigned int cpu; | ||
319 | int rs, re, rc; | ||
320 | |||
321 | /* quick path, check whether all pages are already there */ | ||
322 | rs = page_start; | ||
323 | pcpu_next_pop(chunk, &rs, &re, page_end); | ||
324 | if (rs == page_start && re == page_end) | ||
325 | goto clear; | ||
326 | 277 | ||
327 | /* need to allocate and map pages, this chunk can't be immutable */ | 278 | pages = pcpu_get_pages(chunk); |
328 | WARN_ON(chunk->immutable); | ||
329 | |||
330 | pages = pcpu_get_pages_and_bitmap(chunk, &populated, true); | ||
331 | if (!pages) | 279 | if (!pages) |
332 | return -ENOMEM; | 280 | return -ENOMEM; |
333 | 281 | ||
334 | /* alloc and map */ | 282 | if (pcpu_alloc_pages(chunk, pages, page_start, page_end)) |
335 | pcpu_for_each_unpop_region(chunk, rs, re, page_start, page_end) { | 283 | return -ENOMEM; |
336 | rc = pcpu_alloc_pages(chunk, pages, populated, rs, re); | ||
337 | if (rc) | ||
338 | goto err_free; | ||
339 | free_end = re; | ||
340 | } | ||
341 | 284 | ||
342 | pcpu_for_each_unpop_region(chunk, rs, re, page_start, page_end) { | 285 | if (pcpu_map_pages(chunk, pages, page_start, page_end)) { |
343 | rc = pcpu_map_pages(chunk, pages, populated, rs, re); | 286 | pcpu_free_pages(chunk, pages, page_start, page_end); |
344 | if (rc) | 287 | return -ENOMEM; |
345 | goto err_unmap; | ||
346 | unmap_end = re; | ||
347 | } | 288 | } |
348 | pcpu_post_map_flush(chunk, page_start, page_end); | 289 | pcpu_post_map_flush(chunk, page_start, page_end); |
349 | 290 | ||
350 | /* commit new bitmap */ | ||
351 | bitmap_copy(chunk->populated, populated, pcpu_unit_pages); | ||
352 | clear: | ||
353 | for_each_possible_cpu(cpu) | ||
354 | memset((void *)pcpu_chunk_addr(chunk, cpu, 0) + off, 0, size); | ||
355 | return 0; | 291 | return 0; |
356 | |||
357 | err_unmap: | ||
358 | pcpu_pre_unmap_flush(chunk, page_start, unmap_end); | ||
359 | pcpu_for_each_unpop_region(chunk, rs, re, page_start, unmap_end) | ||
360 | pcpu_unmap_pages(chunk, pages, populated, rs, re); | ||
361 | pcpu_post_unmap_tlb_flush(chunk, page_start, unmap_end); | ||
362 | err_free: | ||
363 | pcpu_for_each_unpop_region(chunk, rs, re, page_start, free_end) | ||
364 | pcpu_free_pages(chunk, pages, populated, rs, re); | ||
365 | return rc; | ||
366 | } | 292 | } |
367 | 293 | ||
368 | /** | 294 | /** |
369 | * pcpu_depopulate_chunk - depopulate and unmap an area of a pcpu_chunk | 295 | * pcpu_depopulate_chunk - depopulate and unmap an area of a pcpu_chunk |
370 | * @chunk: chunk to depopulate | 296 | * @chunk: chunk to depopulate |
371 | * @off: offset to the area to depopulate | 297 | * @page_start: the start page |
372 | * @size: size of the area to depopulate in bytes | 298 | * @page_end: the end page |
373 | * | 299 | * |
374 | * For each cpu, depopulate and unmap pages [@page_start,@page_end) | 300 | * For each cpu, depopulate and unmap pages [@page_start,@page_end) |
375 | * from @chunk. If @flush is true, vcache is flushed before unmapping | 301 | * from @chunk. |
376 | * and tlb after. | ||
377 | * | 302 | * |
378 | * CONTEXT: | 303 | * CONTEXT: |
379 | * pcpu_alloc_mutex. | 304 | * pcpu_alloc_mutex. |
380 | */ | 305 | */ |
381 | static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size) | 306 | static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, |
307 | int page_start, int page_end) | ||
382 | { | 308 | { |
383 | int page_start = PFN_DOWN(off); | ||
384 | int page_end = PFN_UP(off + size); | ||
385 | struct page **pages; | 309 | struct page **pages; |
386 | unsigned long *populated; | ||
387 | int rs, re; | ||
388 | |||
389 | /* quick path, check whether it's empty already */ | ||
390 | rs = page_start; | ||
391 | pcpu_next_unpop(chunk, &rs, &re, page_end); | ||
392 | if (rs == page_start && re == page_end) | ||
393 | return; | ||
394 | |||
395 | /* immutable chunks can't be depopulated */ | ||
396 | WARN_ON(chunk->immutable); | ||
397 | 310 | ||
398 | /* | 311 | /* |
399 | * If control reaches here, there must have been at least one | 312 | * If control reaches here, there must have been at least one |
400 | * successful population attempt so the temp pages array must | 313 | * successful population attempt so the temp pages array must |
401 | * be available now. | 314 | * be available now. |
402 | */ | 315 | */ |
403 | pages = pcpu_get_pages_and_bitmap(chunk, &populated, false); | 316 | pages = pcpu_get_pages(chunk); |
404 | BUG_ON(!pages); | 317 | BUG_ON(!pages); |
405 | 318 | ||
406 | /* unmap and free */ | 319 | /* unmap and free */ |
407 | pcpu_pre_unmap_flush(chunk, page_start, page_end); | 320 | pcpu_pre_unmap_flush(chunk, page_start, page_end); |
408 | 321 | ||
409 | pcpu_for_each_pop_region(chunk, rs, re, page_start, page_end) | 322 | pcpu_unmap_pages(chunk, pages, page_start, page_end); |
410 | pcpu_unmap_pages(chunk, pages, populated, rs, re); | ||
411 | 323 | ||
412 | /* no need to flush tlb, vmalloc will handle it lazily */ | 324 | /* no need to flush tlb, vmalloc will handle it lazily */ |
413 | 325 | ||
414 | pcpu_for_each_pop_region(chunk, rs, re, page_start, page_end) | 326 | pcpu_free_pages(chunk, pages, page_start, page_end); |
415 | pcpu_free_pages(chunk, pages, populated, rs, re); | ||
416 | |||
417 | /* commit new bitmap */ | ||
418 | bitmap_copy(chunk->populated, populated, pcpu_unit_pages); | ||
419 | } | 327 | } |
420 | 328 | ||
421 | static struct pcpu_chunk *pcpu_create_chunk(void) | 329 | static struct pcpu_chunk *pcpu_create_chunk(void) |