The percpu variables are allocated from vmalloc area by default. The architectures which support local percpu map will allocate percpu variables from dedicated percpu area, for example, ARM64. Introduce a new kernel config, CONFIG_HAVE_LOCAL_PER_CPU_MAP. The architectures which support local percpu map will need to select it. If it is enabled, allocate percpu variables from the dedicated percpu area. Signed-off-by: Yang Shi --- mm/Kconfig | 3 +++ mm/percpu.c | 6 ++++++ mm/vmalloc.c | 20 +++++++++++++++++--- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/mm/Kconfig b/mm/Kconfig index e8bf1e9e6ad9..ccdf58b63fb8 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -1022,6 +1022,9 @@ config NEED_PER_CPU_PAGE_FIRST_CHUNK config USE_PERCPU_NUMA_NODE_ID bool +config HAVE_LOCAL_PER_CPU_MAP + bool + config HAVE_SETUP_PER_CPU_AREA bool diff --git a/mm/percpu.c b/mm/percpu.c index b0676b8054ed..daa2c88e6971 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -3243,9 +3243,15 @@ int __init pcpu_page_first_chunk(size_t reserved_size, pcpu_fc_cpu_to_node_fn_t } /* allocate vm area, map the pages and copy static data */ +#ifdef CONFIG_HAVE_LOCAL_PER_CPU_MAP + vm.addr = (void *)ALIGN(PERCPU_START, PAGE_SIZE); + vm.size = num_possible_cpus() * ai->unit_size; + vm_area_add_early(&vm); +#else vm.flags = VM_ALLOC; vm.size = num_possible_cpus() * ai->unit_size; vm_area_register_early(&vm, PAGE_SIZE); +#endif for (unit = 0; unit < num_possible_cpus(); unit++) { unsigned long unit_addr = diff --git a/mm/vmalloc.c b/mm/vmalloc.c index aa08651ec0df..068a6709062d 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -4841,9 +4841,15 @@ pvm_find_va_enclose_addr(unsigned long addr) static unsigned long pvm_determine_end_from_reverse(struct vmap_area **va, unsigned long align) { - unsigned long vmalloc_end = VMALLOC_END & ~(align - 1); + unsigned long vmalloc_end; unsigned long addr; +#ifdef CONFIG_HAVE_LOCAL_PER_CPU_MAP + vmalloc_end = PERCPU_END & ~(align - 1); +#else + vmalloc_end = VMALLOC_END & ~(align - 1); +#endif + if (likely(*va)) { list_for_each_entry_from_reverse((*va), &free_vmap_area_list, list) { @@ -4884,14 +4890,22 @@ struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets, const size_t *sizes, int nr_vms, size_t align) { - const unsigned long vmalloc_start = ALIGN(VMALLOC_START, align); - const unsigned long vmalloc_end = VMALLOC_END & ~(align - 1); + unsigned long vmalloc_start; + unsigned long vmalloc_end; struct vmap_area **vas, *va; struct vm_struct **vms; int area, area2, last_area, term_area; unsigned long base, start, size, end, last_end, orig_start, orig_end; bool purged = false; +#ifdef CONFIG_HAVE_LOCAL_PER_CPU_MAP + vmalloc_start = ALIGN(PERCPU_START, align); + vmalloc_end = PERCPU_END & ~(align - 1); +#else + vmalloc_start = ALIGN(VMALLOC_START, align); + vmalloc_end = VMALLOC_END & ~(align - 1); +#endif + /* verify parameters and allocate data structures */ BUG_ON(offset_in_page(align) || !is_power_of_2(align)); for (last_area = 0, area = 0; area < nr_vms; area++) { -- 2.47.0