Thread (33 messages) 33 messages, 10 authors, 2014-08-23
STALE4329d REVIEWED: 4 (2M)

[PATCH] bluetooth: hci_ldisc: fix deadlock condition

From: Tim Niemeyer <hidden>
Date: 2014-08-22 13:46:05
Also in: lkml, stable
Subsystem: bluetooth drivers, the rest · Maintainers: Marcel Holtmann, Luiz Augusto von Dentz, Linus Torvalds

This Patch was applied to 3.10 and 3.2. It's probably missed on 3.4.

---------------------

From: Felipe Balbi <redacted>

LDISCs shouldn't call tty->ops->write() from within
->write_wakeup().

->write_wakeup() is called with port lock taken and
IRQs disabled, tty->ops->write() will try to acquire
the same port lock and we will deadlock.

Acked-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: Peter Hurley <redacted>
Reported-by: Huang Shijie <redacted>
Signed-off-by: Felipe Balbi <redacted>
Tested-by: Andreas Bie=C3=9Fmann <redacted>
[tim.niemeyer@corscience.de: rebased on 3.4.103]
Signed-off-by: Tim Niemeyer <redacted>
---
 drivers/bluetooth/hci_ldisc.c |   25 ++++++++++++++++++++-----
 drivers/bluetooth/hci_uart.h  |    2 ++
 2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.=
c
index 98a8c05..d4550f9 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -118,10 +118,6 @@ static inline struct sk_buff *hci_uart_dequeue(struc=
t hci_uart *hu)
=20
 int hci_uart_tx_wakeup(struct hci_uart *hu)
 {
-	struct tty_struct *tty =3D hu->tty;
-	struct hci_dev *hdev =3D hu->hdev;
-	struct sk_buff *skb;
-
 	if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
 		set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
 		return 0;
@@ -129,6 +125,22 @@ int hci_uart_tx_wakeup(struct hci_uart *hu)
=20
 	BT_DBG("");
=20
+	schedule_work(&hu->write_work);
+
+	return 0;
+}
+
+static void hci_uart_write_work(struct work_struct *work)
+{
+	struct hci_uart *hu =3D container_of(work, struct hci_uart, write_work)=
;
+	struct tty_struct *tty =3D hu->tty;
+	struct hci_dev *hdev =3D hu->hdev;
+	struct sk_buff *skb;
+
+	/* REVISIT: should we cope with bad skbs or ->write() returning
+	 * and error value ?
+	 */
+
 restart:
 	clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
=20
@@ -153,7 +165,6 @@ restart:
 		goto restart;
=20
 	clear_bit(HCI_UART_SENDING, &hu->tx_state);
-	return 0;
 }
=20
 /* ------- Interface to HCI layer ------ */
@@ -264,6 +275,8 @@ static int hci_uart_tty_open(struct tty_struct *tty)
 	hu->tty =3D tty;
 	tty->receive_room =3D 65536;
=20
+	INIT_WORK(&hu->write_work, hci_uart_write_work);
+
 	spin_lock_init(&hu->rx_lock);
=20
 	/* Flush any pending characters in the driver and line discipline. */
@@ -298,6 +311,8 @@ static void hci_uart_tty_close(struct tty_struct *tty=
)
 		if (hdev)
 			hci_uart_close(hdev);
=20
+		cancel_work_sync(&hu->write_work);
+
 		if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
 			if (hdev) {
 				hci_unregister_dev(hdev);
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 6cf6ab22..af93d83 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -66,6 +66,8 @@ struct hci_uart {
 	unsigned long		flags;
 	unsigned long		hdev_flags;
=20
+	struct work_struct	write_work;
+
 	struct hci_uart_proto	*proto;
 	void			*priv;
=20
--=20
1.7.10.4
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help