diff options
author | Chan-yeol Park <chanyeol.park@samsung.com> | 2014-10-31 01:23:06 -0400 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2014-11-01 17:20:21 -0400 |
commit | 039fada5cd1963c32ed13d18d0dd467fdf966b66 (patch) | |
tree | 8f6c1f136152b3b40816f6bc99369c31daa29111 /net | |
parent | 6bc6c49f1e2f3ab1bec05d1c08aad219ab4eb5d0 (diff) |
Bluetooth: Fix hci_sync missing wakeup interrupt
__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>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/hci_core.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 91995f8ab0a0..41b147c36d11 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -1147,13 +1147,15 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen, | |||
1147 | 1147 | ||
1148 | hdev->req_status = HCI_REQ_PEND; | 1148 | hdev->req_status = HCI_REQ_PEND; |
1149 | 1149 | ||
1150 | err = hci_req_run(&req, hci_req_sync_complete); | ||
1151 | if (err < 0) | ||
1152 | return ERR_PTR(err); | ||
1153 | |||
1154 | add_wait_queue(&hdev->req_wait_q, &wait); | 1150 | add_wait_queue(&hdev->req_wait_q, &wait); |
1155 | set_current_state(TASK_INTERRUPTIBLE); | 1151 | set_current_state(TASK_INTERRUPTIBLE); |
1156 | 1152 | ||
1153 | err = hci_req_run(&req, hci_req_sync_complete); | ||
1154 | if (err < 0) { | ||
1155 | remove_wait_queue(&hdev->req_wait_q, &wait); | ||
1156 | return ERR_PTR(err); | ||
1157 | } | ||
1158 | |||
1157 | schedule_timeout(timeout); | 1159 | schedule_timeout(timeout); |
1158 | 1160 | ||
1159 | remove_wait_queue(&hdev->req_wait_q, &wait); | 1161 | remove_wait_queue(&hdev->req_wait_q, &wait); |
@@ -1211,10 +1213,15 @@ static int __hci_req_sync(struct hci_dev *hdev, | |||
1211 | 1213 | ||
1212 | func(&req, opt); | 1214 | func(&req, opt); |
1213 | 1215 | ||
1216 | add_wait_queue(&hdev->req_wait_q, &wait); | ||
1217 | set_current_state(TASK_INTERRUPTIBLE); | ||
1218 | |||
1214 | err = hci_req_run(&req, hci_req_sync_complete); | 1219 | err = hci_req_run(&req, hci_req_sync_complete); |
1215 | if (err < 0) { | 1220 | if (err < 0) { |
1216 | hdev->req_status = 0; | 1221 | hdev->req_status = 0; |
1217 | 1222 | ||
1223 | remove_wait_queue(&hdev->req_wait_q, &wait); | ||
1224 | |||
1218 | /* ENODATA means the HCI request command queue is empty. | 1225 | /* ENODATA means the HCI request command queue is empty. |
1219 | * This can happen when a request with conditionals doesn't | 1226 | * This can happen when a request with conditionals doesn't |
1220 | * trigger any commands to be sent. This is normal behavior | 1227 | * trigger any commands to be sent. This is normal behavior |
@@ -1226,9 +1233,6 @@ static int __hci_req_sync(struct hci_dev *hdev, | |||
1226 | return err; | 1233 | return err; |
1227 | } | 1234 | } |
1228 | 1235 | ||
1229 | add_wait_queue(&hdev->req_wait_q, &wait); | ||
1230 | set_current_state(TASK_INTERRUPTIBLE); | ||
1231 | |||
1232 | schedule_timeout(timeout); | 1236 | schedule_timeout(timeout); |
1233 | 1237 | ||
1234 | remove_wait_queue(&hdev->req_wait_q, &wait); | 1238 | remove_wait_queue(&hdev->req_wait_q, &wait); |