Le 09/05/2023 à 18:56, Kent Overstreet a écrit : > From: Kent Overstreet <kent.overstreet@xxxxxxxxx> > > This is needed for bcachefs, which dynamically generates per-btree node > unpack functions. > > Signed-off-by: Kent Overstreet <kent.overstreet@xxxxxxxxx> > Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> > Cc: Uladzislau Rezki <urezki@xxxxxxxxx> > Cc: Christoph Hellwig <hch@xxxxxxxxxxxxx> > Cc: linux-mm@xxxxxxxxx > --- > include/linux/vmalloc.h | 1 + > kernel/module/main.c | 4 +--- > mm/nommu.c | 18 ++++++++++++++++++ > mm/vmalloc.c | 21 +++++++++++++++++++++ > 4 files changed, 41 insertions(+), 3 deletions(-) > > diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h > index 69250efa03..ff147fe115 100644 > --- a/include/linux/vmalloc.h > +++ b/include/linux/vmalloc.h > @@ -145,6 +145,7 @@ extern void *vzalloc(unsigned long size) __alloc_size(1); > extern void *vmalloc_user(unsigned long size) __alloc_size(1); > extern void *vmalloc_node(unsigned long size, int node) __alloc_size(1); > extern void *vzalloc_node(unsigned long size, int node) __alloc_size(1); > +extern void *vmalloc_exec(unsigned long size, gfp_t gfp_mask) __alloc_size(1); > extern void *vmalloc_32(unsigned long size) __alloc_size(1); > extern void *vmalloc_32_user(unsigned long size) __alloc_size(1); > extern void *__vmalloc(unsigned long size, gfp_t gfp_mask) __alloc_size(1); > diff --git a/kernel/module/main.c b/kernel/module/main.c > index d3be89de70..9eaa89e84c 100644 > --- a/kernel/module/main.c > +++ b/kernel/module/main.c > @@ -1607,9 +1607,7 @@ static void dynamic_debug_remove(struct module *mod, struct _ddebug_info *dyndbg > > void * __weak module_alloc(unsigned long size) > { > - return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END, > - GFP_KERNEL, PAGE_KERNEL_EXEC, VM_FLUSH_RESET_PERMS, > - NUMA_NO_NODE, __builtin_return_address(0)); > + return vmalloc_exec(size, GFP_KERNEL); > } > > bool __weak module_init_section(const char *name) > diff --git a/mm/nommu.c b/mm/nommu.c > index 57ba243c6a..8d9ab19e39 100644 > --- a/mm/nommu.c > +++ b/mm/nommu.c > @@ -280,6 +280,24 @@ void *vzalloc_node(unsigned long size, int node) > } > EXPORT_SYMBOL(vzalloc_node); > > +/** > + * vmalloc_exec - allocate virtually contiguous, executable memory > + * @size: allocation size > + * > + * Kernel-internal function to allocate enough pages to cover @size > + * the page level allocator and map them into contiguous and > + * executable kernel virtual space. > + * > + * For tight control over page level allocator and protection flags > + * use __vmalloc() instead. > + */ > + > +void *vmalloc_exec(unsigned long size, gfp_t gfp_mask) > +{ > + return __vmalloc(size, gfp_mask); > +} > +EXPORT_SYMBOL_GPL(vmalloc_exec); > + > /** > * vmalloc_32 - allocate virtually contiguous memory (32bit addressable) > * @size: allocation size > diff --git a/mm/vmalloc.c b/mm/vmalloc.c > index 31ff782d36..2ebb9ea7f0 100644 > --- a/mm/vmalloc.c > +++ b/mm/vmalloc.c > @@ -3401,6 +3401,27 @@ void *vzalloc_node(unsigned long size, int node) > } > EXPORT_SYMBOL(vzalloc_node); > > +/** > + * vmalloc_exec - allocate virtually contiguous, executable memory > + * @size: allocation size > + * > + * Kernel-internal function to allocate enough pages to cover @size > + * the page level allocator and map them into contiguous and > + * executable kernel virtual space. > + * > + * For tight control over page level allocator and protection flags > + * use __vmalloc() instead. > + * > + * Return: pointer to the allocated memory or %NULL on error > + */ > +void *vmalloc_exec(unsigned long size, gfp_t gfp_mask) > +{ > + return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END, > + gfp_mask, PAGE_KERNEL_EXEC, VM_FLUSH_RESET_PERMS, > + NUMA_NO_NODE, __builtin_return_address(0)); > +} That cannot work. The VMALLOC space is mapped non-exec on powerpc/32. You have to allocate between MODULES_VADDR and MODULES_END if you want something executable so you must use module_alloc() see https://elixir.bootlin.com/linux/v6.4-rc1/source/arch/powerpc/kernel/module.c#L108 > +EXPORT_SYMBOL_GPL(vmalloc_exec); > + > #if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32) > #define GFP_VMALLOC32 (GFP_DMA32 | GFP_KERNEL) > #elif defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA)