diff options
| author | Tejun Heo <tj@kernel.org> | 2014-09-02 14:46:01 -0400 |
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2014-09-02 14:46:01 -0400 |
| commit | dca496451bddea9aa87b7510dc2eb413d1a19dfd (patch) | |
| tree | c1d926663786fd919d3a9d19659ce80696d7558f /mm | |
| parent | cdb4cba5a3c9fa27240d04f4f8dad316b10d995b (diff) | |
percpu: move common parts out of pcpu_[de]populate_chunk()
percpu-vm and percpu-km implement separate versions of
pcpu_[de]populate_chunk() and some part which is or should be common
are currently in the specific implementations. Make the following
changes.
* Allocate area clearing is moved from the pcpu_populate_chunk()
implementations to pcpu_alloc(). This makes percpu-km's version
noop.
* Quick exit tests in pcpu_[de]populate_chunk() of percpu-vm are moved
to their respective callers so that they are applied to percpu-km
too. This doesn't make any meaningful difference as both functions
are noop for percpu-km; however, this is more consistent and will
help implementing atomic allocation support.
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'mm')
| -rw-r--r-- | mm/percpu-km.c | 5 | ||||
| -rw-r--r-- | mm/percpu-vm.c | 27 | ||||
| -rw-r--r-- | mm/percpu.c | 39 |
3 files changed, 31 insertions, 40 deletions
diff --git a/mm/percpu-km.c b/mm/percpu-km.c index 89633fefc6a2..9a9096f08867 100644 --- a/mm/percpu-km.c +++ b/mm/percpu-km.c | |||
| @@ -35,11 +35,6 @@ | |||
| 35 | 35 | ||
| 36 | static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size) | 36 | static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size) |
| 37 | { | 37 | { |
| 38 | unsigned int cpu; | ||
| 39 | |||
| 40 | for_each_possible_cpu(cpu) | ||
| 41 | memset((void *)pcpu_chunk_addr(chunk, cpu, 0) + off, 0, size); | ||
| 42 | |||
| 43 | return 0; | 38 | return 0; |
| 44 | } | 39 | } |
| 45 | 40 | ||
diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c index d9e0b615492e..edf709793318 100644 --- a/mm/percpu-vm.c +++ b/mm/percpu-vm.c | |||
| @@ -265,7 +265,7 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk, | |||
| 265 | * @size: size of the area to populate in bytes | 265 | * @size: size of the area to populate in bytes |
| 266 | * | 266 | * |
| 267 | * 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 |
| 268 | * @chunk. The area is cleared on return. | 268 | * @chunk. |
| 269 | * | 269 | * |
| 270 | * CONTEXT: | 270 | * CONTEXT: |
| 271 | * pcpu_alloc_mutex, does GFP_KERNEL allocation. | 271 | * pcpu_alloc_mutex, does GFP_KERNEL allocation. |
| @@ -276,18 +276,8 @@ static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size) | |||
| 276 | int page_end = PFN_UP(off + size); | 276 | int page_end = PFN_UP(off + size); |
| 277 | int free_end = page_start, unmap_end = page_start; | 277 | int free_end = page_start, unmap_end = page_start; |
| 278 | struct page **pages; | 278 | struct page **pages; |
| 279 | unsigned int cpu; | ||
| 280 | int rs, re, rc; | 279 | int rs, re, rc; |
| 281 | 280 | ||
| 282 | /* quick path, check whether all pages are already there */ | ||
| 283 | rs = page_start; | ||
| 284 | pcpu_next_pop(chunk, &rs, &re, page_end); | ||
| 285 | if (rs == page_start && re == page_end) | ||
| 286 | goto clear; | ||
| 287 | |||
| 288 | /* need to allocate and map pages, this chunk can't be immutable */ | ||
| 289 | WARN_ON(chunk->immutable); | ||
| 290 | |||
| 291 | pages = pcpu_get_pages(chunk); | 281 | pages = pcpu_get_pages(chunk); |
| 292 | if (!pages) | 282 | if (!pages) |
| 293 | return -ENOMEM; | 283 | return -ENOMEM; |
| @@ -308,10 +298,6 @@ static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size) | |||
| 308 | } | 298 | } |
| 309 | pcpu_post_map_flush(chunk, page_start, page_end); | 299 | pcpu_post_map_flush(chunk, page_start, page_end); |
| 310 | 300 | ||
| 311 | bitmap_set(chunk->populated, page_start, page_end - page_start); | ||
| 312 | clear: | ||
| 313 | for_each_possible_cpu(cpu) | ||
| 314 | memset((void *)pcpu_chunk_addr(chunk, cpu, 0) + off, 0, size); | ||
| 315 | return 0; | 301 | return 0; |
| 316 | 302 | ||
| 317 | err_unmap: | 303 | err_unmap: |
| @@ -345,15 +331,6 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size) | |||
| 345 | struct page **pages; | 331 | struct page **pages; |
| 346 | int rs, re; | 332 | int rs, re; |
| 347 | 333 | ||
| 348 | /* quick path, check whether it's empty already */ | ||
| 349 | rs = page_start; | ||
| 350 | pcpu_next_unpop(chunk, &rs, &re, page_end); | ||
| 351 | if (rs == page_start && re == page_end) | ||
| 352 | return; | ||
| 353 | |||
| 354 | /* immutable chunks can't be depopulated */ | ||
| 355 | WARN_ON(chunk->immutable); | ||
| 356 | |||
| 357 | /* | 334 | /* |
| 358 | * If control reaches here, there must have been at least one | 335 | * If control reaches here, there must have been at least one |
| 359 | * successful population attempt so the temp pages array must | 336 | * successful population attempt so the temp pages array must |
| @@ -372,8 +349,6 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size) | |||
| 372 | 349 | ||
| 373 | pcpu_for_each_pop_region(chunk, rs, re, page_start, page_end) | 350 | pcpu_for_each_pop_region(chunk, rs, re, page_start, page_end) |
| 374 | pcpu_free_pages(chunk, pages, rs, re); | 351 | pcpu_free_pages(chunk, pages, rs, re); |
| 375 | |||
| 376 | bitmap_clear(chunk->populated, page_start, page_end - page_start); | ||
| 377 | } | 352 | } |
| 378 | 353 | ||
| 379 | static struct pcpu_chunk *pcpu_create_chunk(void) | 354 | static struct pcpu_chunk *pcpu_create_chunk(void) |
diff --git a/mm/percpu.c b/mm/percpu.c index da997f9800bd..6087384f6ef0 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
| @@ -709,7 +709,8 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved) | |||
| 709 | static int warn_limit = 10; | 709 | static int warn_limit = 10; |
| 710 | struct pcpu_chunk *chunk; | 710 | struct pcpu_chunk *chunk; |
| 711 | const char *err; | 711 | const char *err; |
| 712 | int slot, off, new_alloc; | 712 | int slot, off, new_alloc, cpu; |
| 713 | int page_start, page_end, rs, re; | ||
| 713 | unsigned long flags; | 714 | unsigned long flags; |
| 714 | void __percpu *ptr; | 715 | void __percpu *ptr; |
| 715 | 716 | ||
| @@ -802,17 +803,32 @@ restart: | |||
| 802 | area_found: | 803 | area_found: |
| 803 | spin_unlock_irqrestore(&pcpu_lock, flags); | 804 | spin_unlock_irqrestore(&pcpu_lock, flags); |
| 804 | 805 | ||
| 805 | /* populate, map and clear the area */ | 806 | /* populate if not all pages are already there */ |
| 806 | if (pcpu_populate_chunk(chunk, off, size)) { | 807 | page_start = PFN_DOWN(off); |
| 807 | spin_lock_irqsave(&pcpu_lock, flags); | 808 | page_end = PFN_UP(off + size); |
| 808 | pcpu_free_area(chunk, off); | 809 | |
| 809 | err = "failed to populate"; | 810 | rs = page_start; |
| 810 | goto fail_unlock; | 811 | pcpu_next_pop(chunk, &rs, &re, page_end); |
| 812 | |||
| 813 | if (rs != page_start || re != page_end) { | ||
| 814 | WARN_ON(chunk->immutable); | ||
| 815 | |||
| 816 | if (pcpu_populate_chunk(chunk, off, size)) { | ||
| 817 | spin_lock_irqsave(&pcpu_lock, flags); | ||
| 818 | pcpu_free_area(chunk, off); | ||
| 819 | err = "failed to populate"; | ||
| 820 | goto fail_unlock; | ||
| 821 | } | ||
| 822 | |||
| 823 | bitmap_set(chunk->populated, page_start, page_end - page_start); | ||
| 811 | } | 824 | } |
| 812 | 825 | ||
| 813 | mutex_unlock(&pcpu_alloc_mutex); | 826 | mutex_unlock(&pcpu_alloc_mutex); |
| 814 | 827 | ||
| 815 | /* return address relative to base address */ | 828 | /* clear the areas and return address relative to base address */ |
| 829 | for_each_possible_cpu(cpu) | ||
| 830 | memset((void *)pcpu_chunk_addr(chunk, cpu, 0) + off, 0, size); | ||
| 831 | |||
| 816 | ptr = __addr_to_pcpu_ptr(chunk->base_addr + off); | 832 | ptr = __addr_to_pcpu_ptr(chunk->base_addr + off); |
| 817 | kmemleak_alloc_percpu(ptr, size); | 833 | kmemleak_alloc_percpu(ptr, size); |
| 818 | return ptr; | 834 | return ptr; |
| @@ -903,7 +919,12 @@ static void pcpu_reclaim(struct work_struct *work) | |||
| 903 | spin_unlock_irq(&pcpu_lock); | 919 | spin_unlock_irq(&pcpu_lock); |
| 904 | 920 | ||
| 905 | list_for_each_entry_safe(chunk, next, &todo, list) { | 921 | list_for_each_entry_safe(chunk, next, &todo, list) { |
| 906 | pcpu_depopulate_chunk(chunk, 0, pcpu_unit_size); | 922 | int rs = 0, re; |
| 923 | |||
| 924 | pcpu_next_unpop(chunk, &rs, &re, PFN_UP(pcpu_unit_size)); | ||
| 925 | if (rs || re != PFN_UP(pcpu_unit_size)) | ||
| 926 | pcpu_depopulate_chunk(chunk, 0, pcpu_unit_size); | ||
| 927 | |||
| 907 | pcpu_destroy_chunk(chunk); | 928 | pcpu_destroy_chunk(chunk); |
| 908 | } | 929 | } |
| 909 | 930 | ||
