Commit 8f9818af authored by Olivier Sobrie's avatar Olivier Sobrie Committed by David S. Miller

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: default avatarOlivier Sobrie <olivier@sobrie.be>
Acked-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5c763edf
...@@ -258,7 +258,6 @@ struct hso_serial { ...@@ -258,7 +258,6 @@ struct hso_serial {
* so as not to drop characters on the floor. * so as not to drop characters on the floor.
*/ */
int curr_rx_urb_idx; int curr_rx_urb_idx;
u16 curr_rx_urb_offset;
u8 rx_urb_filled[MAX_RX_URBS]; u8 rx_urb_filled[MAX_RX_URBS];
struct tasklet_struct unthrottle_tasklet; struct tasklet_struct unthrottle_tasklet;
}; };
...@@ -2001,8 +2000,7 @@ static void ctrl_callback(struct urb *urb) ...@@ -2001,8 +2000,7 @@ static void ctrl_callback(struct urb *urb)
static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
{ {
struct tty_struct *tty; struct tty_struct *tty;
int write_length_remaining = 0; int count;
int curr_write_len;
/* Sanity check */ /* Sanity check */
if (urb == NULL || serial == NULL) { if (urb == NULL || serial == NULL) {
...@@ -2012,29 +2010,28 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial) ...@@ -2012,29 +2010,28 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
tty = tty_port_tty_get(&serial->port); tty = tty_port_tty_get(&serial->port);
/* Push data to tty */
write_length_remaining = urb->actual_length -
serial->curr_rx_urb_offset;
D1("data to push to tty");
while (write_length_remaining) {
if (tty && test_bit(TTY_THROTTLED, &tty->flags)) { if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
tty_kref_put(tty); tty_kref_put(tty);
return -1; return -1;
} }
curr_write_len = tty_insert_flip_string(&serial->port,
urb->transfer_buffer + serial->curr_rx_urb_offset, /* Push data to tty */
write_length_remaining); D1("data to push to tty");
serial->curr_rx_urb_offset += curr_write_len; count = tty_buffer_request_room(&serial->port, urb->actual_length);
write_length_remaining -= curr_write_len; if (count >= urb->actual_length) {
tty_insert_flip_string(&serial->port, urb->transfer_buffer,
urb->actual_length);
tty_flip_buffer_push(&serial->port); tty_flip_buffer_push(&serial->port);
} else {
dev_warn(&serial->parent->usb->dev,
"dropping data, %d bytes lost\n", urb->actual_length);
} }
tty_kref_put(tty); tty_kref_put(tty);
if (write_length_remaining == 0) {
serial->curr_rx_urb_offset = 0;
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
}
return write_length_remaining; return 0;
} }
...@@ -2205,7 +2202,6 @@ static int hso_stop_serial_device(struct hso_device *hso_dev) ...@@ -2205,7 +2202,6 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
} }
} }
serial->curr_rx_urb_idx = 0; serial->curr_rx_urb_idx = 0;
serial->curr_rx_urb_offset = 0;
if (serial->tx_urb) if (serial->tx_urb)
usb_kill_urb(serial->tx_urb); usb_kill_urb(serial->tx_urb);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment