From: Alexander Nyberg <alexn@dsv.su.se>
To: Andrew Morton <akpm@osdl.org>
Cc: Jens Axboe <axboe@suse.de>,
kas@fi.muni.cz, linux-kernel@vger.kernel.org,
lennert.vanalboom@ugent.be
Subject: Re: Memory leak in 2.6.11-rc1?
Date: Mon, 24 Jan 2005 01:56:59 +0100 [thread overview]
Message-ID: <1106528219.867.22.camel@boxen> (raw)
In-Reply-To: <20050123023248.263daca9.akpm@osdl.org>
> I don't think I've ever really seen code to diagnose this.
>
> A simplistic approach would be to add eight or so ulongs into struct page,
> populate them with builtin_return_address(0...7) at allocation time, then
> modify sysrq-m to walk mem_map[] printing it all out for pages which have
> page_count() > 0. That'd find the culprit.
Hi Andrew
I put something similar together of what you described but I made it a
proc-file. It lists all pages owned by some caller and keeps a backtrace
of max 8 addresses. Each page has an order, -1 for unused and if used it lists
the order under which the first page is allocated, the rest in the group are kept -1.
Below is also a program to sort the enormous amount of
output, it will group together backtraces that are alike and list them like:
5 times: Page allocated via order 0
[0xffffffff8015861f] __get_free_pages+31
[0xffffffff8015c0ef] cache_alloc_refill+719
[0xffffffff8015bd74] kmem_cache_alloc+84
[0xffffffff8015bddc] alloc_arraycache+60
[0xffffffff8015d15d] do_tune_cpucache+93
[0xffffffff8015bbf8] cache_alloc_debugcheck_after+280
[0xffffffff8015d31d] enable_cpucache+93
[0xffffffff8015d8a5] kmem_cache_create+1365
It's a bit of hackety-hack in the function trace routines because doing
__builtin_return_address(0) - 7 doesn't work very well when it
runs out of the stack and the function itself doesn't check for it.
Tested on x86 with and without CONFIG_FRAME_POINTER and x86-64 (which
might are the only archs it'll work on). I hope you like it ;)
Suggested use is
cat /proc/page_owner > pgown;
./below_program pgown pgsorted;
vim pgsorted
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
struct block_list {
struct block_list *next;
char *txt;
int len;
int num;
};
struct block_list *block_head;
int read_block(char *buf, int fd)
{
int ret = 0, rd = 0;
int hit = 0;
char *curr = buf;
for (;;) {
rd = read(fd, curr, 1);
if (rd <= 0)
return -1;
ret += rd;
if (*curr == '\n' && hit == 1)
return ret - 1;
else if (*curr == '\n')
hit = 1;
else
hit = 0;
curr++;
}
}
int find_duplicate(char *buf, int len)
{
struct block_list *iterate, *item, *prev;
char *txt;
iterate = block_head;
while (iterate) {
if (len != iterate->len)
goto iterate;
if (!memcmp(buf, iterate->txt, len)) {
iterate->num++;
return 1;
}
iterate:
iterate = iterate->next;
}
/* this block didn't exist */
txt = malloc(len);
item = malloc(sizeof(struct block_list));
strncpy(txt, buf, len);
item->len = len;
item->txt = txt;
item->num = 1;
item->next = NULL;
if (block_head) {
prev = block_head->next;
block_head->next = item;
item->next = prev;
} else
block_head = item;
return 0;
}
int main(int argc, char **argv)
{
int fdin, fdout;
char buf[1024];
int ret;
struct block_list *item;
fdin = open(argv[1], O_RDONLY);
fdout = open(argv[2], O_CREAT | O_RDWR | O_EXCL, S_IWUSR | S_IRUSR);
if (fdin < 0 || fdout < 0) {
printf("Usage: ./program <input> <output>\n");
perror("open: ");
exit(2);
}
for(;;) {
ret = read_block(buf, fdin);
if (ret < 0)
break;
buf[ret] = '\0';
find_duplicate(buf, ret);
}
for (item = block_head; item; item = item->next) {
int written;
/* errors? what errors... */
ret = snprintf(buf, 1024, "%d times: ", item->num);
written = write(fdout, buf, ret);
written = write(fdout, item->txt, item->len);
written = write(fdout, "\n", 1);
}
return 0;
}
===== fs/proc/proc_misc.c 1.113 vs edited =====
--- 1.113/fs/proc/proc_misc.c 2005-01-12 01:42:35 +01:00
+++ edited/fs/proc/proc_misc.c 2005-01-24 00:59:23 +01:00
@@ -534,6 +534,62 @@ static struct file_operations proc_sysrq
};
#endif
+#if 1
+#include <linux/bootmem.h>
+#include <linux/kallsyms.h>
+static ssize_t
+read_page_owner(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+ struct page *start = pfn_to_page(min_low_pfn);
+ static struct page *page;
+ char *kbuf, *modname;
+ const char *symname;
+ int ret = 0, next_idx = 1;
+ char namebuf[128];
+ unsigned long offset = 0, symsize;
+ int i;
+
+ page = start + *ppos;
+ for (; page < pfn_to_page(max_pfn); page++) {
+ if (page->order >= 0)
+ break;
+ next_idx++;
+ continue;
+ }
+
+ if (page >= pfn_to_page(max_pfn))
+ return 0;
+
+ *ppos += next_idx;
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ ret = snprintf(kbuf, count, "Page allocated via order %d\n", page->order);
+
+ for (i = 0; i < 8; i++) {
+ if (!page->trace[i])
+ break;
+ symname = kallsyms_lookup(page->trace[i], &symsize, &offset, &modname, namebuf);
+ ret += snprintf(kbuf + ret, count - ret, "[0x%lx] %s+%lu\n",
+ page->trace[i], namebuf, offset);
+ }
+
+ ret += snprintf(kbuf + ret, count -ret, "\n");
+
+ if (copy_to_user(buf, kbuf, ret))
+ ret = -EFAULT;
+
+ kfree(kbuf);
+ return ret;
+}
+
+static struct file_operations proc_page_owner_operations = {
+ .read = read_page_owner,
+};
+#endif
+
struct proc_dir_entry *proc_root_kcore;
void create_seq_entry(char *name, mode_t mode, struct file_operations *f)
@@ -610,6 +666,13 @@ void __init proc_misc_init(void)
entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL);
if (entry)
entry->proc_fops = &ppc_htab_operations;
+ }
+#endif
+#if 1
+ entry = create_proc_entry("page_owner", S_IWUSR | S_IRUGO, NULL);
+ if (entry) {
+ entry->proc_fops = &proc_page_owner_operations;
+ entry->size = 1024;
}
#endif
}
===== include/linux/mm.h 1.211 vs edited =====
--- 1.211/include/linux/mm.h 2005-01-11 02:29:23 +01:00
+++ edited/include/linux/mm.h 2005-01-23 23:22:52 +01:00
@@ -260,6 +260,10 @@ struct page {
void *virtual; /* Kernel virtual address (NULL if
not kmapped, ie. highmem) */
#endif /* WANT_PAGE_VIRTUAL */
+#if 1
+ int order;
+ unsigned long trace[8];
+#endif
};
/*
===== mm/page_alloc.c 1.254 vs edited =====
--- 1.254/mm/page_alloc.c 2005-01-11 02:29:33 +01:00
+++ edited/mm/page_alloc.c 2005-01-24 01:04:38 +01:00
@@ -103,6 +103,7 @@ static void bad_page(const char *functio
tainted |= TAINT_BAD_PAGE;
}
+
#ifndef CONFIG_HUGETLB_PAGE
#define prep_compound_page(page, order) do { } while (0)
#define destroy_compound_page(page, order) do { } while (0)
@@ -680,6 +681,41 @@ int zone_watermark_ok(struct zone *z, in
return 1;
}
+static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
+{
+ return p > (void *)tinfo &&
+ p < (void *)tinfo + THREAD_SIZE - 3;
+}
+
+static inline void __stack_trace(struct page *page, unsigned long *stack, unsigned long bp)
+{
+ int i = 0;
+ unsigned long addr;
+ struct thread_info *tinfo = (struct thread_info *)
+ ((unsigned long)stack & (~(THREAD_SIZE - 1)));
+
+ memset(page->trace, 0, sizeof(long) * 8);
+
+#ifdef CONFIG_FRAME_POINTER
+ while (valid_stack_ptr(tinfo, (void *)bp)) {
+ addr = *(unsigned long *)(bp + sizeof(long));
+ page->trace[i] = addr;
+ if (++i >= 8)
+ break;
+ bp = *(unsigned long *)bp;
+ }
+#else
+ while (valid_stack_ptr(tinfo, stack)) {
+ addr = *stack++;
+ if (__kernel_text_address(addr)) {
+ page->trace[i] = addr;
+ if (++i >= 8)
+ break;
+ }
+ }
+#endif
+}
+
/*
* This is the 'heart' of the zoned buddy allocator.
*
@@ -709,6 +745,7 @@ __alloc_pages(unsigned int gfp_mask, uns
int alloc_type;
int do_retry;
int can_try_harder;
+ unsigned long address, bp;
might_sleep_if(wait);
@@ -825,6 +862,14 @@ nopage:
return NULL;
got_pg:
zone_statistics(zonelist, z);
+ page->order = (int) order;
+#ifdef X86_64
+ asm ("movq %%rbp, %0" : "=r" (bp) : );
+#else
+ asm ("movl %%ebp, %0" : "=r" (bp) : );
+#endif
+ __stack_trace(page, &address, bp);
+
return page;
}
@@ -877,6 +922,7 @@ fastcall void __free_pages(struct page *
free_hot_page(page);
else
__free_pages_ok(page, order);
+ page->order = -1;
}
}
@@ -1508,6 +1554,7 @@ void __init memmap_init_zone(unsigned lo
set_page_address(page, __va(start_pfn << PAGE_SHIFT));
#endif
start_pfn++;
+ page->order = -1;
}
}
next prev parent reply other threads:[~2005-01-24 0:57 UTC|newest]
Thread overview: 87+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-01-21 16:19 Memory leak in 2.6.11-rc1? Jan Kasprzak
2005-01-22 2:23 ` Alexander Nyberg
2005-01-23 9:11 ` Jens Axboe
2005-01-23 9:19 ` Andrew Morton
2005-01-23 9:56 ` Jens Axboe
2005-01-23 10:32 ` Andrew Morton
2005-01-23 20:03 ` Russell King
2005-01-24 11:48 ` Russell King
2005-01-25 19:32 ` Russell King
2005-01-27 8:28 ` Russell King
2005-01-27 8:47 ` Andrew Morton
2005-01-27 10:19 ` Alessandro Suardi
2005-01-27 12:17 ` Martin Josefsson
2005-01-27 12:56 ` Robert Olsson
2005-01-27 13:03 ` Robert Olsson
2005-01-27 16:49 ` Russell King
2005-01-27 18:37 ` Phil Oester
2005-01-27 19:25 ` Russell King
2005-01-27 20:40 ` Phil Oester
2005-01-28 9:32 ` Russell King
2005-01-27 20:33 ` David S. Miller
2005-01-28 0:17 ` Russell King
2005-01-28 0:34 ` David S. Miller
2005-01-28 8:58 ` Russell King
2005-01-30 13:23 ` Russell King
2005-01-30 15:34 ` Russell King
2005-01-30 16:57 ` Phil Oester
2005-01-30 17:23 ` Patrick McHardy
2005-01-30 17:26 ` Patrick McHardy
2005-01-30 17:58 ` Patrick McHardy
2005-01-30 18:45 ` Russell King
2005-01-31 2:48 ` David S. Miller
2005-01-31 4:11 ` Herbert Xu
2005-01-31 4:45 ` YOSHIFUJI Hideaki / 吉藤英明
2005-01-31 5:00 ` Patrick McHardy
2005-01-31 5:11 ` David S. Miller
2005-01-31 5:40 ` Herbert Xu
2005-01-31 5:16 ` YOSHIFUJI Hideaki / 吉藤英明
2005-01-31 5:42 ` Yasuyuki KOZAKAI
2005-01-30 18:01 ` Russell King
2005-01-30 18:19 ` Phil Oester
2005-01-28 1:41 ` Phil Oester
2005-01-24 0:56 ` Alexander Nyberg [this message]
2005-01-24 20:47 ` Jens Axboe
2005-01-24 20:56 ` Andrew Morton
2005-01-24 21:05 ` Jens Axboe
2005-01-24 22:35 ` Linus Torvalds
2005-01-25 15:53 ` OT " Paulo Marques
2005-01-26 8:01 ` Jens Axboe
2005-01-26 8:11 ` Andrew Morton
2005-01-26 8:40 ` Jens Axboe
2005-01-26 8:44 ` Andrew Morton
2005-01-26 8:47 ` Jens Axboe
2005-01-26 8:52 ` Jens Axboe
2005-01-26 9:00 ` William Lee Irwin III
2005-01-26 8:58 ` Andrew Morton
2005-01-26 9:03 ` Jens Axboe
2005-01-26 15:52 ` Parag Warudkar
2005-02-02 9:29 ` Lennert Van Alboom
2005-02-02 16:00 ` Linus Torvalds
2005-02-02 16:19 ` Lennert Van Alboom
2005-02-02 17:49 ` Dave Hansen
2005-02-02 18:27 ` Linus Torvalds
2005-02-02 19:07 ` Dave Hansen
2005-02-02 21:08 ` Linus Torvalds
2005-01-24 22:05 ` Andrew Morton
2005-02-07 11:00 ` Jan Kasprzak
2005-02-07 11:11 ` William Lee Irwin III
2005-02-07 15:38 ` Linus Torvalds
2005-02-07 15:52 ` Jan Kasprzak
2005-02-07 16:38 ` axboe
2005-02-07 17:35 ` Jan Kasprzak
2005-02-07 21:10 ` Jan Kasprzak
2005-02-08 2:47 ` Memory leak in 2.6.11-rc1? (also here) Noel Maddy
2005-02-16 4:00 ` -rc3 leaking NOT BIO [Was: Memory leak in 2.6.11-rc1?] Parag Warudkar
2005-02-16 5:12 ` Andrew Morton
2005-02-16 6:07 ` Parag Warudkar
2005-02-16 23:52 ` Andrew Morton
2005-02-17 13:00 ` Parag Warudkar
2005-02-17 18:18 ` Linus Torvalds
2005-02-18 1:38 ` Badari Pulavarty
2005-02-21 4:57 ` Parag Warudkar
2005-02-16 23:31 ` Parag Warudkar
2005-02-16 23:51 ` Andrew Morton
2005-02-17 1:19 ` Parag Warudkar
2005-02-17 3:48 ` Horst von Brand
2005-02-17 13:35 ` Parag Warudkar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1106528219.867.22.camel@boxen \
--to=alexn@dsv.su.se \
--cc=akpm@osdl.org \
--cc=axboe@suse.de \
--cc=kas@fi.muni.cz \
--cc=lennert.vanalboom@ugent.be \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.