aboutsummaryrefslogtreecommitdiffstats
path: root/mm/percpu-vm.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-11-18 13:55:35 -0500
committerTejun Heo <tj@kernel.org>2011-11-22 11:09:46 -0500
commita855b84c3d8c73220d4d3cd392a7bee7c83de70e (patch)
tree3134cd884a2c625cf72172c9cb4e4a5e68d749f2 /mm/percpu-vm.c
parent90459ce06f410b983540be56209c0abcbce23944 (diff)
percpu: fix chunk range calculation
Percpu allocator recorded the cpus which map to the first and last units in pcpu_first/last_unit_cpu respectively and used them to determine the address range of a chunk - e.g. it assumed that the first unit has the lowest address in a chunk while the last unit has the highest address. This simply isn't true. Groups in a chunk can have arbitrary positive or negative offsets from the previous one and there is no guarantee that the first unit occupies the lowest offset while the last one the highest. Fix it by actually comparing unit offsets to determine cpus occupying the lowest and highest offsets. Also, rename pcu_first/last_unit_cpu to pcpu_low/high_unit_cpu to avoid confusion. The chunk address range is used to flush cache on vmalloc area map/unmap and decide whether a given address is in the first chunk by per_cpu_ptr_to_phys() and the bug was discovered by invalid per_cpu_ptr_to_phys() translation for crash_note. Kudos to Dave Young for tracking down the problem. Signed-off-by: Tejun Heo <tj@kernel.org> Reported-by: WANG Cong <xiyou.wangcong@gmail.com> Reported-by: Dave Young <dyoung@redhat.com> Tested-by: Dave Young <dyoung@redhat.com> LKML-Reference: <4EC21F67.10905@redhat.com> Cc: stable @kernel.org
Diffstat (limited to 'mm/percpu-vm.c')
-rw-r--r--mm/percpu-vm.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c
index 29e3730d2ffd..12a48a88c0d8 100644
--- a/mm/percpu-vm.c
+++ b/mm/percpu-vm.c
@@ -142,8 +142,8 @@ static void pcpu_pre_unmap_flush(struct pcpu_chunk *chunk,
142 int page_start, int page_end) 142 int page_start, int page_end)
143{ 143{
144 flush_cache_vunmap( 144 flush_cache_vunmap(
145 pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start), 145 pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start),
146 pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end)); 146 pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
147} 147}
148 148
149static void __pcpu_unmap_pages(unsigned long addr, int nr_pages) 149static void __pcpu_unmap_pages(unsigned long addr, int nr_pages)
@@ -205,8 +205,8 @@ static void pcpu_post_unmap_tlb_flush(struct pcpu_chunk *chunk,
205 int page_start, int page_end) 205 int page_start, int page_end)
206{ 206{
207 flush_tlb_kernel_range( 207 flush_tlb_kernel_range(
208 pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start), 208 pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start),
209 pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end)); 209 pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
210} 210}
211 211
212static int __pcpu_map_pages(unsigned long addr, struct page **pages, 212static int __pcpu_map_pages(unsigned long addr, struct page **pages,
@@ -283,8 +283,8 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk,
283 int page_start, int page_end) 283 int page_start, int page_end)
284{ 284{
285 flush_cache_vmap( 285 flush_cache_vmap(
286 pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start), 286 pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start),
287 pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end)); 287 pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end));
288} 288}
289 289
290/** 290/**