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>
This commit is contained in:
Родитель
5611cc4572
Коммит
5f79020cb9
|
@ -196,7 +196,9 @@ static atomic_t kmemleak_enabled = ATOMIC_INIT(0);
|
||||||
static atomic_t kmemleak_initialized = ATOMIC_INIT(0);
|
static atomic_t kmemleak_initialized = ATOMIC_INIT(0);
|
||||||
/* enables or disables early logging of the memory operations */
|
/* enables or disables early logging of the memory operations */
|
||||||
static atomic_t kmemleak_early_log = ATOMIC_INIT(1);
|
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);
|
static atomic_t kmemleak_error = ATOMIC_INIT(0);
|
||||||
|
|
||||||
/* minimum and maximum address that may be valid pointers */
|
/* minimum and maximum address that may be valid pointers */
|
||||||
|
@ -259,9 +261,10 @@ static void kmemleak_disable(void);
|
||||||
/*
|
/*
|
||||||
* Print a warning and dump the stack trace.
|
* Print a warning and dump the stack trace.
|
||||||
*/
|
*/
|
||||||
#define kmemleak_warn(x...) do { \
|
#define kmemleak_warn(x...) do { \
|
||||||
pr_warning(x); \
|
pr_warning(x); \
|
||||||
dump_stack(); \
|
dump_stack(); \
|
||||||
|
atomic_set(&kmemleak_warning, 1); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -403,8 +406,8 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias)
|
||||||
object = prio_tree_entry(node, struct kmemleak_object,
|
object = prio_tree_entry(node, struct kmemleak_object,
|
||||||
tree_node);
|
tree_node);
|
||||||
if (!alias && object->pointer != ptr) {
|
if (!alias && object->pointer != ptr) {
|
||||||
pr_warning("Found object by alias at 0x%08lx\n", ptr);
|
kmemleak_warn("Found object by alias at 0x%08lx\n",
|
||||||
dump_stack();
|
ptr);
|
||||||
dump_object_info(object);
|
dump_object_info(object);
|
||||||
object = NULL;
|
object = NULL;
|
||||||
}
|
}
|
||||||
|
@ -811,8 +814,7 @@ static void __init log_early(int op_type, const void *ptr, size_t size,
|
||||||
log->ptr = ptr;
|
log->ptr = ptr;
|
||||||
log->size = size;
|
log->size = size;
|
||||||
log->min_count = min_count;
|
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++;
|
crt_early_log++;
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
}
|
}
|
||||||
|
@ -1659,6 +1661,17 @@ static int kmemleak_boot_config(char *str)
|
||||||
}
|
}
|
||||||
early_param("kmemleak", kmemleak_boot_config);
|
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.
|
* Kmemleak initialization.
|
||||||
*/
|
*/
|
||||||
|
@ -1720,7 +1733,13 @@ void __init kmemleak_init(void)
|
||||||
kmemleak_no_scan(log->ptr);
|
kmemleak_no_scan(log->ptr);
|
||||||
break;
|
break;
|
||||||
default:
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче