[ltp] Memory leak with vmalloc?
Dave Hansen
linux-thinkpad@linux-thinkpad.org
Wed, 19 Apr 2006 17:15:29 -0700
--=-2iqpybU9O73zjsqNEfE5
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
On Wed, 2006-04-19 at 16:05 -0700, Dave Hansen wrote:
> On Sun, 2006-03-26 at 21:53 +0100, Hamish Marson wrote:
> > Is anyone else finding the same thing? It doesn't sem to be associated
> > with susped/resume itself... Dumping /proc/meminfo before & after shows
> > no loss during the suspend/resume cycle... At least not when I try by
> > hand..
>
> Module code itself sits in vmalloc'd areas, and the e1000 driver also
> does some vmallocs of its own. I'd venture a guess that one of those is
> responsible, first, but no guarantees. Putting some printks around the
> vmallocs in those two places might be helpful.
>
> I can also write you a debugging patch to print out what all of the
> callers of each vmalloc area were. Would take an hour or two to put
> together...
Here's a patch that will dump all of the vmalloc allocations out to
dmesg. Make sure to recompile all of your modules and do a clean kernel
build.
cat /proc/buddyinfo
will activiate it.
-- Dave
--=-2iqpybU9O73zjsqNEfE5
Content-Disposition: attachment; filename=vmalloc-debug.patch
Content-Type: text/x-patch; name=vmalloc-debug.patch; charset=ANSI_X3.4-1968
Content-Transfer-Encoding: 7bit
---
mm/swapfile.c | 0
work-dave/include/linux/vmalloc.h | 30 ++++++++-----
work-dave/mm/page_alloc.c | 5 +-
work-dave/mm/vmalloc.c | 87 +++++++++++++++++++++++++-------------
4 files changed, 83 insertions(+), 39 deletions(-)
diff -puN mm/vmalloc.c~vmalloc-debug mm/vmalloc.c
--- work/mm/vmalloc.c~vmalloc-debug 2006-04-19 17:12:39.000000000 -0700
+++ work-dave/mm/vmalloc.c 2006-04-19 17:12:39.000000000 -0700
@@ -157,8 +157,9 @@ int map_vm_area(struct vm_struct *area,
return err;
}
-struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags,
- unsigned long start, unsigned long end, int node)
+struct vm_struct *__get_vm_area_node_allocfile(unsigned long size, unsigned long flags,
+ unsigned long start, unsigned long end, int node
+ ,char *filename, int line)
{
struct vm_struct **p, *tmp, *area;
unsigned long align = 1;
@@ -178,6 +179,9 @@ struct vm_struct *__get_vm_area_node(uns
size = PAGE_ALIGN(size);
area = kmalloc_node(sizeof(*area), GFP_KERNEL, node);
+ area->afilename = filename;
+ area->aline = line;
+ memset(area, 0, sizeof(*area));
if (unlikely(!area))
return NULL;
@@ -230,10 +234,11 @@ out:
return NULL;
}
-struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
- unsigned long start, unsigned long end)
+struct vm_struct *__get_vm_area_afile(unsigned long size, unsigned long flags,
+ unsigned long start, unsigned long end,
+ char *f, int l)
{
- return __get_vm_area_node(size, flags, start, end, -1);
+ return __get_vm_area_node_allocfile(size, flags, start, end, -1,f,l);
}
/**
@@ -246,14 +251,38 @@ struct vm_struct *__get_vm_area(unsigned
* and reserved it for out purposes. Returns the area descriptor
* on success or %NULL on failure.
*/
-struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
+struct vm_struct *get_vm_area_afile(unsigned long size, unsigned long flags, char *f, int l)
{
- return __get_vm_area(size, flags, VMALLOC_START, VMALLOC_END);
+ return __get_vm_area_afile(size, flags, VMALLOC_START, VMALLOC_END,f,l);
}
-struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags, int node)
+struct vm_struct *get_vm_area_node_afile(unsigned long size, unsigned long flags, int node,char *f, int l)
{
- return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node);
+ return __get_vm_area_node_allocfile(size, flags, VMALLOC_START, VMALLOC_END, node,f,l);
+}
+
+void print_vmalloc_stuff(void)
+{
+ struct vm_struct **p, *tmp;
+
+ read_lock(&vmlist_lock);
+ for (p = &vmlist ; (tmp = *p) != NULL ;p = &tmp->next) {
+ printk("vmalloc %p pages: %5d size: %6ld - %s:%d\n",
+ tmp->addr,
+ tmp->nr_pages,
+ tmp->size,
+ tmp->filename,
+ tmp->line);
+ if ( tmp->filename != tmp->afilename ||
+ tmp->line != tmp->aline)
+ printk("vmalloc %p pages: %5d size: %6ld -a- %s:%d\n",
+ tmp->addr,
+ tmp->nr_pages,
+ tmp->size,
+ tmp->afilename,
+ tmp->aline);
+ }
+ read_unlock(&vmlist_lock);
}
/* Caller must hold vmlist_lock */
@@ -401,8 +430,8 @@ void *vmap(struct page **pages, unsigned
}
EXPORT_SYMBOL(vmap);
-void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
- pgprot_t prot, int node)
+void *__vmalloc_area_node_file(struct vm_struct *area, gfp_t gfp_mask,
+ pgprot_t prot, int node, char *file, int line)
{
struct page **pages;
unsigned int nr_pages, array_size, i;
@@ -413,9 +442,11 @@ void *__vmalloc_area_node(struct vm_stru
area->nr_pages = nr_pages;
/* Please note that the recursion is strictly bounded. */
if (array_size > PAGE_SIZE)
- pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node);
+ pages = __vmalloc_node_file(array_size, gfp_mask, PAGE_KERNEL, node, file, line);
else
pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node);
+ area->filename = file;
+ area->line = line;
area->pages = pages;
if (!area->pages) {
remove_vm_area(area->addr);
@@ -445,9 +476,9 @@ fail:
return NULL;
}
-void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
+void *__vmalloc_area_file(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot, char *file, int line)
{
- return __vmalloc_area_node(area, gfp_mask, prot, -1);
+ return __vmalloc_area_node_file(area, gfp_mask, prot, -1, file, line);
}
/**
@@ -462,8 +493,8 @@ void *__vmalloc_area(struct vm_struct *a
* allocator with @gfp_mask flags. Map them into contiguous
* kernel virtual space, using a pagetable protection of @prot.
*/
-void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
- int node)
+void *__vmalloc_node_file(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
+ int node, char *file, int line)
{
struct vm_struct *area;
@@ -471,19 +502,19 @@ void *__vmalloc_node(unsigned long size,
if (!size || (size >> PAGE_SHIFT) > num_physpages)
return NULL;
- area = get_vm_area_node(size, VM_ALLOC, node);
+ area = get_vm_area_node_afile(size, VM_ALLOC, node, file, line);
if (!area)
return NULL;
- return __vmalloc_area_node(area, gfp_mask, prot, node);
+ return __vmalloc_area_node_file(area, gfp_mask, prot, node, file, line);
}
-EXPORT_SYMBOL(__vmalloc_node);
+EXPORT_SYMBOL(__vmalloc_node_file);
-void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
+void *__vmalloc_file(unsigned long size, gfp_t gfp_mask, pgprot_t prot, char *file, int line)
{
- return __vmalloc_node(size, gfp_mask, prot, -1);
+ return __vmalloc_node_file(size, gfp_mask, prot, -1, file, line);
}
-EXPORT_SYMBOL(__vmalloc);
+EXPORT_SYMBOL(__vmalloc_file);
/**
* vmalloc - allocate virtually contiguous memory
@@ -496,11 +527,11 @@ EXPORT_SYMBOL(__vmalloc);
* For tight cotrol over page level allocator and protection flags
* use __vmalloc() instead.
*/
-void *vmalloc(unsigned long size)
+void *vmalloc_file(unsigned long size, char *file, int line)
{
- return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
+ return __vmalloc_file(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL, file, line);
}
-EXPORT_SYMBOL(vmalloc);
+EXPORT_SYMBOL(vmalloc_file);
/**
* vmalloc_node - allocate memory on a specific node
@@ -514,11 +545,11 @@ EXPORT_SYMBOL(vmalloc);
* For tight cotrol over page level allocator and protection flags
* use __vmalloc() instead.
*/
-void *vmalloc_node(unsigned long size, int node)
+void *vmalloc_node_file(unsigned long size, int node, char *file, int line)
{
- return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL, node);
+ return __vmalloc_node_file(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL, node, file, line);
}
-EXPORT_SYMBOL(vmalloc_node);
+EXPORT_SYMBOL(vmalloc_node_file);
#ifndef PAGE_KERNEL_EXEC
# define PAGE_KERNEL_EXEC PAGE_KERNEL
diff -puN include/linux/vmalloc.h~vmalloc-debug include/linux/vmalloc.h
--- work/include/linux/vmalloc.h~vmalloc-debug 2006-04-19 17:12:39.000000000 -0700
+++ work-dave/include/linux/vmalloc.h 2006-04-19 17:12:39.000000000 -0700
@@ -26,20 +26,28 @@ struct vm_struct {
unsigned int nr_pages;
unsigned long phys_addr;
struct vm_struct *next;
+ char *afilename;
+ int aline;
+ char *filename;
+ int line;
};
/*
* Highlevel APIs for driver use
*/
-extern void *vmalloc(unsigned long size);
-extern void *vmalloc_node(unsigned long size, int node);
+#define vmalloc(size) vmalloc_file(size, __FILE__, __LINE__)
+extern void *vmalloc_file(unsigned long size, char *file, int line);
+#define vmalloc_node(size, node) vmalloc_node_file(size, node, __FILE__, __LINE__)
+extern void *vmalloc_node_file(unsigned long size, int node, char *file, int line);
extern void *vmalloc_exec(unsigned long size);
extern void *vmalloc_32(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(unsigned long size, gfp_t gfp_mask,
- pgprot_t prot, int node);
+#define __vmalloc(size, gfp_mask, prot) __vmalloc_file(size, gfp_mask, prot, __FILE__, __LINE__)
+extern void *__vmalloc_file(unsigned long size, gfp_t gfp_mask, pgprot_t prot, char *file, int line);
+#define __vmalloc_area(a, b, c) __vmalloc_area_file(a, b, c, __FILE, __LINE__)
+extern void *__vmalloc_area_file(struct vm_struct *area, gfp_t gfp_mask,
+ pgprot_t prot, char *file, int line);
+extern void *__vmalloc_node_file(unsigned long size, gfp_t gfp_mask,
+ pgprot_t prot, int node, char *file, int line);
extern void vfree(void *addr);
extern void *vmap(struct page **pages, unsigned int count,
@@ -49,11 +57,13 @@ extern void vunmap(void *addr);
/*
* Lowlevel-APIs (not for driver use!)
*/
-extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
+#define get_vm_area(a, b) get_vm_area_afile(a, b, __FILE__, __LINE__)
+extern struct vm_struct *get_vm_area_afile(unsigned long size, unsigned long flags,char *f, int l);
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);
+#define get_vm_area_node(a,b,c) get_vm_area_node_afile(a,b,c, __FILE__, __LINE__)
+extern struct vm_struct *get_vm_area_node_afile(unsigned long size,
+ unsigned long flags, int node,char *f, int l);
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,
diff -puN mm/page_alloc.c~vmalloc-debug mm/page_alloc.c
--- work/mm/page_alloc.c~vmalloc-debug 2006-04-19 17:12:39.000000000 -0700
+++ work-dave/mm/page_alloc.c 2006-04-19 17:12:39.000000000 -0700
@@ -2274,6 +2274,8 @@ static int frag_show(struct seq_file *m,
struct zone *node_zones = pgdat->node_zones;
unsigned long flags;
int order;
+ extern void print_vmalloc_stuff(void);
+ print_vmalloc_stuff();
for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
if (!populated_zone(zone))
@@ -2305,7 +2307,8 @@ static int zoneinfo_show(struct seq_file
struct zone *zone;
struct zone *node_zones = pgdat->node_zones;
unsigned long flags;
-
+extern void print_vmalloc_stuff(void);
+ print_vmalloc_stuff();
for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; zone++) {
int i;
diff -puN fs/proc/proc_misc.c~vmalloc-debug fs/proc/proc_misc.c
diff -puN include/linux/list.h~vmalloc-debug include/linux/list.h
diff -puN fs/proc/mmu.c~vmalloc-debug fs/proc/mmu.c
diff -puN fs/proc/kcore.c~vmalloc-debug fs/proc/kcore.c
diff -puN mm/swapfile.c~vmalloc-debug mm/swapfile.c
_
--=-2iqpybU9O73zjsqNEfE5--