| From 4231d47e6fe69f061f96c98c30eaf9fb4c14b96d Mon Sep 17 00:00:00 2001 |
| From: Sebastian Siewior <bigeasy@linutronix.de> |
| Date: Wed, 7 Mar 2012 10:19:28 +0000 |
| Subject: net/usbnet: avoid recursive locking in usbnet_stop() |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Sebastian Siewior <bigeasy@linutronix.de> |
| |
| commit 4231d47e6fe69f061f96c98c30eaf9fb4c14b96d upstream. |
| |
| |kernel BUG at kernel/rtmutex.c:724! |
| |[<c029599c>] (rt_spin_lock_slowlock+0x108/0x2bc) from [<c01c2330>] (defer_bh+0x1c/0xb4) |
| |[<c01c2330>] (defer_bh+0x1c/0xb4) from [<c01c3afc>] (rx_complete+0x14c/0x194) |
| |[<c01c3afc>] (rx_complete+0x14c/0x194) from [<c01cac88>] (usb_hcd_giveback_urb+0xa0/0xf0) |
| |[<c01cac88>] (usb_hcd_giveback_urb+0xa0/0xf0) from [<c01e1ff4>] (musb_giveback+0x34/0x40) |
| |[<c01e1ff4>] (musb_giveback+0x34/0x40) from [<c01e2b1c>] (musb_advance_schedule+0xb4/0x1c0) |
| |[<c01e2b1c>] (musb_advance_schedule+0xb4/0x1c0) from [<c01e2ca8>] (musb_cleanup_urb.isra.9+0x80/0x8c) |
| |[<c01e2ca8>] (musb_cleanup_urb.isra.9+0x80/0x8c) from [<c01e2ed0>] (musb_urb_dequeue+0xec/0x108) |
| |[<c01e2ed0>] (musb_urb_dequeue+0xec/0x108) from [<c01cbb90>] (unlink1+0xbc/0xcc) |
| |[<c01cbb90>] (unlink1+0xbc/0xcc) from [<c01cc2ec>] (usb_hcd_unlink_urb+0x54/0xa8) |
| |[<c01cc2ec>] (usb_hcd_unlink_urb+0x54/0xa8) from [<c01c2a84>] (unlink_urbs.isra.17+0x2c/0x58) |
| |[<c01c2a84>] (unlink_urbs.isra.17+0x2c/0x58) from [<c01c2b44>] (usbnet_terminate_urbs+0x94/0x10c) |
| |[<c01c2b44>] (usbnet_terminate_urbs+0x94/0x10c) from [<c01c2d68>] (usbnet_stop+0x100/0x15c) |
| |[<c01c2d68>] (usbnet_stop+0x100/0x15c) from [<c020f718>] (__dev_close_many+0x94/0xc8) |
| |
| defer_bh() takes the lock which is hold during unlink_urbs(). The safe |
| walk suggest that the skb will be removed from the list and this is done |
| by defer_bh() so it seems to be okay to drop the lock here. |
| |
| Reported-by: AnÃbal Almeida Pinto <anibal.pinto@efacec.com> |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| Acked-by: Oliver Neukum <oliver@neukum.org> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/net/usb/usbnet.c | 2 ++ |
| 1 file changed, 2 insertions(+) |
| |
| --- a/drivers/net/usb/usbnet.c |
| +++ b/drivers/net/usb/usbnet.c |
| @@ -585,6 +585,7 @@ static int unlink_urbs (struct usbnet *d |
| entry = (struct skb_data *) skb->cb; |
| urb = entry->urb; |
| |
| + spin_unlock_irqrestore(&q->lock, flags); |
| // during some PM-driven resume scenarios, |
| // these (async) unlinks complete immediately |
| retval = usb_unlink_urb (urb); |
| @@ -592,6 +593,7 @@ static int unlink_urbs (struct usbnet *d |
| netdev_dbg(dev->net, "unlink urb err, %d\n", retval); |
| else |
| count++; |
| + spin_lock_irqsave(&q->lock, flags); |
| } |
| spin_unlock_irqrestore (&q->lock, flags); |
| return count; |