From: "Paul E. McKenney" <paulmck@xxxxxxxxxx> The debug-object double-free checks in __call_rcu() print out the RCU callback function, which is usually sufficient to track down the double free. However, all uses of things like queue_rcu_work() will have the same RCU callback function (rcu_work_rcufn() in this case), so a diagnostic message for a double queue_rcu_work() needs more than just the callback function. This commit therefore prints the last allocation address of the double-freed callback when the callback is slab-allocated and sufficient debugging is enabled. It uses the shiny new kmem_last_alloc() and kmem_last_alloc_errstring() functions for this purpose. Cc: Christoph Lameter <cl@xxxxxxxxx> Cc: Pekka Enberg <penberg@xxxxxxxxxx> Cc: David Rientjes <rientjes@xxxxxxxxxx> Cc: Joonsoo Kim <iamjoonsoo.kim@xxxxxxx> Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> Cc: <linux-mm@xxxxxxxxx> Cc: Andrii Nakryiko <andrii@xxxxxxxxxx> Signed-off-by: Paul E. McKenney <paulmck@xxxxxxxxxx> --- kernel/rcu/tree.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index b6c9c49..788a072 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2957,6 +2957,8 @@ static void check_cb_ovld(struct rcu_data *rdp) static void __call_rcu(struct rcu_head *head, rcu_callback_t func) { + void *allocaddr; + const char *allocerr; unsigned long flags; struct rcu_data *rdp; bool was_alldone; @@ -2970,8 +2972,14 @@ __call_rcu(struct rcu_head *head, rcu_callback_t func) * Use rcu:rcu_callback trace event to find the previous * time callback was passed to __call_rcu(). */ - WARN_ONCE(1, "__call_rcu(): Double-freed CB %p->%pS()!!!\n", - head, head->func); + allocaddr = kmem_last_alloc(head); + allocerr = kmem_last_alloc_errstring(allocaddr); + if (allocerr) + WARN_ONCE(1, "__call_rcu(): Double-freed CB %p->%pS()!!! (%s)\n", + head, head->func, allocerr); + else + WARN_ONCE(1, "__call_rcu(): Double-freed CB %p->%pS()!!! (Allocated at %pS)\n", + head, head->func, allocaddr); WRITE_ONCE(head->func, rcu_leak_callback); return; } -- 2.9.5