diff options
author | Olivier Sobrie <olivier@sobrie.be> | 2014-07-14 06:08:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-14 22:27:34 -0400 |
commit | 8f9818af4eaef1150282e18355aaea425474a411 (patch) | |
tree | 6dd457dfe72ca88b65ce041afe5124271f98f7ab /drivers/net/usb | |
parent | 5c763edfe4879ffc3a87fef64f743d4b5497aabb (diff) |
hso: fix deadlock when receiving bursts of data
When the module sends bursts of data, sometimes a deadlock happens in
the hso driver when the tty buffer doesn't get the chance to be flushed
quickly enough.
Remove the endless while loop in function put_rxbuf_data() which is
called by the urb completion handler.
If there isn't enough room in the tty buffer, discards all the data
received in the URB.
Cc: David Miller <davem@davemloft.net>
Cc: David Laight <David.Laight@ACULAB.COM>
Cc: One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk>
Cc: Dan Williams <dcbw@redhat.com>
Cc: Jan Dumon <j.dumon@option.com>
Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r-- | drivers/net/usb/hso.c | 38 |
1 files changed, 17 insertions, 21 deletions
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 9ca2b418a3ee..a4272ed62da8 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c | |||
@@ -258,7 +258,6 @@ struct hso_serial { | |||
258 | * so as not to drop characters on the floor. | 258 | * so as not to drop characters on the floor. |
259 | */ | 259 | */ |
260 | int curr_rx_urb_idx; | 260 | int curr_rx_urb_idx; |
261 | u16 curr_rx_urb_offset; | ||
262 | u8 rx_urb_filled[MAX_RX_URBS]; | 261 | u8 rx_urb_filled[MAX_RX_URBS]; |
263 | struct tasklet_struct unthrottle_tasklet; | 262 | struct tasklet_struct unthrottle_tasklet; |
264 | }; | 263 | }; |
@@ -2001,8 +2000,7 @@ static void ctrl_callback(struct urb *urb) | |||
2001 | static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) | 2000 | static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) |
2002 | { | 2001 | { |
2003 | struct tty_struct *tty; | 2002 | struct tty_struct *tty; |
2004 | int write_length_remaining = 0; | 2003 | int count; |
2005 | int curr_write_len; | ||
2006 | 2004 | ||
2007 | /* Sanity check */ | 2005 | /* Sanity check */ |
2008 | if (urb == NULL || serial == NULL) { | 2006 | if (urb == NULL || serial == NULL) { |
@@ -2012,29 +2010,28 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) | |||
2012 | 2010 | ||
2013 | tty = tty_port_tty_get(&serial->port); | 2011 | tty = tty_port_tty_get(&serial->port); |
2014 | 2012 | ||
2013 | if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { | ||
2014 | tty_kref_put(tty); | ||
2015 | return -1; | ||
2016 | } | ||
2017 | |||
2015 | /* Push data to tty */ | 2018 | /* Push data to tty */ |
2016 | write_length_remaining = urb->actual_length - | ||
2017 | serial->curr_rx_urb_offset; | ||
2018 | D1("data to push to tty"); | 2019 | D1("data to push to tty"); |
2019 | while (write_length_remaining) { | 2020 | count = tty_buffer_request_room(&serial->port, urb->actual_length); |
2020 | if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { | 2021 | if (count >= urb->actual_length) { |
2021 | tty_kref_put(tty); | 2022 | tty_insert_flip_string(&serial->port, urb->transfer_buffer, |
2022 | return -1; | 2023 | urb->actual_length); |
2023 | } | ||
2024 | curr_write_len = tty_insert_flip_string(&serial->port, | ||
2025 | urb->transfer_buffer + serial->curr_rx_urb_offset, | ||
2026 | write_length_remaining); | ||
2027 | serial->curr_rx_urb_offset += curr_write_len; | ||
2028 | write_length_remaining -= curr_write_len; | ||
2029 | tty_flip_buffer_push(&serial->port); | 2024 | tty_flip_buffer_push(&serial->port); |
2025 | } else { | ||
2026 | dev_warn(&serial->parent->usb->dev, | ||
2027 | "dropping data, %d bytes lost\n", urb->actual_length); | ||
2030 | } | 2028 | } |
2029 | |||
2031 | tty_kref_put(tty); | 2030 | tty_kref_put(tty); |
2032 | 2031 | ||
2033 | if (write_length_remaining == 0) { | 2032 | serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; |
2034 | serial->curr_rx_urb_offset = 0; | 2033 | |
2035 | serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; | 2034 | return 0; |
2036 | } | ||
2037 | return write_length_remaining; | ||
2038 | } | 2035 | } |
2039 | 2036 | ||
2040 | 2037 | ||
@@ -2205,7 +2202,6 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) | |||
2205 | } | 2202 | } |
2206 | } | 2203 | } |
2207 | serial->curr_rx_urb_idx = 0; | 2204 | serial->curr_rx_urb_idx = 0; |
2208 | serial->curr_rx_urb_offset = 0; | ||
2209 | 2205 | ||
2210 | if (serial->tx_urb) | 2206 | if (serial->tx_urb) |
2211 | usb_kill_urb(serial->tx_urb); | 2207 | usb_kill_urb(serial->tx_urb); |