Commit 2bd9af04 authored by Xiaotian Feng's avatar Xiaotian Feng Committed by David S. Miller

isdn: fix possible circular locking dependency

There's a circular locking dependency:

---> isdn_net_get_locked_lp
    --->lock &nd->queue_lock
    --->lock &nd->queue->xmit_lock
    .....................
    ---->unlock &nd->queue_lock

---> isdn_net_writebuf_skb (called with &nd->queue->xmit_lock locked)
    ---->isdn_net_inc_frame_cnt
         ---->isdn_net_device_busy
              ----> lock &nd->queue_lock

This will trigger lockdep warnings:

 =======================================================
 [ INFO: possible circular locking dependency detected ]
 2.6.32-rc4-testing #7
 -------------------------------------------------------
 ipppd/28379 is trying to acquire lock:
 (&netdev->queue_lock){......}, at: [<e62ad0fd>] isdn_net_device_busy+0x2c/0x74 [isdn]

 but task is already holding lock:
 (&netdev->local->xmit_lock){+.....}, at: [<e62aefc2>] isdn_net_write_super+0x3f/0x6e [isdn]

 which lock already depends on the new lock.
 .......

 We don't need to lock nd->queue->xmit_lock to protect single
isdn_net_lp_busy(). This can fix above lockdep warnings.
Reported-and-tested-by: default avatarTilman Schmidt <tilman@imap.cc>
Signed-off-by: default avatarXiaotian Feng <xtfeng@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0dc6d9cb
...@@ -83,19 +83,19 @@ static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd) ...@@ -83,19 +83,19 @@ static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd)
spin_lock_irqsave(&nd->queue_lock, flags); spin_lock_irqsave(&nd->queue_lock, flags);
lp = nd->queue; /* get lp on top of queue */ lp = nd->queue; /* get lp on top of queue */
spin_lock(&nd->queue->xmit_lock);
while (isdn_net_lp_busy(nd->queue)) { while (isdn_net_lp_busy(nd->queue)) {
spin_unlock(&nd->queue->xmit_lock);
nd->queue = nd->queue->next; nd->queue = nd->queue->next;
if (nd->queue == lp) { /* not found -- should never happen */ if (nd->queue == lp) { /* not found -- should never happen */
lp = NULL; lp = NULL;
goto errout; goto errout;
} }
spin_lock(&nd->queue->xmit_lock);
} }
lp = nd->queue; lp = nd->queue;
nd->queue = nd->queue->next; nd->queue = nd->queue->next;
spin_unlock_irqrestore(&nd->queue_lock, flags);
spin_lock(&lp->xmit_lock);
local_bh_disable(); local_bh_disable();
return lp;
errout: errout:
spin_unlock_irqrestore(&nd->queue_lock, flags); spin_unlock_irqrestore(&nd->queue_lock, flags);
return lp; return lp;
......
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