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) static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; + struct tty_ldisc *ld; if (!to) return; - /* tty_buffer_flush(to); FIXME */ + + ld = tty_ldisc_ref(to); + tty_buffer_flush(to, ld); + if (ld) + tty_ldisc_deref(ld); + if (to->packet) { spin_lock_irq(&tty->ctrl_lock); tty->ctrl_status |= TIOCPKT_FLUSHWRITE; @@ -425,6 +431,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, tty->port = ports[1]; o_tty->port->itty = o_tty; + tty_buffer_set_lock_subclass(o_tty->port); + tty_driver_kref_get(driver); tty->count++; 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) return 0; } EXPORT_SYMBOL_GPL(tty_buffer_set_limit); + +/* slave ptys can claim nested buffer lock when handling BRK and INTR */ +void tty_buffer_set_lock_subclass(struct tty_port *port) +{ + lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE); +} 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 @@ * * legacy_mutex - Nested tty locks are necessary for releasing pty pairs. * The stable lock order is master pty first, then slave pty. + * tty_buffer lock - slave ptys can claim nested buffer lock when handling + * signal chars. The stable lock order is slave pty, then + * master. */ enum { @@ -460,6 +463,7 @@ extern void tty_flush_to_ldisc(struct tty_struct *tty); extern void tty_buffer_free_all(struct tty_port *port); extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); extern void tty_buffer_init(struct tty_port *port); +extern void tty_buffer_set_lock_subclass(struct tty_port *port); extern speed_t tty_termios_baud_rate(struct ktermios *termios); extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); extern void tty_termios_encode_baud_rate(struct ktermios *termios,