Skip to content

Commit

Permalink
mm: unify module_alloc code for vmalloc
Browse files Browse the repository at this point in the history
Four architectures (arm, mips, sparc, x86) use __vmalloc_area() for
module_init().  Much of the code is duplicated and can be generalized in a
globally accessible function, __vmalloc_node_range().

__vmalloc_node() now calls into __vmalloc_node_range() with a range of
[VMALLOC_START, VMALLOC_END) for functionally equivalent behavior.

Each architecture may then use __vmalloc_node_range() directly to remove
the duplication of code.

Signed-off-by: David Rientjes <[email protected]>
Cc: Christoph Lameter <[email protected]>
Cc: Russell King <[email protected]>
Cc: Ralf Baechle <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
rientjes authored and torvalds committed Jan 14, 2011
1 parent ec3f64f commit d0a2126
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 68 deletions.
14 changes: 3 additions & 11 deletions arch/arm/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,9 @@
#ifdef CONFIG_MMU
void *module_alloc(unsigned long size)
{
struct vm_struct *area;

size = PAGE_ALIGN(size);
if (!size)
return NULL;

area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
if (!area)
return NULL;

return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC);
return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
GFP_KERNEL, PAGE_KERNEL_EXEC, -1,
__builtin_return_address(0));
}
#else /* CONFIG_MMU */
void *module_alloc(unsigned long size)
Expand Down
14 changes: 3 additions & 11 deletions arch/mips/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,9 @@ static DEFINE_SPINLOCK(dbe_lock);
void *module_alloc(unsigned long size)
{
#ifdef MODULE_START
struct vm_struct *area;

size = PAGE_ALIGN(size);
if (!size)
return NULL;

area = __get_vm_area(size, VM_ALLOC, MODULE_START, MODULE_END);
if (!area)
return NULL;

return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
GFP_KERNEL, PAGE_KERNEL, -1,
__builtin_return_address(0));
#else
if (size == 0)
return NULL;
Expand Down
14 changes: 4 additions & 10 deletions arch/sparc/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,11 @@

static void *module_map(unsigned long size)
{
struct vm_struct *area;

size = PAGE_ALIGN(size);
if (!size || size > MODULES_LEN)
return NULL;

area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
if (!area)
if (PAGE_ALIGN(size) > MODULES_LEN)
return NULL;

return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
GFP_KERNEL, PAGE_KERNEL, -1,
__builtin_return_address(0));
}

static char *dot2underscore(char *name)
Expand Down
17 changes: 4 additions & 13 deletions arch/x86/kernel/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,11 @@

void *module_alloc(unsigned long size)
{
struct vm_struct *area;

if (!size)
return NULL;
size = PAGE_ALIGN(size);
if (size > MODULES_LEN)
if (PAGE_ALIGN(size) > MODULES_LEN)
return NULL;

area = __get_vm_area(size, VM_ALLOC, MODULES_VADDR, MODULES_END);
if (!area)
return NULL;

return __vmalloc_area(area, GFP_KERNEL | __GFP_HIGHMEM,
PAGE_KERNEL_EXEC);
return __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END,
GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC,
-1, __builtin_return_address(0));
}

/* Free memory returned from module_alloc */
Expand Down
5 changes: 3 additions & 2 deletions include/linux/vmalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ extern void *vmalloc_exec(unsigned long size);
extern void *vmalloc_32(unsigned long size);
extern void *vmalloc_32_user(unsigned long size);
extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot);
extern void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask,
pgprot_t prot);
extern void *__vmalloc_node_range(unsigned long size, unsigned long align,
unsigned long start, unsigned long end, gfp_t gfp_mask,
pgprot_t prot, int node, void *caller);
extern void vfree(const void *addr);

extern void *vmap(struct page **pages, unsigned int count,
Expand Down
50 changes: 29 additions & 21 deletions mm/vmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1530,25 +1530,12 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
return NULL;
}

void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
{
void *addr = __vmalloc_area_node(area, gfp_mask, prot, -1,
__builtin_return_address(0));

/*
* A ref_count = 3 is needed because the vm_struct and vmap_area
* structures allocated in the __get_vm_area_node() function contain
* references to the virtual address of the vmalloc'ed block.
*/
kmemleak_alloc(addr, area->size - PAGE_SIZE, 3, gfp_mask);

return addr;
}

/**
* __vmalloc_node - allocate virtually contiguous memory
* __vmalloc_node_range - allocate virtually contiguous memory
* @size: allocation size
* @align: desired alignment
* @start: vm area range start
* @end: vm area range end
* @gfp_mask: flags for the page level allocator
* @prot: protection mask for the allocated pages
* @node: node to use for allocation or -1
Expand All @@ -1558,9 +1545,9 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
* allocator with @gfp_mask flags. Map them into contiguous
* kernel virtual space, using a pagetable protection of @prot.
*/
static void *__vmalloc_node(unsigned long size, unsigned long align,
gfp_t gfp_mask, pgprot_t prot,
int node, void *caller)
void *__vmalloc_node_range(unsigned long size, unsigned long align,
unsigned long start, unsigned long end, gfp_t gfp_mask,
pgprot_t prot, int node, void *caller)
{
struct vm_struct *area;
void *addr;
Expand All @@ -1570,8 +1557,8 @@ static void *__vmalloc_node(unsigned long size, unsigned long align,
if (!size || (size >> PAGE_SHIFT) > totalram_pages)
return NULL;

area = __get_vm_area_node(size, align, VM_ALLOC, VMALLOC_START,
VMALLOC_END, node, gfp_mask, caller);
area = __get_vm_area_node(size, align, VM_ALLOC, start, end, node,
gfp_mask, caller);

if (!area)
return NULL;
Expand All @@ -1588,6 +1575,27 @@ static void *__vmalloc_node(unsigned long size, unsigned long align,
return addr;
}

/**
* __vmalloc_node - allocate virtually contiguous memory
* @size: allocation size
* @align: desired alignment
* @gfp_mask: flags for the page level allocator
* @prot: protection mask for the allocated pages
* @node: node to use for allocation or -1
* @caller: caller's return address
*
* Allocate enough pages to cover @size from the page level
* allocator with @gfp_mask flags. Map them into contiguous
* kernel virtual space, using a pagetable protection of @prot.
*/
static void *__vmalloc_node(unsigned long size, unsigned long align,
gfp_t gfp_mask, pgprot_t prot,
int node, void *caller)
{
return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
gfp_mask, prot, node, caller);
}

void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
{
return __vmalloc_node(size, 1, gfp_mask, prot, -1,
Expand Down

0 comments on commit d0a2126

Please sign in to comment.