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: Tilman Schmidt <tilman@imap.cc> Signed-off-by: Xiaotian Feng <xtfeng@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0dc6d9cbe7
commit
2bd9af046f
1 changed files with 3 additions and 3 deletions
|
@ -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);
|
||||
lp = nd->queue; /* get lp on top of queue */
|
||||
spin_lock(&nd->queue->xmit_lock);
|
||||
while (isdn_net_lp_busy(nd->queue)) {
|
||||
spin_unlock(&nd->queue->xmit_lock);
|
||||
nd->queue = nd->queue->next;
|
||||
if (nd->queue == lp) { /* not found -- should never happen */
|
||||
lp = NULL;
|
||||
goto errout;
|
||||
}
|
||||
spin_lock(&nd->queue->xmit_lock);
|
||||
}
|
||||
lp = nd->queue;
|
||||
nd->queue = nd->queue->next;
|
||||
spin_unlock_irqrestore(&nd->queue_lock, flags);
|
||||
spin_lock(&lp->xmit_lock);
|
||||
local_bh_disable();
|
||||
return lp;
|
||||
errout:
|
||||
spin_unlock_irqrestore(&nd->queue_lock, flags);
|
||||
return lp;
|
||||
|
|
Loading…
Reference in a new issue