From: Pasha Tatashin get_vm_area_node() Unlike the other public get_vm_area_* variants, this one accepts node from which to allocate data structure, and also the align, which allows to create vm area with a specific alignment. This call is going to be used by dynamic stacks in order to ensure that the stack VM area of a specific alignment, and that even if there is only one page mapped, no page table allocations are going to be needed to map the other stack pages. vmap_pages_range() We will need it from kernel/fork.c in order to map the initial stack pages, so export the function and add a forward declaration of this function to the linux/vmalloc.h header. Signed-off-by: Pasha Tatashin Signed-off-by: Linus Walleij [Switched to vmap_pages_range instead of noflush variant, fix typos] Signed-off-by: David Stevens --- include/linux/vmalloc.h | 14 ++++++++++++++ mm/vmalloc.c | 25 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index e8e94f90d686..7b56a0b998ab 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -250,6 +250,9 @@ extern struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags, unsigned long start, unsigned long end, const void *caller); +struct vm_struct *get_vm_area_node(unsigned long size, unsigned long align, + unsigned long flags, int node, gfp_t gfp, + const void *caller); void free_vm_area(struct vm_struct *area); extern struct vm_struct *remove_vm_area(const void *addr); extern struct vm_struct *find_vm_area(const void *addr); @@ -301,11 +304,22 @@ static inline void set_vm_flush_reset_perms(void *addr) if (vm) vm->flags |= VM_FLUSH_RESET_PERMS; } + +int __must_check vmap_pages_range(unsigned long addr, unsigned long end, + pgprot_t prot, struct page **pages, unsigned int page_shift); + #else /* !CONFIG_MMU */ #define VMALLOC_TOTAL 0UL static inline unsigned long vmalloc_nr_pages(void) { return 0; } static inline void set_vm_flush_reset_perms(void *addr) {} +static inline +int __must_check vmap_pages_range(unsigned long addr, unsigned long end, + pgprot_t prot, struct page **pages, unsigned int page_shift) +{ + return -EINVAL; +} + #endif /* CONFIG_MMU */ #if defined(CONFIG_MMU) && defined(CONFIG_SMP) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 61caa55a4402..39b7e118cbce 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -722,6 +722,7 @@ int vmap_pages_range(unsigned long addr, unsigned long end, { return __vmap_pages_range(addr, end, prot, pages, page_shift, GFP_KERNEL); } +EXPORT_SYMBOL_GPL(vmap_pages_range); static int check_sparse_vm_area(struct vm_struct *area, unsigned long start, unsigned long end) @@ -3285,6 +3286,30 @@ struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags, NUMA_NO_NODE, GFP_KERNEL, caller); } +/** + * get_vm_area_node - reserve a contiguous and aligned kernel virtual area + * @size: size of the area + * @align: alignment of the start address of the area + * @flags: %VM_IOREMAP for I/O mappings + * @node: NUMA node from which to allocate the area data structure + * @gfp: Flags to pass to the allocator + * @caller: Caller to be stored in the vm area data structure + * + * Search for an area of @size/align in the kernel virtual mapping area and + * reserve it for our purposes. Returns the area descriptor on success or %NULL + * on failure. + * + * Return: the area descriptor on success or %NULL on failure. + */ +struct vm_struct *get_vm_area_node(unsigned long size, unsigned long align, + unsigned long flags, int node, gfp_t gfp, + const void *caller) +{ + return __get_vm_area_node(size, align, PAGE_SHIFT, flags, + VMALLOC_START, VMALLOC_END, + node, gfp, caller); +} + /** * find_vm_area - find a continuous kernel virtual area * @addr: base address -- 2.54.0.rc2.544.gc7ae2d5bb8-goog