diff options
Diffstat (limited to 'mm/percpu.c')
-rw-r--r-- | mm/percpu.c | 50 |
1 files changed, 33 insertions, 17 deletions
diff --git a/mm/percpu.c b/mm/percpu.c index b70f2acd8853..3311c8919f37 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
@@ -8,12 +8,12 @@ | |||
8 | * | 8 | * |
9 | * This is percpu allocator which can handle both static and dynamic | 9 | * This is percpu allocator which can handle both static and dynamic |
10 | * areas. Percpu areas are allocated in chunks in vmalloc area. Each | 10 | * areas. Percpu areas are allocated in chunks in vmalloc area. Each |
11 | * chunk is consisted of num_possible_cpus() units and the first chunk | 11 | * chunk is consisted of nr_cpu_ids units and the first chunk is used |
12 | * is used for static percpu variables in the kernel image (special | 12 | * for static percpu variables in the kernel image (special boot time |
13 | * boot time alloc/init handling necessary as these areas need to be | 13 | * alloc/init handling necessary as these areas need to be brought up |
14 | * brought up before allocation services are running). Unit grows as | 14 | * before allocation services are running). Unit grows as necessary |
15 | * necessary and all units grow or shrink in unison. When a chunk is | 15 | * and all units grow or shrink in unison. When a chunk is filled up, |
16 | * filled up, another chunk is allocated. ie. in vmalloc area | 16 | * another chunk is allocated. ie. in vmalloc area |
17 | * | 17 | * |
18 | * c0 c1 c2 | 18 | * c0 c1 c2 |
19 | * ------------------- ------------------- ------------ | 19 | * ------------------- ------------------- ------------ |
@@ -197,7 +197,12 @@ static unsigned long pcpu_chunk_addr(struct pcpu_chunk *chunk, | |||
197 | static bool pcpu_chunk_page_occupied(struct pcpu_chunk *chunk, | 197 | static bool pcpu_chunk_page_occupied(struct pcpu_chunk *chunk, |
198 | int page_idx) | 198 | int page_idx) |
199 | { | 199 | { |
200 | return *pcpu_chunk_pagep(chunk, 0, page_idx) != NULL; | 200 | /* |
201 | * Any possible cpu id can be used here, so there's no need to | ||
202 | * worry about preemption or cpu hotplug. | ||
203 | */ | ||
204 | return *pcpu_chunk_pagep(chunk, raw_smp_processor_id(), | ||
205 | page_idx) != NULL; | ||
201 | } | 206 | } |
202 | 207 | ||
203 | /* set the pointer to a chunk in a page struct */ | 208 | /* set the pointer to a chunk in a page struct */ |
@@ -297,6 +302,14 @@ static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr) | |||
297 | return pcpu_first_chunk; | 302 | return pcpu_first_chunk; |
298 | } | 303 | } |
299 | 304 | ||
305 | /* | ||
306 | * The address is relative to unit0 which might be unused and | ||
307 | * thus unmapped. Offset the address to the unit space of the | ||
308 | * current processor before looking it up in the vmalloc | ||
309 | * space. Note that any possible cpu id can be used here, so | ||
310 | * there's no need to worry about preemption or cpu hotplug. | ||
311 | */ | ||
312 | addr += raw_smp_processor_id() * pcpu_unit_size; | ||
300 | return pcpu_get_page_chunk(vmalloc_to_page(addr)); | 313 | return pcpu_get_page_chunk(vmalloc_to_page(addr)); |
301 | } | 314 | } |
302 | 315 | ||
@@ -558,7 +571,7 @@ static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme) | |||
558 | static void pcpu_unmap(struct pcpu_chunk *chunk, int page_start, int page_end, | 571 | static void pcpu_unmap(struct pcpu_chunk *chunk, int page_start, int page_end, |
559 | bool flush_tlb) | 572 | bool flush_tlb) |
560 | { | 573 | { |
561 | unsigned int last = num_possible_cpus() - 1; | 574 | unsigned int last = nr_cpu_ids - 1; |
562 | unsigned int cpu; | 575 | unsigned int cpu; |
563 | 576 | ||
564 | /* unmap must not be done on immutable chunk */ | 577 | /* unmap must not be done on immutable chunk */ |
@@ -643,7 +656,7 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size, | |||
643 | */ | 656 | */ |
644 | static int pcpu_map(struct pcpu_chunk *chunk, int page_start, int page_end) | 657 | static int pcpu_map(struct pcpu_chunk *chunk, int page_start, int page_end) |
645 | { | 658 | { |
646 | unsigned int last = num_possible_cpus() - 1; | 659 | unsigned int last = nr_cpu_ids - 1; |
647 | unsigned int cpu; | 660 | unsigned int cpu; |
648 | int err; | 661 | int err; |
649 | 662 | ||
@@ -749,7 +762,7 @@ static struct pcpu_chunk *alloc_pcpu_chunk(void) | |||
749 | chunk->map[chunk->map_used++] = pcpu_unit_size; | 762 | chunk->map[chunk->map_used++] = pcpu_unit_size; |
750 | chunk->page = chunk->page_ar; | 763 | chunk->page = chunk->page_ar; |
751 | 764 | ||
752 | chunk->vm = get_vm_area(pcpu_chunk_size, GFP_KERNEL); | 765 | chunk->vm = get_vm_area(pcpu_chunk_size, VM_ALLOC); |
753 | if (!chunk->vm) { | 766 | if (!chunk->vm) { |
754 | free_pcpu_chunk(chunk); | 767 | free_pcpu_chunk(chunk); |
755 | return NULL; | 768 | return NULL; |
@@ -1067,9 +1080,9 @@ size_t __init pcpu_setup_first_chunk(pcpu_get_page_fn_t get_page_fn, | |||
1067 | PFN_UP(size_sum)); | 1080 | PFN_UP(size_sum)); |
1068 | 1081 | ||
1069 | pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT; | 1082 | pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT; |
1070 | pcpu_chunk_size = num_possible_cpus() * pcpu_unit_size; | 1083 | pcpu_chunk_size = nr_cpu_ids * pcpu_unit_size; |
1071 | pcpu_chunk_struct_size = sizeof(struct pcpu_chunk) | 1084 | pcpu_chunk_struct_size = sizeof(struct pcpu_chunk) |
1072 | + num_possible_cpus() * pcpu_unit_pages * sizeof(struct page *); | 1085 | + nr_cpu_ids * pcpu_unit_pages * sizeof(struct page *); |
1073 | 1086 | ||
1074 | if (dyn_size < 0) | 1087 | if (dyn_size < 0) |
1075 | dyn_size = pcpu_unit_size - static_size - reserved_size; | 1088 | dyn_size = pcpu_unit_size - static_size - reserved_size; |
@@ -1248,7 +1261,7 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size, | |||
1248 | } else | 1261 | } else |
1249 | pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE); | 1262 | pcpue_unit_size = max_t(size_t, pcpue_size, PCPU_MIN_UNIT_SIZE); |
1250 | 1263 | ||
1251 | chunk_size = pcpue_unit_size * num_possible_cpus(); | 1264 | chunk_size = pcpue_unit_size * nr_cpu_ids; |
1252 | 1265 | ||
1253 | pcpue_ptr = __alloc_bootmem_nopanic(chunk_size, PAGE_SIZE, | 1266 | pcpue_ptr = __alloc_bootmem_nopanic(chunk_size, PAGE_SIZE, |
1254 | __pa(MAX_DMA_ADDRESS)); | 1267 | __pa(MAX_DMA_ADDRESS)); |
@@ -1259,12 +1272,15 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size, | |||
1259 | } | 1272 | } |
1260 | 1273 | ||
1261 | /* return the leftover and copy */ | 1274 | /* return the leftover and copy */ |
1262 | for_each_possible_cpu(cpu) { | 1275 | for (cpu = 0; cpu < nr_cpu_ids; cpu++) { |
1263 | void *ptr = pcpue_ptr + cpu * pcpue_unit_size; | 1276 | void *ptr = pcpue_ptr + cpu * pcpue_unit_size; |
1264 | 1277 | ||
1265 | free_bootmem(__pa(ptr + pcpue_size), | 1278 | if (cpu_possible(cpu)) { |
1266 | pcpue_unit_size - pcpue_size); | 1279 | free_bootmem(__pa(ptr + pcpue_size), |
1267 | memcpy(ptr, __per_cpu_load, static_size); | 1280 | pcpue_unit_size - pcpue_size); |
1281 | memcpy(ptr, __per_cpu_load, static_size); | ||
1282 | } else | ||
1283 | free_bootmem(__pa(ptr), pcpue_unit_size); | ||
1268 | } | 1284 | } |
1269 | 1285 | ||
1270 | /* we're ready, commit */ | 1286 | /* we're ready, commit */ |