aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2009-06-11 07:44:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-11 11:50:59 -0400
commit38db89799bdf11625a831c5af33938dcb11908b6 (patch)
treec50eff175df0fbe9270ef461962030d6bdfad674
parent5b0ed5263cb089500052f8c1ab6e0706bebf0d83 (diff)
tty: throttling race fix
The tty throttling code can race due to the lock drops. It takes very high loads but this has been observed and verified by Rob Duncan. The basic problem is that on an SMP box we can go CPU #1 CPU #2 need to throttle ? suppose we should buffer space cleared are we throttled yes ? - unthrottle call throttle method This changeet take the termios lock to protect against this. The termios lock isn't the initial obvious candidate but many implementations of throttle methods already need to poke around their own termios structures (and nobody really locks them against a racing change of flow control). This does mean that anyone who is setting tty->low_latency = 1 and then calling tty_flip_buffer_push from their unthrottle method is going to end up collapsing in a pile of locks. However we've removed all the known bogus users of low_latency = 1 and such use isn't safe anyway for other reasons so catching it would be an improvement. Signed-off-by: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/char/tty_ioctl.c13
-rw-r--r--include/linux/tty_driver.h6
2 files changed, 17 insertions, 2 deletions
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 6f4c7d0a53bf..2401dbcbee9c 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -97,14 +97,19 @@ EXPORT_SYMBOL(tty_driver_flush_buffer);
97 * @tty: terminal 97 * @tty: terminal
98 * 98 *
99 * Indicate that a tty should stop transmitting data down the stack. 99 * Indicate that a tty should stop transmitting data down the stack.
100 * Takes the termios mutex to protect against parallel throttle/unthrottle
101 * and also to ensure the driver can consistently reference its own
102 * termios data at this point when implementing software flow control.
100 */ 103 */
101 104
102void tty_throttle(struct tty_struct *tty) 105void tty_throttle(struct tty_struct *tty)
103{ 106{
107 mutex_lock(&tty->termios_mutex);
104 /* check TTY_THROTTLED first so it indicates our state */ 108 /* check TTY_THROTTLED first so it indicates our state */
105 if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && 109 if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
106 tty->ops->throttle) 110 tty->ops->throttle)
107 tty->ops->throttle(tty); 111 tty->ops->throttle(tty);
112 mutex_unlock(&tty->termios_mutex);
108} 113}
109EXPORT_SYMBOL(tty_throttle); 114EXPORT_SYMBOL(tty_throttle);
110 115
@@ -113,13 +118,21 @@ EXPORT_SYMBOL(tty_throttle);
113 * @tty: terminal 118 * @tty: terminal
114 * 119 *
115 * Indicate that a tty may continue transmitting data down the stack. 120 * Indicate that a tty may continue transmitting data down the stack.
121 * Takes the termios mutex to protect against parallel throttle/unthrottle
122 * and also to ensure the driver can consistently reference its own
123 * termios data at this point when implementing software flow control.
124 *
125 * Drivers should however remember that the stack can issue a throttle,
126 * then change flow control method, then unthrottle.
116 */ 127 */
117 128
118void tty_unthrottle(struct tty_struct *tty) 129void tty_unthrottle(struct tty_struct *tty)
119{ 130{
131 mutex_lock(&tty->termios_mutex);
120 if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && 132 if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
121 tty->ops->unthrottle) 133 tty->ops->unthrottle)
122 tty->ops->unthrottle(tty); 134 tty->ops->unthrottle(tty);
135 mutex_unlock(&tty->termios_mutex);
123} 136}
124EXPORT_SYMBOL(tty_unthrottle); 137EXPORT_SYMBOL(tty_unthrottle);
125 138
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index bcba84ea2d86..3566129384a4 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -127,7 +127,8 @@
127 * the line discipline are close to full, and it should somehow 127 * the line discipline are close to full, and it should somehow
128 * signal that no more characters should be sent to the tty. 128 * signal that no more characters should be sent to the tty.
129 * 129 *
130 * Optional: Always invoke via tty_throttle(); 130 * Optional: Always invoke via tty_throttle(), called under the
131 * termios lock.
131 * 132 *
132 * void (*unthrottle)(struct tty_struct * tty); 133 * void (*unthrottle)(struct tty_struct * tty);
133 * 134 *
@@ -135,7 +136,8 @@
135 * that characters can now be sent to the tty without fear of 136 * that characters can now be sent to the tty without fear of
136 * overrunning the input buffers of the line disciplines. 137 * overrunning the input buffers of the line disciplines.
137 * 138 *
138 * Optional: Always invoke via tty_unthrottle(); 139 * Optional: Always invoke via tty_unthrottle(), called under the
140 * termios lock.
139 * 141 *
140 * void (*stop)(struct tty_struct *tty); 142 * void (*stop)(struct tty_struct *tty);
141 * 143 *