summaryrefslogtreecommitdiffstats
path: root/mm/percpu.c
diff options
context:
space:
mode:
authorzijun_hu <zijun_hu@htc.com>2016-10-05 09:19:11 -0400
committerTejun Heo <tj@kernel.org>2016-10-05 11:52:54 -0400
commit93c76b6b2faaad7bfbc0cda840763aa4819ef26e (patch)
treeaf612304a46abb22e4821e2ea373d9556b170564 /mm/percpu.c
parent799bc3c51b2b120ca6e59e702ede23fff2efaf43 (diff)
mm/percpu.c: correct max_distance calculation for pcpu_embed_first_chunk()
pcpu_embed_first_chunk() calculates the range a percpu chunk spans into @max_distance and uses it to ensure that a chunk is not too big compared to the total vmalloc area. However, during calculation, it used incorrect top address by adding a unit size to the highest group's base address. This can make the calculated max_distance slightly smaller than the actual distance although given the scale of values involved the error is very unlikely to have an actual impact. Fix this issue by adding the group's size instead of a unit size. BTW, The type of variable max_distance is changed from size_t to unsigned long too based on below consideration: - type unsigned long usually have same width with IP core registers and can be applied at here very well - make @max_distance type consistent with the operand calculated against it such as @ai->groups[i].base_offset and macro VMALLOC_TOTAL - type unsigned long is more universal then size_t, size_t is type defined to unsigned int or unsigned long among various ARCHs usually Signed-off-by: zijun_hu <zijun_hu@htc.com> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'mm/percpu.c')
-rw-r--r--mm/percpu.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/mm/percpu.c b/mm/percpu.c
index 9903830aaebb..e2737e56b017 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -1961,7 +1961,8 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
1961 void *base = (void *)ULONG_MAX; 1961 void *base = (void *)ULONG_MAX;
1962 void **areas = NULL; 1962 void **areas = NULL;
1963 struct pcpu_alloc_info *ai; 1963 struct pcpu_alloc_info *ai;
1964 size_t size_sum, areas_size, max_distance; 1964 size_t size_sum, areas_size;
1965 unsigned long max_distance;
1965 int group, i, rc; 1966 int group, i, rc;
1966 1967
1967 ai = pcpu_build_alloc_info(reserved_size, dyn_size, atom_size, 1968 ai = pcpu_build_alloc_info(reserved_size, dyn_size, atom_size,
@@ -2023,17 +2024,18 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size,
2023 } 2024 }
2024 2025
2025 /* base address is now known, determine group base offsets */ 2026 /* base address is now known, determine group base offsets */
2026 max_distance = 0; 2027 i = 0;
2027 for (group = 0; group < ai->nr_groups; group++) { 2028 for (group = 0; group < ai->nr_groups; group++) {
2028 ai->groups[group].base_offset = areas[group] - base; 2029 ai->groups[group].base_offset = areas[group] - base;
2029 max_distance = max_t(size_t, max_distance, 2030 if (areas[group] > areas[i])
2030 ai->groups[group].base_offset); 2031 i = group;
2031 } 2032 }
2032 max_distance += ai->unit_size; 2033 max_distance = ai->groups[i].base_offset +
2034 ai->unit_size * ai->groups[i].nr_units;
2033 2035
2034 /* warn if maximum distance is further than 75% of vmalloc space */ 2036 /* warn if maximum distance is further than 75% of vmalloc space */
2035 if (max_distance > VMALLOC_TOTAL * 3 / 4) { 2037 if (max_distance > VMALLOC_TOTAL * 3 / 4) {
2036 pr_warn("max_distance=0x%zx too large for vmalloc space 0x%lx\n", 2038 pr_warn("max_distance=0x%lx too large for vmalloc space 0x%lx\n",
2037 max_distance, VMALLOC_TOTAL); 2039 max_distance, VMALLOC_TOTAL);
2038#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK 2040#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK
2039 /* and fail if we have fallback */ 2041 /* and fail if we have fallback */