* hci_ldsic nested locking problem
@ 2014-03-20 16:34 Felipe Balbi
[not found] ` <20140320163435.GH32692-HgARHv6XitL9zxVx7UNMDg@public.gmane.org>
0 siblings, 1 reply; 16+ messages in thread
From: Felipe Balbi @ 2014-03-20 16:34 UTC (permalink / raw)
To: Marcel Holtmann, Alan Cox, Greg KH
Cc: Muralidharan Karicheri, linux-bluetooth, linux-serial,
Linux Kernel Mailing List
[-- Attachment #1: Type: text/plain, Size: 564 bytes --]
Hi,
when 8250 driver calls uart_write_wakeup(), the tty port lock is already
taken. hci_ldisc.c's implementation of ->write_wakeup() calls
tty->ops->write() to actually send the characters, but that call will
try to acquire the same port lock again.
Looking at other line disciplines that looks like a bug in hci_ldisc.c.
Am I correct to assume that ->write_wakeup() is supposed to *just*
wakeup the bottom half so we handle ->write() in another context ?
Is it legal to call tty->ops->write() from within ->write_wakeup() ?
cheers
--
balbi
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread[parent not found: <20140320163435.GH32692-HgARHv6XitL9zxVx7UNMDg@public.gmane.org>]
* Re: hci_ldsic nested locking problem [not found] ` <20140320163435.GH32692-HgARHv6XitL9zxVx7UNMDg@public.gmane.org> @ 2014-03-20 16:42 ` Alan Cox [not found] ` <1395333736.22077.32.camel-wU3TRTJX3O1FGiH78xh5akvbDziVy8sZEvhb3Hwu1Ks@public.gmane.org> 0 siblings, 1 reply; 16+ messages in thread From: Alan Cox @ 2014-03-20 16:42 UTC (permalink / raw) To: balbi-l0cyMroinI0 Cc: Marcel Holtmann, Greg KH, Muralidharan Karicheri, linux-bluetooth-u79uwXL29TY76Z2rM5mHXA, linux-serial-u79uwXL29TY76Z2rM5mHXA, Linux Kernel Mailing List On Thu, 2014-03-20 at 11:34 -0500, Felipe Balbi wrote: > Hi, > > when 8250 driver calls uart_write_wakeup(), the tty port lock is already > taken. hci_ldisc.c's implementation of ->write_wakeup() calls > tty->ops->write() to actually send the characters, but that call will > try to acquire the same port lock again. > > Looking at other line disciplines that looks like a bug in hci_ldisc.c. > Am I correct to assume that ->write_wakeup() is supposed to *just* > wakeup the bottom half so we handle ->write() in another context ? > > Is it legal to call tty->ops->write() from within ->write_wakeup() ? It isn't because you might send all the bytes and go write write_wakeup write write wakeup ... and recurse Alan ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <1395333736.22077.32.camel-wU3TRTJX3O1FGiH78xh5akvbDziVy8sZEvhb3Hwu1Ks@public.gmane.org>]
* Re: hci_ldsic nested locking problem [not found] ` <1395333736.22077.32.camel-wU3TRTJX3O1FGiH78xh5akvbDziVy8sZEvhb3Hwu1Ks@public.gmane.org> @ 2014-03-20 17:16 ` Felipe Balbi 2014-03-20 17:29 ` Felipe Balbi 2014-03-20 17:31 ` Peter Hurley 0 siblings, 2 replies; 16+ messages in thread From: Felipe Balbi @ 2014-03-20 17:16 UTC (permalink / raw) To: Alan Cox Cc: balbi-l0cyMroinI0, Marcel Holtmann, Greg KH, Muralidharan Karicheri, linux-bluetooth-u79uwXL29TY76Z2rM5mHXA, linux-serial-u79uwXL29TY76Z2rM5mHXA, Linux Kernel Mailing List [-- Attachment #1: Type: text/plain, Size: 983 bytes --] On Thu, Mar 20, 2014 at 04:42:16PM +0000, Alan Cox wrote: > On Thu, 2014-03-20 at 11:34 -0500, Felipe Balbi wrote: > > Hi, > > > > when 8250 driver calls uart_write_wakeup(), the tty port lock is already > > taken. hci_ldisc.c's implementation of ->write_wakeup() calls > > tty->ops->write() to actually send the characters, but that call will > > try to acquire the same port lock again. > > > > Looking at other line disciplines that looks like a bug in hci_ldisc.c. > > Am I correct to assume that ->write_wakeup() is supposed to *just* > > wakeup the bottom half so we handle ->write() in another context ? > > > > Is it legal to call tty->ops->write() from within ->write_wakeup() ? > > It isn't because you might send all the bytes and go > > write > write_wakeup > write > write wakeup > ... > > and recurse cool, so there really is a bug in hci_ldisc. Marcel, any tips on how do you want this to be sorted out ? -- balbi [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 17:16 ` Felipe Balbi @ 2014-03-20 17:29 ` Felipe Balbi 2014-03-20 17:34 ` Peter Hurley 2014-03-20 17:31 ` Peter Hurley 1 sibling, 1 reply; 16+ messages in thread From: Felipe Balbi @ 2014-03-20 17:29 UTC (permalink / raw) To: Felipe Balbi Cc: Alan Cox, Marcel Holtmann, Greg KH, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List [-- Attachment #1: Type: text/plain, Size: 1848 bytes --] On Thu, Mar 20, 2014 at 12:16:22PM -0500, Felipe Balbi wrote: > On Thu, Mar 20, 2014 at 04:42:16PM +0000, Alan Cox wrote: > > On Thu, 2014-03-20 at 11:34 -0500, Felipe Balbi wrote: > > > Hi, > > > > > > when 8250 driver calls uart_write_wakeup(), the tty port lock is already > > > taken. hci_ldisc.c's implementation of ->write_wakeup() calls > > > tty->ops->write() to actually send the characters, but that call will > > > try to acquire the same port lock again. > > > > > > Looking at other line disciplines that looks like a bug in hci_ldisc.c. > > > Am I correct to assume that ->write_wakeup() is supposed to *just* > > > wakeup the bottom half so we handle ->write() in another context ? > > > > > > Is it legal to call tty->ops->write() from within ->write_wakeup() ? > > > > It isn't because you might send all the bytes and go > > > > write > > write_wakeup > > write > > write wakeup > > ... > > > > and recurse then we need updates to Documentation: Documentation/serial/tty.txt:: | Driver Side Interfaces: | | receive_buf() - Hand buffers of bytes from the driver to the ldisc | for processing. Semantics currently rather | mysterious 8( | | write_wakeup() - May be called at any point between open and close. | The TTY_DO_WRITE_WAKEUP flag indicates if a call | is needed but always races versus calls. Thus the | ldisc must be careful about setting order and to | handle unexpected calls. Must not sleep. | | The driver is forbidden from calling this directly | from the ->write call from the ldisc as the ldisc | is permitted to call the driver write method from | this function. In such a situation defer it. documentation says ldisc is allowed to call ->write() from ->write_wakeup(). huh ? -- balbi [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 17:29 ` Felipe Balbi @ 2014-03-20 17:34 ` Peter Hurley 2014-03-20 17:35 ` Felipe Balbi 0 siblings, 1 reply; 16+ messages in thread From: Peter Hurley @ 2014-03-20 17:34 UTC (permalink / raw) To: balbi Cc: Alan Cox, Marcel Holtmann, Greg KH, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List, Huang Shijie [ +cc Huang Shijie ] On 03/20/2014 01:29 PM, Felipe Balbi wrote: > then we need updates to Documentation: > > Documentation/serial/tty.txt:: > > | Driver Side Interfaces: > | > | receive_buf() - Hand buffers of bytes from the driver to the ldisc > | for processing. Semantics currently rather > | mysterious 8( > | > | write_wakeup() - May be called at any point between open and close. > | The TTY_DO_WRITE_WAKEUP flag indicates if a call > | is needed but always races versus calls. Thus the > | ldisc must be careful about setting order and to > | handle unexpected calls. Must not sleep. > | > | The driver is forbidden from calling this directly > | from the ->write call from the ldisc as the ldisc > | is permitted to call the driver write method from > | this function. In such a situation defer it. > > documentation says ldisc is allowed to call ->write() from > ->write_wakeup(). huh ? Patch submitted but never applied. http://www.spinics.net/lists/linux-serial/msg11144.html Regards, Peter Hurley ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 17:34 ` Peter Hurley @ 2014-03-20 17:35 ` Felipe Balbi [not found] ` <20140320173518.GD2827-HgARHv6XitL9zxVx7UNMDg@public.gmane.org> 0 siblings, 1 reply; 16+ messages in thread From: Felipe Balbi @ 2014-03-20 17:35 UTC (permalink / raw) To: Peter Hurley Cc: balbi, Alan Cox, Marcel Holtmann, Greg KH, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List, Huang Shijie [-- Attachment #1: Type: text/plain, Size: 1252 bytes --] On Thu, Mar 20, 2014 at 01:34:57PM -0400, Peter Hurley wrote: > [ +cc Huang Shijie ] > > On 03/20/2014 01:29 PM, Felipe Balbi wrote: > >then we need updates to Documentation: > > > >Documentation/serial/tty.txt:: > > > >| Driver Side Interfaces: > >| > >| receive_buf() - Hand buffers of bytes from the driver to the ldisc > >| for processing. Semantics currently rather > >| mysterious 8( > >| > >| write_wakeup() - May be called at any point between open and close. > >| The TTY_DO_WRITE_WAKEUP flag indicates if a call > >| is needed but always races versus calls. Thus the > >| ldisc must be careful about setting order and to > >| handle unexpected calls. Must not sleep. > >| > >| The driver is forbidden from calling this directly > >| from the ->write call from the ldisc as the ldisc > >| is permitted to call the driver write method from > >| this function. In such a situation defer it. > > > >documentation says ldisc is allowed to call ->write() from > >->write_wakeup(). huh ? > > Patch submitted but never applied. > > http://www.spinics.net/lists/linux-serial/msg11144.html Thank you. For that patch: Acked-by: Felipe Balbi <balbi@ti.com> -- balbi [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <20140320173518.GD2827-HgARHv6XitL9zxVx7UNMDg@public.gmane.org>]
* Re: hci_ldsic nested locking problem [not found] ` <20140320173518.GD2827-HgARHv6XitL9zxVx7UNMDg@public.gmane.org> @ 2014-03-20 18:45 ` Greg KH 2014-03-20 18:54 ` Peter Hurley 0 siblings, 1 reply; 16+ messages in thread From: Greg KH @ 2014-03-20 18:45 UTC (permalink / raw) To: Felipe Balbi Cc: Peter Hurley, Alan Cox, Marcel Holtmann, Muralidharan Karicheri, linux-bluetooth-u79uwXL29TY76Z2rM5mHXA, linux-serial-u79uwXL29TY76Z2rM5mHXA, Linux Kernel Mailing List, Huang Shijie On Thu, Mar 20, 2014 at 12:35:18PM -0500, Felipe Balbi wrote: > On Thu, Mar 20, 2014 at 01:34:57PM -0400, Peter Hurley wrote: > > [ +cc Huang Shijie ] > > > > On 03/20/2014 01:29 PM, Felipe Balbi wrote: > > >then we need updates to Documentation: > > > > > >Documentation/serial/tty.txt:: > > > > > >| Driver Side Interfaces: > > >| > > >| receive_buf() - Hand buffers of bytes from the driver to the ldisc > > >| for processing. Semantics currently rather > > >| mysterious 8( > > >| > > >| write_wakeup() - May be called at any point between open and close. > > >| The TTY_DO_WRITE_WAKEUP flag indicates if a call > > >| is needed but always races versus calls. Thus the > > >| ldisc must be careful about setting order and to > > >| handle unexpected calls. Must not sleep. > > >| > > >| The driver is forbidden from calling this directly > > >| from the ->write call from the ldisc as the ldisc > > >| is permitted to call the driver write method from > > >| this function. In such a situation defer it. > > > > > >documentation says ldisc is allowed to call ->write() from > > >->write_wakeup(). huh ? > > > > Patch submitted but never applied. > > > > http://www.spinics.net/lists/linux-serial/msg11144.html > > Thank you. For that patch: > > Acked-by: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org> Can someone resend it, this is lost in my tree for some reason... ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 18:45 ` Greg KH @ 2014-03-20 18:54 ` Peter Hurley 0 siblings, 0 replies; 16+ messages in thread From: Peter Hurley @ 2014-03-20 18:54 UTC (permalink / raw) To: Greg KH Cc: Felipe Balbi, Alan Cox, Marcel Holtmann, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List, Huang Shijie On 03/20/2014 02:45 PM, Greg KH wrote: > On Thu, Mar 20, 2014 at 12:35:18PM -0500, Felipe Balbi wrote: >> On Thu, Mar 20, 2014 at 01:34:57PM -0400, Peter Hurley wrote: >>> [ +cc Huang Shijie ] >>> >>> On 03/20/2014 01:29 PM, Felipe Balbi wrote: >>>> then we need updates to Documentation: >>>> >>>> Documentation/serial/tty.txt:: >>>> >>>> | Driver Side Interfaces: >>>> | >>>> | receive_buf() - Hand buffers of bytes from the driver to the ldisc >>>> | for processing. Semantics currently rather >>>> | mysterious 8( >>>> | >>>> | write_wakeup() - May be called at any point between open and close. >>>> | The TTY_DO_WRITE_WAKEUP flag indicates if a call >>>> | is needed but always races versus calls. Thus the >>>> | ldisc must be careful about setting order and to >>>> | handle unexpected calls. Must not sleep. >>>> | >>>> | The driver is forbidden from calling this directly >>>> | from the ->write call from the ldisc as the ldisc >>>> | is permitted to call the driver write method from >>>> | this function. In such a situation defer it. >>>> >>>> documentation says ldisc is allowed to call ->write() from >>>> ->write_wakeup(). huh ? >>> >>> Patch submitted but never applied. >>> >>> http://www.spinics.net/lists/linux-serial/msg11144.html >> >> Thank you. For that patch: >> >> Acked-by: Felipe Balbi <balbi@ti.com> > > Can someone resend it, this is lost in my tree for some reason... Apologies if my mailer mangles this. --- >% --- From: Huang Shijie <b32955@freescale.com> In the uart_handle_cts_change(), uart_write_wakeup() is called after we call @uart_port->ops->start_tx(). The Documentation/serial/driver tells us: ----------------------------------------------- start_tx(port) Start transmitting characters. Locking: port->lock taken. Interrupts: locally disabled. ----------------------------------------------- So when the uart_write_wakeup() is called, the port->lock is taken by the upper. See the following callstack: |_ uart_write_wakeup |_ tty_wakeup |_ ld->ops->write_wakeup With the port->lock held, we call the @write_wakeup. Some implemetation of the @write_wakeup does not notice that the port->lock is held, and it still tries to send data with uart_write() which will try to grab the prot->lock. A dead lock occurs, see the following log caught in the Bluetooth by uart: -------------------------------------------------------------------- BUG: spinlock lockup suspected on CPU#0, swapper/0/0 lock: 0xdc3f4410, .magic: dead4ead, .owner: swapper/0/0, .owner_cpu: 0 CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W 3.10.17-16839-ge4a1bef #1320 [<80014cbc>] (unwind_backtrace+0x0/0x138) from [<8001251c>] (show_stack+0x10/0x14) [<8001251c>] (show_stack+0x10/0x14) from [<802816ac>] (do_raw_spin_lock+0x108/0x184) [<802816ac>] (do_raw_spin_lock+0x108/0x184) from [<806a22b0>] (_raw_spin_lock_irqsave+0x54/0x60) [<806a22b0>] (_raw_spin_lock_irqsave+0x54/0x60) from [<802f5754>] (uart_write+0x38/0xe0) [<802f5754>] (uart_write+0x38/0xe0) from [<80455270>] (hci_uart_tx_wakeup+0xa4/0x168) [<80455270>] (hci_uart_tx_wakeup+0xa4/0x168) from [<802dab18>] (tty_wakeup+0x50/0x5c) [<802dab18>] (tty_wakeup+0x50/0x5c) from [<802f81a4>] (imx_rtsint+0x50/0x80) [<802f81a4>] (imx_rtsint+0x50/0x80) from [<802f88f4>] (imx_int+0x158/0x17c) [<802f88f4>] (imx_int+0x158/0x17c) from [<8007abe0>] (handle_irq_event_percpu+0x50/0x194) [<8007abe0>] (handle_irq_event_percpu+0x50/0x194) from [<8007ad60>] (handle_irq_event+0x3c/0x5c) -------------------------------------------------------------------- This patch adds more limits to the @write_wakeup, the one who wants to implemet the @write_wakeup should follow the limits which avoid the deadlock. Signed-off-by: Huang Shijie <b32955@freescale.com> --- include/linux/tty_ldisc.h | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index f15c898..539ccc5 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -91,7 +91,10 @@ * This function is called by the low-level tty driver to signal * that line discpline should try to send more characters to the * low-level driver for transmission. If the line discpline does - * not have any more data to send, it can just return. + * not have any more data to send, it can just return. If the line + * discipline does have some data to send, please arise a tasklet + * or workqueue to do the real data transfer. Do not send data in + * this hook, it may leads to a deadlock. * * int (*hangup)(struct tty_struct *) * -- 1.7.2.rc3 ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 17:16 ` Felipe Balbi 2014-03-20 17:29 ` Felipe Balbi @ 2014-03-20 17:31 ` Peter Hurley [not found] ` <532B25FC.3070408-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org> 1 sibling, 1 reply; 16+ messages in thread From: Peter Hurley @ 2014-03-20 17:31 UTC (permalink / raw) To: balbi, Marcel Holtmann Cc: Alan Cox, Greg KH, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List, Huang Shijie [ +cc Huang Shijie ] On 03/20/2014 01:16 PM, Felipe Balbi wrote: > On Thu, Mar 20, 2014 at 04:42:16PM +0000, Alan Cox wrote: >> On Thu, 2014-03-20 at 11:34 -0500, Felipe Balbi wrote: >>> Hi, >>> >>> when 8250 driver calls uart_write_wakeup(), the tty port lock is already >>> taken. hci_ldisc.c's implementation of ->write_wakeup() calls >>> tty->ops->write() to actually send the characters, but that call will >>> try to acquire the same port lock again. >>> >>> Looking at other line disciplines that looks like a bug in hci_ldisc.c. >>> Am I correct to assume that ->write_wakeup() is supposed to *just* >>> wakeup the bottom half so we handle ->write() in another context ? >>> >>> Is it legal to call tty->ops->write() from within ->write_wakeup() ? >> >> It isn't because you might send all the bytes and go >> >> write >> write_wakeup >> write >> write wakeup >> ... >> >> and recurse > > cool, so there really is a bug in hci_ldisc. Marcel, any tips on how do > you want this to be sorted out ? hci_uart_tx_wakeup() should perform the I/O as work. FWIW, this was reported by Huang Shijie back on Dec 6. I'd fix it but I have no way to test it. Regards, Peter Hurley ^ permalink raw reply [flat|nested] 16+ messages in thread
[parent not found: <532B25FC.3070408-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>]
* Re: hci_ldsic nested locking problem [not found] ` <532B25FC.3070408-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org> @ 2014-03-20 18:11 ` Felipe Balbi 2014-03-20 18:21 ` Peter Hurley 0 siblings, 1 reply; 16+ messages in thread From: Felipe Balbi @ 2014-03-20 18:11 UTC (permalink / raw) To: Peter Hurley Cc: balbi-l0cyMroinI0, Marcel Holtmann, Alan Cox, Greg KH, Muralidharan Karicheri, linux-bluetooth-u79uwXL29TY76Z2rM5mHXA, linux-serial-u79uwXL29TY76Z2rM5mHXA, Linux Kernel Mailing List, Huang Shijie [-- Attachment #1: Type: text/plain, Size: 3257 bytes --] On Thu, Mar 20, 2014 at 01:31:40PM -0400, Peter Hurley wrote: > [ +cc Huang Shijie ] > > On 03/20/2014 01:16 PM, Felipe Balbi wrote: > >On Thu, Mar 20, 2014 at 04:42:16PM +0000, Alan Cox wrote: > >>On Thu, 2014-03-20 at 11:34 -0500, Felipe Balbi wrote: > >>>Hi, > >>> > >>>when 8250 driver calls uart_write_wakeup(), the tty port lock is already > >>>taken. hci_ldisc.c's implementation of ->write_wakeup() calls > >>>tty->ops->write() to actually send the characters, but that call will > >>>try to acquire the same port lock again. > >>> > >>>Looking at other line disciplines that looks like a bug in hci_ldisc.c. > >>>Am I correct to assume that ->write_wakeup() is supposed to *just* > >>>wakeup the bottom half so we handle ->write() in another context ? > >>> > >>>Is it legal to call tty->ops->write() from within ->write_wakeup() ? > >> > >>It isn't because you might send all the bytes and go > >> > >> write > >> write_wakeup > >> write > >> write wakeup > >> ... > >> > >>and recurse > > > >cool, so there really is a bug in hci_ldisc. Marcel, any tips on how do > >you want this to be sorted out ? > > hci_uart_tx_wakeup() should perform the I/O as work. > FWIW, this was reported by Huang Shijie back on Dec 6. > > I'd fix it but I have no way to test it. here's a build-tested only patch which is waiting for testing from other colleagues who've got a platform to reproduce the problem: diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index bc68a44..789000d 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(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { - struct tty_struct *tty = hu->tty; - struct hci_dev *hdev = 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,18 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) BT_DBG(""); + schedule_work(&hu->write_work); + + return 0; +} + +static void hci_uart_write_work(struct work_struct *work) +{ + struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); + struct tty_struct *tty = hu->tty; + struct hci_dev *hdev = hu->hdev; + struct sk_buff *skb; + restart: clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); @@ -153,7 +161,6 @@ restart: goto restart; clear_bit(HCI_UART_SENDING, &hu->tx_state); - return 0; } static void hci_uart_init_work(struct work_struct *work) @@ -289,6 +296,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) tty->receive_room = 65536; INIT_WORK(&hu->init_ready, hci_uart_init_work); + INIT_WORK(&hu->write_work, hci_uart_write_work); spin_lock_init(&hu->rx_lock); diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index fffa61f..12df101 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -68,6 +68,7 @@ struct hci_uart { unsigned long hdev_flags; struct work_struct init_ready; + struct work_struct write_work; struct hci_uart_proto *proto; void *priv; -- balbi [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 18:11 ` Felipe Balbi @ 2014-03-20 18:21 ` Peter Hurley 2014-03-20 18:25 ` Felipe Balbi 0 siblings, 1 reply; 16+ messages in thread From: Peter Hurley @ 2014-03-20 18:21 UTC (permalink / raw) To: balbi Cc: Marcel Holtmann, Alan Cox, Greg KH, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List, Huang Shijie On 03/20/2014 02:11 PM, Felipe Balbi wrote: > On Thu, Mar 20, 2014 at 01:31:40PM -0400, Peter Hurley wrote: >> [ +cc Huang Shijie ] >> >> On 03/20/2014 01:16 PM, Felipe Balbi wrote: >>> On Thu, Mar 20, 2014 at 04:42:16PM +0000, Alan Cox wrote: >>>> On Thu, 2014-03-20 at 11:34 -0500, Felipe Balbi wrote: >>>>> Hi, >>>>> >>>>> when 8250 driver calls uart_write_wakeup(), the tty port lock is already >>>>> taken. hci_ldisc.c's implementation of ->write_wakeup() calls >>>>> tty->ops->write() to actually send the characters, but that call will >>>>> try to acquire the same port lock again. >>>>> >>>>> Looking at other line disciplines that looks like a bug in hci_ldisc.c. >>>>> Am I correct to assume that ->write_wakeup() is supposed to *just* >>>>> wakeup the bottom half so we handle ->write() in another context ? >>>>> >>>>> Is it legal to call tty->ops->write() from within ->write_wakeup() ? >>>> >>>> It isn't because you might send all the bytes and go >>>> >>>> write >>>> write_wakeup >>>> write >>>> write wakeup >>>> ... >>>> >>>> and recurse >>> >>> cool, so there really is a bug in hci_ldisc. Marcel, any tips on how do >>> you want this to be sorted out ? >> >> hci_uart_tx_wakeup() should perform the I/O as work. >> FWIW, this was reported by Huang Shijie back on Dec 6. >> >> I'd fix it but I have no way to test it. > > here's a build-tested only patch which is waiting for testing from other > colleagues who've got a platform to reproduce the problem: Where's the cancel_work_sync() on teardown? Regards, Peter Hurley > diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c > index bc68a44..789000d 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(struct hci_uart *hu) > > int hci_uart_tx_wakeup(struct hci_uart *hu) > { > - struct tty_struct *tty = hu->tty; > - struct hci_dev *hdev = 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,18 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) > > BT_DBG(""); > > + schedule_work(&hu->write_work); > + > + return 0; > +} > + > +static void hci_uart_write_work(struct work_struct *work) > +{ > + struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); > + struct tty_struct *tty = hu->tty; > + struct hci_dev *hdev = hu->hdev; > + struct sk_buff *skb; > + > restart: > clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); > > @@ -153,7 +161,6 @@ restart: > goto restart; > > clear_bit(HCI_UART_SENDING, &hu->tx_state); > - return 0; > } > > static void hci_uart_init_work(struct work_struct *work) > @@ -289,6 +296,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) > tty->receive_room = 65536; > > INIT_WORK(&hu->init_ready, hci_uart_init_work); > + INIT_WORK(&hu->write_work, hci_uart_write_work); > > spin_lock_init(&hu->rx_lock); > > diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h > index fffa61f..12df101 100644 > --- a/drivers/bluetooth/hci_uart.h > +++ b/drivers/bluetooth/hci_uart.h > @@ -68,6 +68,7 @@ struct hci_uart { > unsigned long hdev_flags; > > struct work_struct init_ready; > + struct work_struct write_work; > > struct hci_uart_proto *proto; > void *priv; > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 18:21 ` Peter Hurley @ 2014-03-20 18:25 ` Felipe Balbi 2014-03-20 19:01 ` Felipe Balbi 2014-03-20 19:16 ` Peter Hurley 0 siblings, 2 replies; 16+ messages in thread From: Felipe Balbi @ 2014-03-20 18:25 UTC (permalink / raw) To: Peter Hurley Cc: balbi, Marcel Holtmann, Alan Cox, Greg KH, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List, Huang Shijie [-- Attachment #1: Type: text/plain, Size: 4486 bytes --] On Thu, Mar 20, 2014 at 02:21:17PM -0400, Peter Hurley wrote: > On 03/20/2014 02:11 PM, Felipe Balbi wrote: > >On Thu, Mar 20, 2014 at 01:31:40PM -0400, Peter Hurley wrote: > >>[ +cc Huang Shijie ] > >> > >>On 03/20/2014 01:16 PM, Felipe Balbi wrote: > >>>On Thu, Mar 20, 2014 at 04:42:16PM +0000, Alan Cox wrote: > >>>>On Thu, 2014-03-20 at 11:34 -0500, Felipe Balbi wrote: > >>>>>Hi, > >>>>> > >>>>>when 8250 driver calls uart_write_wakeup(), the tty port lock is already > >>>>>taken. hci_ldisc.c's implementation of ->write_wakeup() calls > >>>>>tty->ops->write() to actually send the characters, but that call will > >>>>>try to acquire the same port lock again. > >>>>> > >>>>>Looking at other line disciplines that looks like a bug in hci_ldisc.c. > >>>>>Am I correct to assume that ->write_wakeup() is supposed to *just* > >>>>>wakeup the bottom half so we handle ->write() in another context ? > >>>>> > >>>>>Is it legal to call tty->ops->write() from within ->write_wakeup() ? > >>>> > >>>>It isn't because you might send all the bytes and go > >>>> > >>>> write > >>>> write_wakeup > >>>> write > >>>> write wakeup > >>>> ... > >>>> > >>>>and recurse > >>> > >>>cool, so there really is a bug in hci_ldisc. Marcel, any tips on how do > >>>you want this to be sorted out ? > >> > >>hci_uart_tx_wakeup() should perform the I/O as work. > >>FWIW, this was reported by Huang Shijie back on Dec 6. > >> > >>I'd fix it but I have no way to test it. > > > >here's a build-tested only patch which is waiting for testing from other > >colleagues who've got a platform to reproduce the problem: > > Where's the cancel_work_sync() on teardown? here, as a patch too this time: From 3ee6b74833f154df64a6164476b854846206a3f2 Mon Sep 17 00:00:00 2001 From: Felipe Balbi <balbi@ti.com> Date: Thu, 20 Mar 2014 13:20:10 -0500 Subject: [PATCH] bluetooth: hci_ldisc: fix deadlock condition 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. Signed-off-by: Felipe Balbi <balbi@ti.com> --- drivers/bluetooth/hci_ldisc.c | 20 +++++++++++++++----- drivers/bluetooth/hci_uart.h | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 6e06f6f..ecdd765 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(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { - struct tty_struct *tty = hu->tty; - struct hci_dev *hdev = 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,18 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) BT_DBG(""); + schedule_work(&hu->write_work); + + return 0; +} + +static void hci_uart_write_work(struct work_struct *work) +{ + struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); + struct tty_struct *tty = hu->tty; + struct hci_dev *hdev = hu->hdev; + struct sk_buff *skb; + restart: clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); @@ -153,7 +161,6 @@ restart: goto restart; clear_bit(HCI_UART_SENDING, &hu->tx_state); - return 0; } static void hci_uart_init_work(struct work_struct *work) @@ -281,6 +288,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) tty->receive_room = 65536; INIT_WORK(&hu->init_ready, hci_uart_init_work); + INIT_WORK(&hu->write_work, hci_uart_write_work); spin_lock_init(&hu->rx_lock); @@ -318,6 +326,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) if (hdev) hci_uart_close(hdev); + cancel_work_sync(&hy->write_work); + if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { if (hdev) { if (test_bit(HCI_UART_REGISTERED, &hu->flags)) diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index fffa61f..12df101 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -68,6 +68,7 @@ struct hci_uart { unsigned long hdev_flags; struct work_struct init_ready; + struct work_struct write_work; struct hci_uart_proto *proto; void *priv; -- 1.9.1.286.g5172cb3 -- balbi [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 18:25 ` Felipe Balbi @ 2014-03-20 19:01 ` Felipe Balbi 2014-03-20 19:03 ` Felipe Balbi 2014-03-20 19:16 ` Peter Hurley 1 sibling, 1 reply; 16+ messages in thread From: Felipe Balbi @ 2014-03-20 19:01 UTC (permalink / raw) To: Felipe Balbi Cc: Peter Hurley, Marcel Holtmann, Alan Cox, Greg KH, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List, Huang Shijie [-- Attachment #1: Type: text/plain, Size: 4289 bytes --] On Thu, Mar 20, 2014 at 01:25:28PM -0500, Felipe Balbi wrote: > On Thu, Mar 20, 2014 at 02:21:17PM -0400, Peter Hurley wrote: > > On 03/20/2014 02:11 PM, Felipe Balbi wrote: > > >On Thu, Mar 20, 2014 at 01:31:40PM -0400, Peter Hurley wrote: > > >>[ +cc Huang Shijie ] > > >> > > >>On 03/20/2014 01:16 PM, Felipe Balbi wrote: > > >>>On Thu, Mar 20, 2014 at 04:42:16PM +0000, Alan Cox wrote: > > >>>>On Thu, 2014-03-20 at 11:34 -0500, Felipe Balbi wrote: > > >>>>>Hi, > > >>>>> > > >>>>>when 8250 driver calls uart_write_wakeup(), the tty port lock is already > > >>>>>taken. hci_ldisc.c's implementation of ->write_wakeup() calls > > >>>>>tty->ops->write() to actually send the characters, but that call will > > >>>>>try to acquire the same port lock again. > > >>>>> > > >>>>>Looking at other line disciplines that looks like a bug in hci_ldisc.c. > > >>>>>Am I correct to assume that ->write_wakeup() is supposed to *just* > > >>>>>wakeup the bottom half so we handle ->write() in another context ? > > >>>>> > > >>>>>Is it legal to call tty->ops->write() from within ->write_wakeup() ? > > >>>> > > >>>>It isn't because you might send all the bytes and go > > >>>> > > >>>> write > > >>>> write_wakeup > > >>>> write > > >>>> write wakeup > > >>>> ... > > >>>> > > >>>>and recurse > > >>> > > >>>cool, so there really is a bug in hci_ldisc. Marcel, any tips on how do > > >>>you want this to be sorted out ? > > >> > > >>hci_uart_tx_wakeup() should perform the I/O as work. > > >>FWIW, this was reported by Huang Shijie back on Dec 6. > > >> > > >>I'd fix it but I have no way to test it. > > > > > >here's a build-tested only patch which is waiting for testing from other > > >colleagues who've got a platform to reproduce the problem: > > > > Where's the cancel_work_sync() on teardown? > > here, as a patch too this time: > > From 3ee6b74833f154df64a6164476b854846206a3f2 Mon Sep 17 00:00:00 2001 > From: Felipe Balbi <balbi@ti.com> > Date: Thu, 20 Mar 2014 13:20:10 -0500 > Subject: [PATCH] bluetooth: hci_ldisc: fix deadlock condition > > 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. > > Signed-off-by: Felipe Balbi <balbi@ti.com> > --- > drivers/bluetooth/hci_ldisc.c | 20 +++++++++++++++----- > drivers/bluetooth/hci_uart.h | 1 + > 2 files changed, 16 insertions(+), 5 deletions(-) > > diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c > index 6e06f6f..ecdd765 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(struct hci_uart *hu) > > int hci_uart_tx_wakeup(struct hci_uart *hu) > { > - struct tty_struct *tty = hu->tty; > - struct hci_dev *hdev = 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,18 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) > > BT_DBG(""); > > + schedule_work(&hu->write_work); > + > + return 0; > +} > + > +static void hci_uart_write_work(struct work_struct *work) > +{ > + struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); > + struct tty_struct *tty = hu->tty; > + struct hci_dev *hdev = hu->hdev; > + struct sk_buff *skb; > + > restart: > clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); > > @@ -153,7 +161,6 @@ restart: > goto restart; > > clear_bit(HCI_UART_SENDING, &hu->tx_state); > - return 0; > } > > static void hci_uart_init_work(struct work_struct *work) > @@ -281,6 +288,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) > tty->receive_room = 65536; > > INIT_WORK(&hu->init_ready, hci_uart_init_work); > + INIT_WORK(&hu->write_work, hci_uart_write_work); > > spin_lock_init(&hu->rx_lock); > > @@ -318,6 +326,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) > if (hdev) > hci_uart_close(hdev); > > + cancel_work_sync(&hy->write_work); forgot to commit, darn it -- balbi [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 19:01 ` Felipe Balbi @ 2014-03-20 19:03 ` Felipe Balbi 0 siblings, 0 replies; 16+ messages in thread From: Felipe Balbi @ 2014-03-20 19:03 UTC (permalink / raw) To: Felipe Balbi Cc: Peter Hurley, Marcel Holtmann, Alan Cox, Greg KH, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List, Huang Shijie [-- Attachment #1: Type: text/plain, Size: 3047 bytes --] Hi, On Thu, Mar 20, 2014 at 02:01:54PM -0500, Felipe Balbi wrote: > > @@ -318,6 +326,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) > > if (hdev) > > hci_uart_close(hdev); > > > > + cancel_work_sync(&hy->write_work); > > forgot to commit, darn it here it is: From eaf7ff6f2d224f202369e4820b76a03fa664fab0 Mon Sep 17 00:00:00 2001 From: Felipe Balbi <balbi@ti.com> Date: Thu, 20 Mar 2014 13:20:10 -0500 Subject: [PATCH] bluetooth: hci_ldisc: fix deadlock condition 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. Signed-off-by: Felipe Balbi <balbi@ti.com> --- drivers/bluetooth/hci_ldisc.c | 20 +++++++++++++++----- drivers/bluetooth/hci_uart.h | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 6e06f6f..5a53e50 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(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { - struct tty_struct *tty = hu->tty; - struct hci_dev *hdev = 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,18 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) BT_DBG(""); + schedule_work(&hu->write_work); + + return 0; +} + +static void hci_uart_write_work(struct work_struct *work) +{ + struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); + struct tty_struct *tty = hu->tty; + struct hci_dev *hdev = hu->hdev; + struct sk_buff *skb; + restart: clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); @@ -153,7 +161,6 @@ restart: goto restart; clear_bit(HCI_UART_SENDING, &hu->tx_state); - return 0; } static void hci_uart_init_work(struct work_struct *work) @@ -281,6 +288,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) tty->receive_room = 65536; INIT_WORK(&hu->init_ready, hci_uart_init_work); + INIT_WORK(&hu->write_work, hci_uart_write_work); spin_lock_init(&hu->rx_lock); @@ -318,6 +326,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) if (hdev) hci_uart_close(hdev); + cancel_work_sync(&hu->write_work); + if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { if (hdev) { if (test_bit(HCI_UART_REGISTERED, &hu->flags)) diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index fffa61f..12df101 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -68,6 +68,7 @@ struct hci_uart { unsigned long hdev_flags; struct work_struct init_ready; + struct work_struct write_work; struct hci_uart_proto *proto; void *priv; -- 1.9.1.286.g5172cb3 -- balbi [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 18:25 ` Felipe Balbi 2014-03-20 19:01 ` Felipe Balbi @ 2014-03-20 19:16 ` Peter Hurley 2014-03-20 19:25 ` Felipe Balbi 1 sibling, 1 reply; 16+ messages in thread From: Peter Hurley @ 2014-03-20 19:16 UTC (permalink / raw) To: balbi Cc: Marcel Holtmann, Alan Cox, Greg KH, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List, Huang Shijie On 03/20/2014 02:25 PM, Felipe Balbi wrote: > On Thu, Mar 20, 2014 at 02:21:17PM -0400, Peter Hurley wrote: >> On 03/20/2014 02:11 PM, Felipe Balbi wrote: >>> On Thu, Mar 20, 2014 at 01:31:40PM -0400, Peter Hurley wrote: >>>> [ +cc Huang Shijie ] >>>> >>>> On 03/20/2014 01:16 PM, Felipe Balbi wrote: >>>>> On Thu, Mar 20, 2014 at 04:42:16PM +0000, Alan Cox wrote: >>>>>> On Thu, 2014-03-20 at 11:34 -0500, Felipe Balbi wrote: >>>>>>> Hi, >>>>>>> >>>>>>> when 8250 driver calls uart_write_wakeup(), the tty port lock is already >>>>>>> taken. hci_ldisc.c's implementation of ->write_wakeup() calls >>>>>>> tty->ops->write() to actually send the characters, but that call will >>>>>>> try to acquire the same port lock again. >>>>>>> >>>>>>> Looking at other line disciplines that looks like a bug in hci_ldisc.c. >>>>>>> Am I correct to assume that ->write_wakeup() is supposed to *just* >>>>>>> wakeup the bottom half so we handle ->write() in another context ? >>>>>>> >>>>>>> Is it legal to call tty->ops->write() from within ->write_wakeup() ? >>>>>> >>>>>> It isn't because you might send all the bytes and go >>>>>> >>>>>> write >>>>>> write_wakeup >>>>>> write >>>>>> write wakeup >>>>>> ... >>>>>> >>>>>> and recurse >>>>> >>>>> cool, so there really is a bug in hci_ldisc. Marcel, any tips on how do >>>>> you want this to be sorted out ? >>>> >>>> hci_uart_tx_wakeup() should perform the I/O as work. >>>> FWIW, this was reported by Huang Shijie back on Dec 6. >>>> >>>> I'd fix it but I have no way to test it. >>> >>> here's a build-tested only patch which is waiting for testing from other >>> colleagues who've got a platform to reproduce the problem: >> >> Where's the cancel_work_sync() on teardown? > > here, as a patch too this time: Thanks. Minor edits below but, strictly speaking, not necessary. Reviewed-by: Peter Hurley <peter@hurleysoftware.com> > From 3ee6b74833f154df64a6164476b854846206a3f2 Mon Sep 17 00:00:00 2001 > From: Felipe Balbi <balbi@ti.com> > Date: Thu, 20 Mar 2014 13:20:10 -0500 > Subject: [PATCH] bluetooth: hci_ldisc: fix deadlock condition > > 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. > I know you found it independently but ? Reported-by: Huang Shijie <b32955@freescale.com> > Signed-off-by: Felipe Balbi <balbi@ti.com> > --- > drivers/bluetooth/hci_ldisc.c | 20 +++++++++++++++----- > drivers/bluetooth/hci_uart.h | 1 + > 2 files changed, 16 insertions(+), 5 deletions(-) > > diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c > index 6e06f6f..ecdd765 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(struct hci_uart *hu) > > int hci_uart_tx_wakeup(struct hci_uart *hu) > { > - struct tty_struct *tty = hu->tty; > - struct hci_dev *hdev = 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,18 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) > > BT_DBG(""); > > + schedule_work(&hu->write_work); > + > + return 0; > +} > + > +static void hci_uart_write_work(struct work_struct *work) > +{ > + struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); > + struct tty_struct *tty = hu->tty; > + struct hci_dev *hdev = hu->hdev; > + struct sk_buff *skb; > + + /* FIXME: if bad skb length or tty->ops->write() returns < 0 ??? */ > restart: > clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); > > @@ -153,7 +161,6 @@ restart: > goto restart; > > clear_bit(HCI_UART_SENDING, &hu->tx_state); > - return 0; > } > > static void hci_uart_init_work(struct work_struct *work) > @@ -281,6 +288,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) > tty->receive_room = 65536; > > INIT_WORK(&hu->init_ready, hci_uart_init_work); > + INIT_WORK(&hu->write_work, hci_uart_write_work); > > spin_lock_init(&hu->rx_lock); > > @@ -318,6 +326,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) > if (hdev) > hci_uart_close(hdev); > > + cancel_work_sync(&hy->write_work); > + > if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { > if (hdev) { > if (test_bit(HCI_UART_REGISTERED, &hu->flags)) > diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h > index fffa61f..12df101 100644 > --- a/drivers/bluetooth/hci_uart.h > +++ b/drivers/bluetooth/hci_uart.h > @@ -68,6 +68,7 @@ struct hci_uart { > unsigned long hdev_flags; > > struct work_struct init_ready; > + struct work_struct write_work; > > struct hci_uart_proto *proto; > void *priv; > ^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: hci_ldsic nested locking problem 2014-03-20 19:16 ` Peter Hurley @ 2014-03-20 19:25 ` Felipe Balbi 0 siblings, 0 replies; 16+ messages in thread From: Felipe Balbi @ 2014-03-20 19:25 UTC (permalink / raw) To: Peter Hurley Cc: balbi, Marcel Holtmann, Alan Cox, Greg KH, Muralidharan Karicheri, linux-bluetooth, linux-serial, Linux Kernel Mailing List, Huang Shijie [-- Attachment #1: Type: text/plain, Size: 5439 bytes --] Hi, On Thu, Mar 20, 2014 at 03:16:35PM -0400, Peter Hurley wrote: > On 03/20/2014 02:25 PM, Felipe Balbi wrote: > >On Thu, Mar 20, 2014 at 02:21:17PM -0400, Peter Hurley wrote: > >>On 03/20/2014 02:11 PM, Felipe Balbi wrote: > >>>On Thu, Mar 20, 2014 at 01:31:40PM -0400, Peter Hurley wrote: > >>>>[ +cc Huang Shijie ] > >>>> > >>>>On 03/20/2014 01:16 PM, Felipe Balbi wrote: > >>>>>On Thu, Mar 20, 2014 at 04:42:16PM +0000, Alan Cox wrote: > >>>>>>On Thu, 2014-03-20 at 11:34 -0500, Felipe Balbi wrote: > >>>>>>>Hi, > >>>>>>> > >>>>>>>when 8250 driver calls uart_write_wakeup(), the tty port lock is already > >>>>>>>taken. hci_ldisc.c's implementation of ->write_wakeup() calls > >>>>>>>tty->ops->write() to actually send the characters, but that call will > >>>>>>>try to acquire the same port lock again. > >>>>>>> > >>>>>>>Looking at other line disciplines that looks like a bug in hci_ldisc.c. > >>>>>>>Am I correct to assume that ->write_wakeup() is supposed to *just* > >>>>>>>wakeup the bottom half so we handle ->write() in another context ? > >>>>>>> > >>>>>>>Is it legal to call tty->ops->write() from within ->write_wakeup() ? > >>>>>> > >>>>>>It isn't because you might send all the bytes and go > >>>>>> > >>>>>> write > >>>>>> write_wakeup > >>>>>> write > >>>>>> write wakeup > >>>>>> ... > >>>>>> > >>>>>>and recurse > >>>>> > >>>>>cool, so there really is a bug in hci_ldisc. Marcel, any tips on how do > >>>>>you want this to be sorted out ? > >>>> > >>>>hci_uart_tx_wakeup() should perform the I/O as work. > >>>>FWIW, this was reported by Huang Shijie back on Dec 6. > >>>> > >>>>I'd fix it but I have no way to test it. > >>> > >>>here's a build-tested only patch which is waiting for testing from other > >>>colleagues who've got a platform to reproduce the problem: > >> > >>Where's the cancel_work_sync() on teardown? > > > >here, as a patch too this time: > > Thanks. Minor edits below but, strictly speaking, not necessary. > > Reviewed-by: Peter Hurley <peter@hurleysoftware.com> > > > > From 3ee6b74833f154df64a6164476b854846206a3f2 Mon Sep 17 00:00:00 2001 > >From: Felipe Balbi <balbi@ti.com> > >Date: Thu, 20 Mar 2014 13:20:10 -0500 > >Subject: [PATCH] bluetooth: hci_ldisc: fix deadlock condition > > > >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. > > > > I know you found it independently but ? > > Reported-by: Huang Shijie <b32955@freescale.com> I will never add any *-by tags without seeing it in the mailing list. Now I can add it to the patch and send it as a real patch (git send-email it). > >Signed-off-by: Felipe Balbi <balbi@ti.com> > >--- > > drivers/bluetooth/hci_ldisc.c | 20 +++++++++++++++----- > > drivers/bluetooth/hci_uart.h | 1 + > > 2 files changed, 16 insertions(+), 5 deletions(-) > > > >diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c > >index 6e06f6f..ecdd765 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(struct hci_uart *hu) > > > > int hci_uart_tx_wakeup(struct hci_uart *hu) > > { > >- struct tty_struct *tty = hu->tty; > >- struct hci_dev *hdev = 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,18 @@ int hci_uart_tx_wakeup(struct hci_uart *hu) > > > > BT_DBG(""); > > > >+ schedule_work(&hu->write_work); > >+ > >+ return 0; > >+} > >+ > >+static void hci_uart_write_work(struct work_struct *work) > >+{ > >+ struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); > >+ struct tty_struct *tty = hu->tty; > >+ struct hci_dev *hdev = hu->hdev; > >+ struct sk_buff *skb; > >+ > > + /* FIXME: if bad skb length or tty->ops->write() returns < 0 ??? */ > > > restart: > > clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); > > > >@@ -153,7 +161,6 @@ restart: > > goto restart; > > > > clear_bit(HCI_UART_SENDING, &hu->tx_state); > >- return 0; > > } > > > > static void hci_uart_init_work(struct work_struct *work) > >@@ -281,6 +288,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) > > tty->receive_room = 65536; > > > > INIT_WORK(&hu->init_ready, hci_uart_init_work); > >+ INIT_WORK(&hu->write_work, hci_uart_write_work); > > > > spin_lock_init(&hu->rx_lock); > > > >@@ -318,6 +326,8 @@ static void hci_uart_tty_close(struct tty_struct *tty) > > if (hdev) > > hci_uart_close(hdev); > > > >+ cancel_work_sync(&hy->write_work); > >+ > > if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { > > if (hdev) { > > if (test_bit(HCI_UART_REGISTERED, &hu->flags)) > >diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h > >index fffa61f..12df101 100644 > >--- a/drivers/bluetooth/hci_uart.h > >+++ b/drivers/bluetooth/hci_uart.h > >@@ -68,6 +68,7 @@ struct hci_uart { > > unsigned long hdev_flags; > > > > struct work_struct init_ready; > >+ struct work_struct write_work; > > > > struct hci_uart_proto *proto; > > void *priv; > > > -- balbi [-- Attachment #2: Digital signature --] [-- Type: application/pgp-signature, Size: 819 bytes --] ^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2014-03-20 19:25 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-03-20 16:34 hci_ldsic nested locking problem Felipe Balbi
[not found] ` <20140320163435.GH32692-HgARHv6XitL9zxVx7UNMDg@public.gmane.org>
2014-03-20 16:42 ` Alan Cox
[not found] ` <1395333736.22077.32.camel-wU3TRTJX3O1FGiH78xh5akvbDziVy8sZEvhb3Hwu1Ks@public.gmane.org>
2014-03-20 17:16 ` Felipe Balbi
2014-03-20 17:29 ` Felipe Balbi
2014-03-20 17:34 ` Peter Hurley
2014-03-20 17:35 ` Felipe Balbi
[not found] ` <20140320173518.GD2827-HgARHv6XitL9zxVx7UNMDg@public.gmane.org>
2014-03-20 18:45 ` Greg KH
2014-03-20 18:54 ` Peter Hurley
2014-03-20 17:31 ` Peter Hurley
[not found] ` <532B25FC.3070408-WaGBZJeGNqdsbIuE7sb01tBPR1lH4CV8@public.gmane.org>
2014-03-20 18:11 ` Felipe Balbi
2014-03-20 18:21 ` Peter Hurley
2014-03-20 18:25 ` Felipe Balbi
2014-03-20 19:01 ` Felipe Balbi
2014-03-20 19:03 ` Felipe Balbi
2014-03-20 19:16 ` Peter Hurley
2014-03-20 19:25 ` Felipe Balbi
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).