diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2011-09-28 07:17:03 -0400 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2011-12-02 11:12:41 -0500 |
commit | 5f79020cb9fea59a5d4d1712bcd320523b129b35 (patch) | |
tree | e726d58389a1cd71999a19015f44716e6b6d747d /mm | |
parent | 5611cc4572e889b62a7b4c72a413536bf6a9c416 (diff) |
kmemleak: Show where early_log issues come from
Based on initial patch by Steven Rostedt.
Early kmemleak warnings did not show where the actual kmemleak API had
been called from but rather just a backtrace to the kmemleak_init()
function. By having all early kmemleak logs record the stack_trace, we
can have kmemleak_init() write exactly where the problem occurred. This
patch adds the setting of the kmemleak_warning variable every time a
kmemleak warning is issued. The kmemleak_init() function checks this
variable during early log replaying and prints the log trace if there
was any warning.
Reported-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Andrew Morton <akpm@google.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/kmemleak.c | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/mm/kmemleak.c b/mm/kmemleak.c index f3b2a00fe9c1..8b528e3f8413 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c | |||
@@ -196,7 +196,9 @@ static atomic_t kmemleak_enabled = ATOMIC_INIT(0); | |||
196 | static atomic_t kmemleak_initialized = ATOMIC_INIT(0); | 196 | static atomic_t kmemleak_initialized = ATOMIC_INIT(0); |
197 | /* enables or disables early logging of the memory operations */ | 197 | /* enables or disables early logging of the memory operations */ |
198 | static atomic_t kmemleak_early_log = ATOMIC_INIT(1); | 198 | static atomic_t kmemleak_early_log = ATOMIC_INIT(1); |
199 | /* set if a fata kmemleak error has occurred */ | 199 | /* set if a kmemleak warning was issued */ |
200 | static atomic_t kmemleak_warning = ATOMIC_INIT(0); | ||
201 | /* set if a fatal kmemleak error has occurred */ | ||
200 | static atomic_t kmemleak_error = ATOMIC_INIT(0); | 202 | static atomic_t kmemleak_error = ATOMIC_INIT(0); |
201 | 203 | ||
202 | /* minimum and maximum address that may be valid pointers */ | 204 | /* minimum and maximum address that may be valid pointers */ |
@@ -259,9 +261,10 @@ static void kmemleak_disable(void); | |||
259 | /* | 261 | /* |
260 | * Print a warning and dump the stack trace. | 262 | * Print a warning and dump the stack trace. |
261 | */ | 263 | */ |
262 | #define kmemleak_warn(x...) do { \ | 264 | #define kmemleak_warn(x...) do { \ |
263 | pr_warning(x); \ | 265 | pr_warning(x); \ |
264 | dump_stack(); \ | 266 | dump_stack(); \ |
267 | atomic_set(&kmemleak_warning, 1); \ | ||
265 | } while (0) | 268 | } while (0) |
266 | 269 | ||
267 | /* | 270 | /* |
@@ -403,8 +406,8 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias) | |||
403 | object = prio_tree_entry(node, struct kmemleak_object, | 406 | object = prio_tree_entry(node, struct kmemleak_object, |
404 | tree_node); | 407 | tree_node); |
405 | if (!alias && object->pointer != ptr) { | 408 | if (!alias && object->pointer != ptr) { |
406 | pr_warning("Found object by alias at 0x%08lx\n", ptr); | 409 | kmemleak_warn("Found object by alias at 0x%08lx\n", |
407 | dump_stack(); | 410 | ptr); |
408 | dump_object_info(object); | 411 | dump_object_info(object); |
409 | object = NULL; | 412 | object = NULL; |
410 | } | 413 | } |
@@ -811,8 +814,7 @@ static void __init log_early(int op_type, const void *ptr, size_t size, | |||
811 | log->ptr = ptr; | 814 | log->ptr = ptr; |
812 | log->size = size; | 815 | log->size = size; |
813 | log->min_count = min_count; | 816 | log->min_count = min_count; |
814 | if (op_type == KMEMLEAK_ALLOC) | 817 | log->trace_len = __save_stack_trace(log->trace); |
815 | log->trace_len = __save_stack_trace(log->trace); | ||
816 | crt_early_log++; | 818 | crt_early_log++; |
817 | local_irq_restore(flags); | 819 | local_irq_restore(flags); |
818 | } | 820 | } |
@@ -1659,6 +1661,17 @@ static int kmemleak_boot_config(char *str) | |||
1659 | } | 1661 | } |
1660 | early_param("kmemleak", kmemleak_boot_config); | 1662 | early_param("kmemleak", kmemleak_boot_config); |
1661 | 1663 | ||
1664 | static void __init print_log_trace(struct early_log *log) | ||
1665 | { | ||
1666 | struct stack_trace trace; | ||
1667 | |||
1668 | trace.nr_entries = log->trace_len; | ||
1669 | trace.entries = log->trace; | ||
1670 | |||
1671 | pr_notice("Early log backtrace:\n"); | ||
1672 | print_stack_trace(&trace, 2); | ||
1673 | } | ||
1674 | |||
1662 | /* | 1675 | /* |
1663 | * Kmemleak initialization. | 1676 | * Kmemleak initialization. |
1664 | */ | 1677 | */ |
@@ -1720,7 +1733,13 @@ void __init kmemleak_init(void) | |||
1720 | kmemleak_no_scan(log->ptr); | 1733 | kmemleak_no_scan(log->ptr); |
1721 | break; | 1734 | break; |
1722 | default: | 1735 | default: |
1723 | WARN_ON(1); | 1736 | kmemleak_warn("Unknown early log operation: %d\n", |
1737 | log->op_type); | ||
1738 | } | ||
1739 | |||
1740 | if (atomic_read(&kmemleak_warning)) { | ||
1741 | print_log_trace(log); | ||
1742 | atomic_set(&kmemleak_warning, 0); | ||
1724 | } | 1743 | } |
1725 | } | 1744 | } |
1726 | } | 1745 | } |