Commit a602538e authored by Paul E. McKenney's avatar Paul E. McKenney

srcu: Add DEBUG_OBJECTS_RCU_HEAD functionality

This commit adds DEBUG_OBJECTS_RCU_HEAD checking to detect call_srcu()
counterparts to double-free bugs.
Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
parent d4efe6c5
...@@ -761,6 +761,13 @@ static bool srcu_might_be_idle(struct srcu_struct *sp) ...@@ -761,6 +761,13 @@ static bool srcu_might_be_idle(struct srcu_struct *sp)
return true; /* With reasonable probability, idle! */ return true; /* With reasonable probability, idle! */
} }
/*
* SRCU callback function to leak a callback.
*/
static void srcu_leak_callback(struct rcu_head *rhp)
{
}
/* /*
* Enqueue an SRCU callback on the srcu_data structure associated with * Enqueue an SRCU callback on the srcu_data structure associated with
* the current CPU and the specified srcu_struct structure, initiating * the current CPU and the specified srcu_struct structure, initiating
...@@ -799,6 +806,12 @@ void __call_srcu(struct srcu_struct *sp, struct rcu_head *rhp, ...@@ -799,6 +806,12 @@ void __call_srcu(struct srcu_struct *sp, struct rcu_head *rhp,
struct srcu_data *sdp; struct srcu_data *sdp;
check_init_srcu_struct(sp); check_init_srcu_struct(sp);
if (debug_rcu_head_queue(rhp)) {
/* Probable double call_srcu(), so leak the callback. */
WRITE_ONCE(rhp->func, srcu_leak_callback);
WARN_ONCE(1, "call_srcu(): Leaked duplicate callback\n");
return;
}
rhp->func = func; rhp->func = func;
local_irq_save(flags); local_irq_save(flags);
sdp = this_cpu_ptr(sp->sda); sdp = this_cpu_ptr(sp->sda);
...@@ -973,9 +986,12 @@ void srcu_barrier(struct srcu_struct *sp) ...@@ -973,9 +986,12 @@ void srcu_barrier(struct srcu_struct *sp)
spin_lock_irq(&sdp->lock); spin_lock_irq(&sdp->lock);
atomic_inc(&sp->srcu_barrier_cpu_cnt); atomic_inc(&sp->srcu_barrier_cpu_cnt);
sdp->srcu_barrier_head.func = srcu_barrier_cb; sdp->srcu_barrier_head.func = srcu_barrier_cb;
debug_rcu_head_queue(&sdp->srcu_barrier_head);
if (!rcu_segcblist_entrain(&sdp->srcu_cblist, if (!rcu_segcblist_entrain(&sdp->srcu_cblist,
&sdp->srcu_barrier_head, 0)) &sdp->srcu_barrier_head, 0)) {
debug_rcu_head_unqueue(&sdp->srcu_barrier_head);
atomic_dec(&sp->srcu_barrier_cpu_cnt); atomic_dec(&sp->srcu_barrier_cpu_cnt);
}
spin_unlock_irq(&sdp->lock); spin_unlock_irq(&sdp->lock);
} }
...@@ -1100,6 +1116,7 @@ static void srcu_invoke_callbacks(struct work_struct *work) ...@@ -1100,6 +1116,7 @@ static void srcu_invoke_callbacks(struct work_struct *work)
spin_unlock_irq(&sdp->lock); spin_unlock_irq(&sdp->lock);
rhp = rcu_cblist_dequeue(&ready_cbs); rhp = rcu_cblist_dequeue(&ready_cbs);
for (; rhp != NULL; rhp = rcu_cblist_dequeue(&ready_cbs)) { for (; rhp != NULL; rhp = rcu_cblist_dequeue(&ready_cbs)) {
debug_rcu_head_unqueue(rhp);
local_bh_disable(); local_bh_disable();
rhp->func(rhp); rhp->func(rhp);
local_bh_enable(); local_bh_enable();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment