Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -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;