Skip to content

Commit 1d1d14d

Browse files
peterhurleygregkh
authored andcommitted
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 <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 3abf87c commit 1d1d14d

File tree

3 files changed

+19
-1
lines changed

3 files changed

+19
-1
lines changed

drivers/tty/pty.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,16 @@ static int pty_signal(struct tty_struct *tty, int sig)
212212
static void pty_flush_buffer(struct tty_struct *tty)
213213
{
214214
struct tty_struct *to = tty->link;
215+
struct tty_ldisc *ld;
215216

216217
if (!to)
217218
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+
219225
if (to->packet) {
220226
spin_lock_irq(&tty->ctrl_lock);
221227
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -425,6 +431,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
425431
tty->port = ports[1];
426432
o_tty->port->itty = o_tty;
427433

434+
tty_buffer_set_lock_subclass(o_tty->port);
435+
428436
tty_driver_kref_get(driver);
429437
tty->count++;
430438
o_tty->count++;

drivers/tty/tty_buffer.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,3 +557,9 @@ int tty_buffer_set_limit(struct tty_port *port, int limit)
557557
return 0;
558558
}
559559
EXPORT_SYMBOL_GPL(tty_buffer_set_limit);
560+
561+
/* slave ptys can claim nested buffer lock when handling BRK and INTR */
562+
void tty_buffer_set_lock_subclass(struct tty_port *port)
563+
{
564+
lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE);
565+
}

include/linux/tty.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@
2525
*
2626
* legacy_mutex - Nested tty locks are necessary for releasing pty pairs.
2727
* 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.
2831
*/
2932

3033
enum {
@@ -460,6 +463,7 @@ extern void tty_flush_to_ldisc(struct tty_struct *tty);
460463
extern void tty_buffer_free_all(struct tty_port *port);
461464
extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld);
462465
extern void tty_buffer_init(struct tty_port *port);
466+
extern void tty_buffer_set_lock_subclass(struct tty_port *port);
463467
extern speed_t tty_termios_baud_rate(struct ktermios *termios);
464468
extern speed_t tty_termios_input_baud_rate(struct ktermios *termios);
465469
extern void tty_termios_encode_baud_rate(struct ktermios *termios,

0 commit comments

Comments
 (0)