Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5f79020c authored by Catalin Marinas's avatar Catalin Marinas
Browse files

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: default avatarSteven Rostedt <rostedt@goodmis.org>
Cc: Andrew Morton <akpm@google.com>
Signed-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
Acked-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent 5611cc45
Loading
Loading
Loading
Loading
+28 −9
Original line number Diff line number Diff line
@@ -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 */
@@ -262,6 +264,7 @@ static void kmemleak_disable(void);
#define kmemleak_warn(x...)	do {		\
	pr_warning(x);				\
	dump_stack();				\
	atomic_set(&kmemleak_warning, 1);	\
} 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,
					 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;
		}
@@ -811,7 +814,6 @@ 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);
	crt_early_log++;
	local_irq_restore(flags);
@@ -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.
 */
@@ -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);
		}
	}
}