The following commit has been merged into the core/rcu branch of tip: Commit-ID: b4b7914a6a73fc169fd1ce2fcd78a1d83d9528a9 Gitweb: https://git.kernel.org/tip/b4b7914a6a73fc169fd1ce2fcd78a1d83d9528a9 Author: Paul E. McKenney <paul...@kernel.org> AuthorDate: Tue, 08 Dec 2020 13:45:49 -08:00 Committer: Paul E. McKenney <paul...@kernel.org> CommitterDate: Fri, 22 Jan 2021 15:24:16 -08:00
rcu: Make call_rcu() print mem_dump_obj() info for double-freed callback 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 calls mem_dump_obj() to dump out any additional available information on the double-freed callback. Cc: Christoph Lameter <c...@linux.com> Cc: Pekka Enberg <penb...@kernel.org> Cc: David Rientjes <rient...@google.com> Cc: Joonsoo Kim <iamjoonsoo....@lge.com> Cc: Andrew Morton <a...@linux-foundation.org> Cc: <linux...@kvack.org> Reported-by: Andrii Nakryiko <and...@kernel.org> Tested-by: Naresh Kamboju <naresh.kamb...@linaro.org> Signed-off-by: Paul E. McKenney <paul...@kernel.org> --- kernel/rcu/tree.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 40e5e3d..84513c5 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -2941,6 +2941,7 @@ static void check_cb_ovld(struct rcu_data *rdp) static void __call_rcu(struct rcu_head *head, rcu_callback_t func) { + static atomic_t doublefrees; unsigned long flags; struct rcu_data *rdp; bool was_alldone; @@ -2954,8 +2955,10 @@ __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); + if (atomic_inc_return(&doublefrees) < 4) { + pr_err("%s(): Double-freed CB %p->%pS()!!! ", __func__, head, head->func); + mem_dump_obj(head); + } WRITE_ONCE(head->func, rcu_leak_callback); return; }