summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2013-03-06 08:20:53 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-18 16:11:59 -0700
commite91e52e42814b130c20d17bc1e2adf813c50db11 (patch)
tree3459953655d71ed43cedd3ecdc9fe637b7960bd0
parent70bc126471af30bb115e635512dcf6d86fe6e29a (diff)
n_tty: Fix stuck throttled driver
As noted in the following comment: /* FIXME: there is a tiny race here if the receive room check runs before the other work executes and empties the buffer (upping the receiving room and unthrottling. We then throttle and get stuck. This has been observed and traced down by Vincent Pillet/ We need to address this when we sort out out the rx path locking */ Use new safe throttle/unthrottle functions to re-evaluate conditions if interrupted by the complement flow control function. Reported-by: Vincent Pillet <vincentx.pillet@intel.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/n_tty.c28
1 files changed, 17 insertions, 11 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 7fbad56db7c..e3a9321f7f8 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1468,14 +1468,14 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
* mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet!
*/
- if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
- tty_throttle(tty);
-
- /* FIXME: there is a tiny race here if the receive room check runs
- before the other work executes and empties the buffer (upping
- the receiving room and unthrottling. We then throttle and get
- stuck. This has been observed and traced down by Vincent Pillet/
- We need to address this when we sort out out the rx path locking */
+ while (1) {
+ tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
+ if (tty->receive_room >= TTY_THRESHOLD_THROTTLE)
+ break;
+ if (!tty_throttle_safe(tty))
+ break;
+ }
+ __tty_set_flow_change(tty, 0);
}
int is_ignored(int sig)
@@ -1944,11 +1944,17 @@ do_it_again:
* longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
* we won't get any more characters.
*/
- if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
+ while (1) {
+ tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
+ if (n_tty_chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
+ break;
+ if (!tty->count)
+ break;
n_tty_set_room(tty);
- if (tty->count)
- tty_unthrottle(tty);
+ if (!tty_unthrottle_safe(tty))
+ break;
}
+ __tty_set_flow_change(tty, 0);
if (b - buf >= minimum)
break;