The following commit has been merged in the linux branch: commit 2bd9af046fdc10703b266b0f3b25423f0b7d703e Author: Xiaotian Feng xtfeng@gmail.com Date: Wed Oct 21 23:07:04 2009 +0000
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
diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h index 74032d0..7511f08 100644 --- a/drivers/isdn/i4l/isdn_net.h +++ b/drivers/isdn/i4l/isdn_net.h @@ -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;