Re: INFO: possible circular locking dependency detected

From: Steven Rostedt
Date: Thu Jul 14 2011 - 12:58:34 EST


On Thu, 2011-07-14 at 17:49 +0300, Sergey Senozhatsky wrote:
> [ 4172.371363] Chain exists of:
> [ 4172.371363] rcu_node_level_0 --> sync_rcu_preempt_exp_wq.lock --> &p->pi_lock
> [ 4172.371370]
> [ 4172.371371] Possible unsafe locking scenario:
> [ 4172.371372]
> [ 4172.371374] CPU0 CPU1
> [ 4172.371375] ---- ----
> [ 4172.371377] lock(&p->pi_lock);
> [ 4172.371380] lock(sync_rcu_preempt_exp_wq.lock);
> [ 4172.371384] lock(&p->pi_lock);
> [ 4172.371387] lock(rcu_node_level_0);
> [ 4172.371390]
> [ 4172.371390] *** DEADLOCK ***

Here's what I found:

Note: rcu_node_level_0 == rnp->lock from rcu_init_one()

static char *buf[] = { "rcu_node_level_0",
"rcu_node_level_1",
"rcu_node_level_2",
"rcu_node_level_3" }; /* Match MAX_RCU_LVLS */

[..]
raw_spin_lock_init(&rnp->lock);
lockdep_set_class_and_name(&rnp->lock,
&rcu_node_class[i], buf[i]);


We have this call chain:

rcu_report_exp_rnp() {
raw_spin_lock_irqsave(&rnp->lock, flags);
wake_up(&sync_rcu_preempt_exp_wq);

__wake_up() {
/* q == sync_rcu_preempt_exp_wq */
spin_lock_irqsave(&q->lock, flags);
try_to_wake_up() {
raw_spin_lock_irqsave(&p->pi_lock, flags);

Which gives us the noted lock chain:


rcu_node_level_0 --> sync_rcu_preempt_exp_wq.lock --> &p->pi_lock


But then we have:

try_to_wake_up() {
raw_spin_lock_irqsave(&p->pi_lock, flags);
select_task_rq_fair() {
rcu_read_unlock() {
rcu_read_unlock_special() {
raw_spin_lock(&rnp->lock);


Now we have the call chain of &p->pi_lock -> rcu_node_level_O

But to call this we have:

void __rcu_read_unlock(void)
{
struct task_struct *t = current;

barrier(); /* needed if we ever invoke rcu_read_unlock in rcutree.c */
--t->rcu_read_lock_nesting;
barrier(); /* decrement before load of ->rcu_read_unlock_special */
if (t->rcu_read_lock_nesting == 0 &&
unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
rcu_read_unlock_special(t);

Thus the question is, how did we get rcu_read_unlock_special set here?

-- Steve


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/