From f6fc86f2c572ff1d192e8b5d5bf339ba06ebe3e4 Mon Sep 17 00:00:00 2001 From: Kuba Pawlak Date: Wed, 28 Oct 2015 15:18:05 +0100 Subject: [PATCH] Bluetooth: Fix possible deadlock in btusb commit 8f9d02f470f48416444ac3a1eacecdd0f743f1a7 introduced spinlocks in btusb_work. This is run in a context of a worqueue and can be interrupted by hardware irq. If it happens while spinlock is held, we have a deadlock. Solution is to use _irqsave/_resore version of locking [ 466.460560] ================================= [ 466.460565] [ INFO: inconsistent lock state ] [ 466.460572] 4.3.0-rc6+ #1 Tainted: G W [ 466.460576] --------------------------------- [ 466.460582] inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage. [ 466.460589] kworker/0:2/94 [HC0[0]:SC0[0]:HE1:SE1] takes: [ 466.460595] (&(&data->rxlock)->rlock){?.-...}, at: [] btusb_work+0xa3/0x3fd [btusb] [ 466.460621] {IN-HARDIRQ-W} state was registered at: [ 466.460625] [] __lock_acquire+0xc45/0x1e80 [ 466.460638] [] lock_acquire+0xe5/0x1f0 [ 466.460646] [] _raw_spin_lock+0x38/0x50 [ 466.460657] [] btusb_recv_intr+0x38/0x170 [btusb] [ 466.460668] [] btusb_intr_complete+0xa6/0x130 [btusb] [ 466.460679] [] __usb_hcd_giveback_urb+0x8e/0x160 [ 466.460690] [] usb_hcd_giveback_urb+0x3f/0x120 [ 466.460698] [] uhci_giveback_urb+0xad/0x280 [ 466.460706] [] uhci_scan_schedule.part.33+0x6b4/0xbe0 [ 466.460714] [] uhci_irq+0xd0/0x180 [ 466.460722] [] usb_hcd_irq+0x26/0x40 [ 466.460729] [] handle_irq_event_percpu+0x40/0x300 [ 466.460739] [] handle_irq_event+0x40/0x60 [ 466.460746] [] handle_fasteoi_irq+0x89/0x150 [ 466.460754] [] handle_irq+0x73/0x120 [ 466.460763] [] do_IRQ+0x61/0x120 [ 466.460772] [] ret_from_intr+0x0/0x31 [ 466.460780] [] cpuidle_enter+0x17/0x20 [ 466.460790] [] call_cpuidle+0x32/0x60 [ 466.460800] [] cpu_startup_entry+0x2b8/0x3f0 [ 466.460807] [] rest_init+0x13a/0x140 [ 466.460817] [] start_kernel+0x4a3/0x4c4 [ 466.460827] [] x86_64_start_reservations+0x2a/0x2c [ 466.460837] [] x86_64_start_kernel+0x14a/0x16d [ 466.460846] irq event stamp: 754913 [ 466.460851] hardirqs last enabled at (754913): [] _raw_spin_unlock_irq+0x2c/0x40 [ 466.460861] hardirqs last disabled at (754912): [] _raw_spin_lock_irq+0x1d/0x60 [ 466.460869] softirqs last enabled at (753024): [] __do_softirq+0x380/0x490 [ 466.460880] softirqs last disabled at (753009): [] irq_exit+0x10f/0x120 [ 466.460888] other info that might help us debug this: [ 466.460894] Possible unsafe locking scenario: [ 466.460899] CPU0 [ 466.460903] ---- [ 466.460907] lock(&(&data->rxlock)->rlock); [ 466.460915] [ 466.460918] lock(&(&data->rxlock)->rlock); [ 466.460926] *** DEADLOCK *** [ 466.460935] 2 locks held by kworker/0:2/94: [ 466.460939] #0: ("events"){.+.+.+}, at: [] process_one_work+0x16b/0x660 [ 466.460958] #1: ((&data->work)){+.+...}, at: [] process_one_work+0x16b/0x660 [ 466.460974] Signed-off-by: Kuba Pawlak Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e33dacf5bd98..92f0ee388f9e 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1372,6 +1372,8 @@ static void btusb_work(struct work_struct *work) } if (data->isoc_altsetting != new_alts) { + unsigned long flags; + clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->isoc_anchor); @@ -1384,10 +1386,10 @@ static void btusb_work(struct work_struct *work) * Clear outstanding fragment when selecting a new * alternate setting. */ - spin_lock(&data->rxlock); + spin_lock_irqsave(&data->rxlock, flags); kfree_skb(data->sco_skb); data->sco_skb = NULL; - spin_unlock(&data->rxlock); + spin_unlock_irqrestore(&data->rxlock, flags); if (__set_isoc_interface(hdev, new_alts) < 0) return; -- 2.30.2