Skip to content

Commit

Permalink
kmemleak: Show where early_log issues come from
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Catalin Marinas committed Dec 2, 2011
1 parent 5611cc4 commit 5f79020
Showing 1 changed file with 28 additions and 9 deletions.
37 changes: 28 additions & 9 deletions mm/kmemleak.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,9 @@ static atomic_t kmemleak_enabled = ATOMIC_INIT(0);
static atomic_t kmemleak_initialized = ATOMIC_INIT(0);
/* enables or disables early logging of the memory operations */
static atomic_t kmemleak_early_log = ATOMIC_INIT(1);
/* set if a fata kmemleak error has occurred */
/* set if a kmemleak warning was issued */
static atomic_t kmemleak_warning = ATOMIC_INIT(0);
/* set if a fatal kmemleak error has occurred */
static atomic_t kmemleak_error = ATOMIC_INIT(0);

/* minimum and maximum address that may be valid pointers */
Expand Down Expand Up @@ -259,9 +261,10 @@ static void kmemleak_disable(void);
/*
* Print a warning and dump the stack trace.
*/
#define kmemleak_warn(x...) do { \
pr_warning(x); \
dump_stack(); \
#define kmemleak_warn(x...) do { \
pr_warning(x); \
dump_stack(); \
atomic_set(&kmemleak_warning, 1); \
} while (0)

/*
Expand Down Expand Up @@ -403,8 +406,8 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias)
object = prio_tree_entry(node, struct kmemleak_object,
tree_node);
if (!alias && object->pointer != ptr) {
pr_warning("Found object by alias at 0x%08lx\n", ptr);
dump_stack();
kmemleak_warn("Found object by alias at 0x%08lx\n",
ptr);
dump_object_info(object);
object = NULL;
}
Expand Down Expand Up @@ -811,8 +814,7 @@ static void __init log_early(int op_type, const void *ptr, size_t size,
log->ptr = ptr;
log->size = size;
log->min_count = min_count;
if (op_type == KMEMLEAK_ALLOC)
log->trace_len = __save_stack_trace(log->trace);
log->trace_len = __save_stack_trace(log->trace);
crt_early_log++;
local_irq_restore(flags);
}
Expand Down Expand Up @@ -1659,6 +1661,17 @@ static int kmemleak_boot_config(char *str)
}
early_param("kmemleak", kmemleak_boot_config);

static void __init print_log_trace(struct early_log *log)
{
struct stack_trace trace;

trace.nr_entries = log->trace_len;
trace.entries = log->trace;

pr_notice("Early log backtrace:\n");
print_stack_trace(&trace, 2);
}

/*
* Kmemleak initialization.
*/
Expand Down Expand Up @@ -1720,7 +1733,13 @@ void __init kmemleak_init(void)
kmemleak_no_scan(log->ptr);
break;
default:
WARN_ON(1);
kmemleak_warn("Unknown early log operation: %d\n",
log->op_type);
}

if (atomic_read(&kmemleak_warning)) {
print_log_trace(log);
atomic_set(&kmemleak_warning, 0);
}
}
}
Expand Down

0 comments on commit 5f79020

Please sign in to comment.