aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2015-01-17 15:42:05 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-02-02 13:11:27 -0500
commit1d1d14da12e79a6c05fbe1a975401f0f56c93316 (patch)
tree6cbf288a73b5251633590e31da9b175be7311559
parent3abf87cd3e70009ed70a7f28c2914888a7e27332 (diff)
pty: Fix buffer flush deadlock
The pty driver does not clear its write buffer when commanded. This is to avoid an apparent deadlock between parallel flushes from both pty ends; specifically when handling either BRK or INTR input. However, parallel flushes from this source is not possible since the pty master can never be set to BRKINT or ISIG. Parallel flushes from other sources are possible but these do not threaten deadlocks. Annotate the tty buffer mutex for lockdep to represent the nested tty_buffer locking which occurs when the pty slave is processing input (its buffer mutex held) and receives INTR or BRK and acquires the linked tty buffer mutex via tty_buffer_flush(). Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/pty.c10
-rw-r--r--drivers/tty/tty_buffer.c6
-rw-r--r--include/linux/tty.h4
3 files changed, 19 insertions, 1 deletions
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index f882ac81b93a..0e273158edac 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -212,10 +212,16 @@ static int pty_signal(struct tty_struct *tty, int sig)
212static void pty_flush_buffer(struct tty_struct *tty) 212static void pty_flush_buffer(struct tty_struct *tty)
213{ 213{
214 struct tty_struct *to = tty->link; 214 struct tty_struct *to = tty->link;
215 struct tty_ldisc *ld;
215 216
216 if (!to) 217 if (!to)
217 return; 218 return;
218 /* tty_buffer_flush(to); FIXME */ 219
220 ld = tty_ldisc_ref(to);
221 tty_buffer_flush(to, ld);
222 if (ld)
223 tty_ldisc_deref(ld);
224
219 if (to->packet) { 225 if (to->packet) {
220 spin_lock_irq(&tty->ctrl_lock); 226 spin_lock_irq(&tty->ctrl_lock);
221 tty->ctrl_status |= TIOCPKT_FLUSHWRITE; 227 tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -425,6 +431,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
425 tty->port = ports[1]; 431 tty->port = ports[1];
426 o_tty->port->itty = o_tty; 432 o_tty->port->itty = o_tty;
427 433
434 tty_buffer_set_lock_subclass(o_tty->port);
435
428 tty_driver_kref_get(driver); 436 tty_driver_kref_get(driver);
429 tty->count++; 437 tty->count++;
430 o_tty->count++; 438 o_tty->count++;
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 3605103fc1ac..75661641f5fe 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -557,3 +557,9 @@ int tty_buffer_set_limit(struct tty_port *port, int limit)
557 return 0; 557 return 0;
558} 558}
559EXPORT_SYMBOL_GPL(tty_buffer_set_limit); 559EXPORT_SYMBOL_GPL(tty_buffer_set_limit);
560
561/* slave ptys can claim nested buffer lock when handling BRK and INTR */
562void tty_buffer_set_lock_subclass(struct tty_port *port)
563{
564 lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE);
565}
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 849659908f23..55964b9490dd 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -25,6 +25,9 @@
25 * 25 *
26 * legacy_mutex - Nested tty locks are necessary for releasing pty pairs. 26 * legacy_mutex - Nested tty locks are necessary for releasing pty pairs.
27 * The stable lock order is master pty first, then slave pty. 27 * The stable lock order is master pty first, then slave pty.
28 * tty_buffer lock - slave ptys can claim nested buffer lock when handling
29 * signal chars. The stable lock order is slave pty, then
30 * master.
28 */ 31 */
29 32
30enum { 33enum {
@@ -460,6 +463,7 @@ extern void tty_flush_to_ldisc(struct tty_struct *tty);
460extern void tty_buffer_free_all(struct tty_port *port); 463extern void tty_buffer_free_all(struct tty_port *port);
461extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); 464extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld);
462extern void tty_buffer_init(struct tty_port *port); 465extern void tty_buffer_init(struct tty_port *port);
466extern void tty_buffer_set_lock_subclass(struct tty_port *port);
463extern speed_t tty_termios_baud_rate(struct ktermios *termios); 467extern speed_t tty_termios_baud_rate(struct ktermios *termios);
464extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); 468extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
465extern void tty_termios_encode_baud_rate(struct ktermios *termios, 469extern void tty_termios_encode_baud_rate(struct ktermios *termios,