mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
Bluetooth: hci_core: Fix queuing tx_work after workqueue is drained
hci_send_acl(), hci_send_sco() and hci_send_iso() queue hdev->tx_work
unconditionally. They can run from the L2CAP/SCO/ISO socket send path
while hci_dev_close_sync() is draining hdev->workqueue (HCIDEVDOWN
racing with a socket write). Since that queue_work() is not chained
work from the tx_work worker itself, __queue_work() sees the queue
marked __WQ_DRAINING, warns "cannot queue %ps on wq %s", and drops
the work:
WARNING: CPU: 1 PID: 5985 at kernel/workqueue.c:2352 __queue_work
Call Trace:
queue_work_on
l2cap_chan_send
l2cap_sock_sendmsg
...
hci_dev_close_sync() already sets HCI_CMD_DRAIN_WORKQUEUE before
draining, but only hci_cmd_work() and handle_cmd_cnt_and_timer()
check it before queuing. Route the tx_work producers through the
same guard via a shared hci_sched_tx() helper.
Fixes: 525daaea45 ("Bluetooth: hci_sync: Set HCI_CMD_DRAIN_WORKQUEUE during device close")
Reported-by: syzbot+b6919040d9958e2fc1ae@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=b6919040d9958e2fc1ae
Signed-off-by: ThangNN99 <ngocthang2710.1999@gmail.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
e824176679
commit
6610c6fe4b
|
|
@ -3236,6 +3236,17 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
|
|||
bt_dev_dbg(hdev, "chan %p queued %d", chan, skb_queue_len(queue));
|
||||
}
|
||||
|
||||
/* Queue hdev->tx_work, unless hdev->workqueue is being drained by
|
||||
* hci_dev_close_sync(), which would otherwise WARN and drop the work.
|
||||
*/
|
||||
static void hci_sched_tx(struct hci_dev *hdev)
|
||||
{
|
||||
rcu_read_lock();
|
||||
if (!hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE))
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
|
||||
{
|
||||
struct hci_dev *hdev = chan->conn->hdev;
|
||||
|
|
@ -3244,7 +3255,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
|
|||
|
||||
hci_queue_acl(chan, &chan->data_q, skb, flags);
|
||||
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
hci_sched_tx(hdev);
|
||||
}
|
||||
|
||||
/* Send SCO data */
|
||||
|
|
@ -3269,7 +3280,7 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
|
|||
bt_dev_dbg(hdev, "hcon %p queued %d", conn,
|
||||
skb_queue_len(&conn->data_q));
|
||||
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
hci_sched_tx(hdev);
|
||||
}
|
||||
|
||||
/* Send ISO data */
|
||||
|
|
@ -3340,7 +3351,7 @@ void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb)
|
|||
|
||||
hci_queue_iso(conn, &conn->data_q, skb);
|
||||
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
hci_sched_tx(hdev);
|
||||
}
|
||||
|
||||
/* ---- HCI TX task (outgoing data) ---- */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user