From d24afc57d51b1be41f95521e81399061fa5875a6 Mon Sep 17 00:00:00 2001 From: Rolf Eike Beer Date: Wed, 27 Sep 2006 01:50:13 -0700 Subject: [PATCH] Mark __remove_vm_area() static The function is exported but not used from anywhere else. It's also marked as "not for driver use" so noone out there should really care. Signed-off-by: Rolf Eike Beer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmalloc.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux/vmalloc.h') diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index dee88c6b6fa7..ce5f1482e6be 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -62,7 +62,6 @@ extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, extern struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int node); extern struct vm_struct *remove_vm_area(void *addr); -extern struct vm_struct *__remove_vm_area(void *addr); extern int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages); extern void unmap_vm_area(struct vm_struct *area); -- cgit v1.2.3 From 52fd24ca1db3a741f144bbc229beefe044202cac Mon Sep 17 00:00:00 2001 From: Giridhar Pemmasani Date: Sat, 28 Oct 2006 10:38:34 -0700 Subject: [PATCH] __vmalloc with GFP_ATOMIC causes 'sleeping from invalid context' If __vmalloc is called to allocate memory with GFP_ATOMIC in atomic context, the chain of calls results in __get_vm_area_node allocating memory for vm_struct with GFP_KERNEL, causing the 'sleeping from invalid context' warning. This patch fixes it by passing the gfp flags along so __get_vm_area_node allocates memory for vm_struct with the same flags. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmalloc.h | 3 ++- mm/vmalloc.c | 18 +++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'include/linux/vmalloc.h') diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index ce5f1482e6be..dc9a29d84abc 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -60,7 +60,8 @@ extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags); extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, unsigned long start, unsigned long end); extern struct vm_struct *get_vm_area_node(unsigned long size, - unsigned long flags, int node); + unsigned long flags, int node, + gfp_t gfp_mask); extern struct vm_struct *remove_vm_area(void *addr); extern int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages); diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 1133dd3aafcf..6d381df7c9b3 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -160,13 +160,15 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages) return err; } -struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, - unsigned long start, unsigned long end, int node) +static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, + unsigned long start, unsigned long end, + int node, gfp_t gfp_mask) { struct vm_struct **p, *tmp, *area; unsigned long align = 1; unsigned long addr; + BUG_ON(in_interrupt()); if (flags & VM_IOREMAP) { int bit = fls(size); @@ -180,7 +182,7 @@ struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags, addr = ALIGN(start, align); size = PAGE_ALIGN(size); - area = kmalloc_node(sizeof(*area), GFP_KERNEL, node); + area = kmalloc_node(sizeof(*area), gfp_mask, node); if (unlikely(!area)) return NULL; @@ -236,7 +238,7 @@ out: struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, unsigned long start, unsigned long end) { - return __get_vm_area_node(size, flags, start, end, -1); + return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL); } /** @@ -253,9 +255,11 @@ struct vm_struct *get_vm_area(unsigned long size, unsigned long flags) return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END); } -struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int node) +struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, + int node, gfp_t gfp_mask) { - return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node); + return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node, + gfp_mask); } /* Caller must hold vmlist_lock */ @@ -487,7 +491,7 @@ static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot, if (!size || (size >> PAGE_SHIFT) > num_physpages) return NULL; - area = get_vm_area_node(size, VM_ALLOC, node); + area = get_vm_area_node(size, VM_ALLOC, node, gfp_mask); if (!area) return NULL; -- cgit v1.2.3 From 2b4ac44e7c7e16cf9411b81693ff3e604f332bf1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 10 Nov 2006 12:27:48 -0800 Subject: [PATCH] vmalloc: optimization, cleanup, bugfixes - reorder 'struct vm_struct' to speedup lookups on CPUS with small cache lines. The fields 'next,addr,size' should be now in the same cache line, to speedup lookups. - One minor cleanup in __get_vm_area_node() - Bugfixes in vmalloc_user() and vmalloc_32_user() NULL returns from __vmalloc() and __find_vm_area() were not tested. [akpm@osdl.org: remove redundant BUG_ONs] Signed-off-by: Eric Dumazet Cc: Nick Piggin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/vmalloc.h | 3 ++- mm/vmalloc.c | 26 +++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'include/linux/vmalloc.h') diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index dc9a29d84abc..924e502905d4 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -23,13 +23,14 @@ struct vm_area_struct; #endif struct vm_struct { + /* keep next,addr,size together to speedup lookups */ + struct vm_struct *next; void *addr; unsigned long size; unsigned long flags; struct page **pages; unsigned int nr_pages; unsigned long phys_addr; - struct vm_struct *next; }; /* diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 46606c133e82..7dc6aa745166 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -186,10 +186,8 @@ static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long fl if (unlikely(!area)) return NULL; - if (unlikely(!size)) { - kfree (area); + if (unlikely(!size)) return NULL; - } /* * We always allocate a guard page. @@ -532,11 +530,12 @@ void *vmalloc_user(unsigned long size) void *ret; ret = __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); - write_lock(&vmlist_lock); - area = __find_vm_area(ret); - area->flags |= VM_USERMAP; - write_unlock(&vmlist_lock); - + if (ret) { + write_lock(&vmlist_lock); + area = __find_vm_area(ret); + area->flags |= VM_USERMAP; + write_unlock(&vmlist_lock); + } return ret; } EXPORT_SYMBOL(vmalloc_user); @@ -605,11 +604,12 @@ void *vmalloc_32_user(unsigned long size) void *ret; ret = __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); - write_lock(&vmlist_lock); - area = __find_vm_area(ret); - area->flags |= VM_USERMAP; - write_unlock(&vmlist_lock); - + if (ret) { + write_lock(&vmlist_lock); + area = __find_vm_area(ret); + area->flags |= VM_USERMAP; + write_unlock(&vmlist_lock); + } return ret; } EXPORT_SYMBOL(vmalloc_32_user); -- cgit v1.2.3