Bluetooth: Fix hci_sync missing wakeup interrupt
authorChan-yeol Park <chanyeol.park@samsung.com>
Fri, 31 Oct 2014 05:23:06 +0000 (14:23 +0900)
committerJohan Hedberg <johan.hedberg@intel.com>
Sat, 1 Nov 2014 21:20:21 +0000 (23:20 +0200)
__hci_cmd_sync_ev(), __hci_req_sync() could miss wake_up_interrupt from
hci_req_sync_complete() because hci_cmd_work() workqueue and its response
could be completed before they are ready to get the signal through
add_wait_queue(), set_current_state(TASK_INTERRUPTIBLE).

Signed-off-by: Chan-yeol Park <chanyeol.park@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
net/bluetooth/hci_core.c

index 91995f8ab0a0dd410bc922373376fa24054273c9..41b147c36d11b54405622c1aa67ab128ae7af1e8 100644 (file)
@@ -1147,13 +1147,15 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
 
        hdev->req_status = HCI_REQ_PEND;
 
-       err = hci_req_run(&req, hci_req_sync_complete);
-       if (err < 0)
-               return ERR_PTR(err);
-
        add_wait_queue(&hdev->req_wait_q, &wait);
        set_current_state(TASK_INTERRUPTIBLE);
 
+       err = hci_req_run(&req, hci_req_sync_complete);
+       if (err < 0) {
+               remove_wait_queue(&hdev->req_wait_q, &wait);
+               return ERR_PTR(err);
+       }
+
        schedule_timeout(timeout);
 
        remove_wait_queue(&hdev->req_wait_q, &wait);
@@ -1211,10 +1213,15 @@ static int __hci_req_sync(struct hci_dev *hdev,
 
        func(&req, opt);
 
+       add_wait_queue(&hdev->req_wait_q, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
        err = hci_req_run(&req, hci_req_sync_complete);
        if (err < 0) {
                hdev->req_status = 0;
 
+               remove_wait_queue(&hdev->req_wait_q, &wait);
+
                /* ENODATA means the HCI request command queue is empty.
                 * This can happen when a request with conditionals doesn't
                 * trigger any commands to be sent. This is normal behavior
@@ -1226,9 +1233,6 @@ static int __hci_req_sync(struct hci_dev *hdev,
                return err;
        }
 
-       add_wait_queue(&hdev->req_wait_q, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-
        schedule_timeout(timeout);
 
        remove_wait_queue(&hdev->req_wait_q, &wait);