@@ -519,6 +519,7 @@ struct hci_dev {
struct sk_buff *recv_event;
struct mutex req_lock;
+ spinlock_t req_skb_lock;
wait_queue_head_t req_wait_q;
__u32 req_status;
__u32 req_result;
@@ -2572,6 +2572,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
mutex_init(&hdev->lock);
mutex_init(&hdev->req_lock);
+ spin_lock_init(&hdev->req_skb_lock);
ida_init(&hdev->unset_handle_ida);
@@ -106,8 +106,7 @@ void hci_req_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
hdev->req_result = result;
hdev->req_status = HCI_REQ_DONE;
if (skb) {
- kfree_skb(hdev->req_skb);
- hdev->req_skb = skb_get(skb);
+ hci_req_skb_release_and_set(hdev, skb_get(skb));
}
wake_up_interruptible(&hdev->req_wait_q);
}
@@ -181,8 +180,7 @@ int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
break;
}
- kfree_skb(hdev->req_skb);
- hdev->req_skb = NULL;
+ hci_req_skb_release_and_set(hdev, NULL);
hdev->req_status = hdev->req_result = 0;
bt_dev_dbg(hdev, "end: err %d", err);
@@ -28,6 +28,15 @@
#define hci_req_sync_lock(hdev) mutex_lock(&hdev->req_lock)
#define hci_req_sync_unlock(hdev) mutex_unlock(&hdev->req_lock)
+#define hci_req_skb_release_and_set(hdev, val) \
+({ \
+ if (hdev->req_skb) { \
+ spin_lock(&hdev->req_skb_lock); \
+ kfree_skb(hdev->req_skb); \
+ hdev->req_skb = val; \
+ spin_unlock(&hdev->req_skb_lock); \
+ } \
+})
struct hci_request {
struct hci_dev *hdev;
@@ -33,8 +33,7 @@ static void hci_cmd_sync_complete(struct hci_dev *hdev, u8 result, u16 opcode,
hdev->req_status = HCI_REQ_DONE;
/* Free the request command so it is not used as response */
- kfree_skb(hdev->req_skb);
- hdev->req_skb = NULL;
+ hci_req_skb_release_and_set(hdev, NULL);
if (skb) {
struct sock *sk = hci_skb_sk(skb);
@@ -4935,10 +4934,7 @@ int hci_dev_open_sync(struct hci_dev *hdev)
hdev->sent_cmd = NULL;
}
- if (hdev->req_skb) {
- kfree_skb(hdev->req_skb);
- hdev->req_skb = NULL;
- }
+ hci_req_skb_release_and_set(hdev, NULL);
clear_bit(HCI_RUNNING, &hdev->flags);
hci_sock_dev_event(hdev, HCI_DEV_CLOSE);
@@ -5100,10 +5096,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
}
/* Drop last request */
- if (hdev->req_skb) {
- kfree_skb(hdev->req_skb);
- hdev->req_skb = NULL;
- }
+ hci_req_skb_release_and_set(hdev, NULL);
clear_bit(HCI_RUNNING, &hdev->flags);
hci_sock_dev_event(hdev, HCI_DEV_CLOSE);