diff options
| -rw-r--r-- | drivers/tty/n_tty.c | 45 | ||||
| -rw-r--r-- | drivers/tty/pty.c | 1 | ||||
| -rw-r--r-- | include/linux/tty.h | 3 |
3 files changed, 34 insertions, 15 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 5793aa0d3bfb..cf6e0f2e1331 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c | |||
| @@ -1090,16 +1090,45 @@ static void eraser(unsigned char c, struct tty_struct *tty) | |||
| 1090 | * Called when a signal is being sent due to terminal input. | 1090 | * Called when a signal is being sent due to terminal input. |
| 1091 | * Called from the driver receive_buf path so serialized. | 1091 | * Called from the driver receive_buf path so serialized. |
| 1092 | * | 1092 | * |
| 1093 | * Performs input and output flush if !NOFLSH. In this context, the echo | ||
| 1094 | * buffer is 'output'. The signal is processed first to alert any current | ||
| 1095 | * readers or writers to discontinue and exit their i/o loops. | ||
| 1096 | * | ||
| 1093 | * Locking: ctrl_lock | 1097 | * Locking: ctrl_lock |
| 1094 | */ | 1098 | */ |
| 1095 | 1099 | ||
| 1096 | static void isig(int sig, struct tty_struct *tty) | 1100 | static void isig(int sig, struct tty_struct *tty) |
| 1097 | { | 1101 | { |
| 1102 | struct n_tty_data *ldata = tty->disc_data; | ||
| 1098 | struct pid *tty_pgrp = tty_get_pgrp(tty); | 1103 | struct pid *tty_pgrp = tty_get_pgrp(tty); |
| 1099 | if (tty_pgrp) { | 1104 | if (tty_pgrp) { |
| 1100 | kill_pgrp(tty_pgrp, sig, 1); | 1105 | kill_pgrp(tty_pgrp, sig, 1); |
| 1101 | put_pid(tty_pgrp); | 1106 | put_pid(tty_pgrp); |
| 1102 | } | 1107 | } |
| 1108 | |||
| 1109 | if (!L_NOFLSH(tty)) { | ||
| 1110 | up_read(&tty->termios_rwsem); | ||
| 1111 | down_write(&tty->termios_rwsem); | ||
| 1112 | |||
| 1113 | /* clear echo buffer */ | ||
| 1114 | mutex_lock(&ldata->output_lock); | ||
| 1115 | ldata->echo_head = ldata->echo_tail = 0; | ||
| 1116 | ldata->echo_mark = ldata->echo_commit = 0; | ||
| 1117 | mutex_unlock(&ldata->output_lock); | ||
| 1118 | |||
| 1119 | /* clear output buffer */ | ||
| 1120 | tty_driver_flush_buffer(tty); | ||
| 1121 | |||
| 1122 | /* clear input buffer */ | ||
| 1123 | reset_buffer_flags(tty->disc_data); | ||
| 1124 | |||
| 1125 | /* notify pty master of flush */ | ||
| 1126 | if (tty->link) | ||
| 1127 | n_tty_packet_mode_flush(tty); | ||
| 1128 | |||
| 1129 | up_write(&tty->termios_rwsem); | ||
| 1130 | down_read(&tty->termios_rwsem); | ||
| 1131 | } | ||
| 1103 | } | 1132 | } |
| 1104 | 1133 | ||
| 1105 | /** | 1134 | /** |
| @@ -1123,13 +1152,6 @@ static void n_tty_receive_break(struct tty_struct *tty) | |||
| 1123 | return; | 1152 | return; |
| 1124 | if (I_BRKINT(tty)) { | 1153 | if (I_BRKINT(tty)) { |
| 1125 | isig(SIGINT, tty); | 1154 | isig(SIGINT, tty); |
| 1126 | if (!L_NOFLSH(tty)) { | ||
| 1127 | /* flushing needs exclusive termios_rwsem */ | ||
| 1128 | up_read(&tty->termios_rwsem); | ||
| 1129 | n_tty_flush_buffer(tty); | ||
| 1130 | tty_driver_flush_buffer(tty); | ||
| 1131 | down_read(&tty->termios_rwsem); | ||
| 1132 | } | ||
| 1133 | return; | 1155 | return; |
| 1134 | } | 1156 | } |
| 1135 | if (I_PARMRK(tty)) { | 1157 | if (I_PARMRK(tty)) { |
| @@ -1203,13 +1225,7 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) | |||
| 1203 | static void | 1225 | static void |
| 1204 | n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) | 1226 | n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) |
| 1205 | { | 1227 | { |
| 1206 | if (!L_NOFLSH(tty)) { | 1228 | isig(signal, tty); |
| 1207 | /* flushing needs exclusive termios_rwsem */ | ||
| 1208 | up_read(&tty->termios_rwsem); | ||
| 1209 | n_tty_flush_buffer(tty); | ||
| 1210 | tty_driver_flush_buffer(tty); | ||
| 1211 | down_read(&tty->termios_rwsem); | ||
| 1212 | } | ||
| 1213 | if (I_IXON(tty)) | 1229 | if (I_IXON(tty)) |
| 1214 | start_tty(tty); | 1230 | start_tty(tty); |
| 1215 | if (L_ECHO(tty)) { | 1231 | if (L_ECHO(tty)) { |
| @@ -1217,7 +1233,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) | |||
| 1217 | commit_echoes(tty); | 1233 | commit_echoes(tty); |
| 1218 | } else | 1234 | } else |
| 1219 | process_echoes(tty); | 1235 | process_echoes(tty); |
| 1220 | isig(signal, tty); | ||
| 1221 | return; | 1236 | return; |
| 1222 | } | 1237 | } |
| 1223 | 1238 | ||
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 0e273158edac..e72ee629cead 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c | |||
| @@ -395,6 +395,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, | |||
| 395 | goto err_put_module; | 395 | goto err_put_module; |
| 396 | 396 | ||
| 397 | tty_set_lock_subclass(o_tty); | 397 | tty_set_lock_subclass(o_tty); |
| 398 | lockdep_set_subclass(&o_tty->termios_rwsem, TTY_LOCK_SLAVE); | ||
| 398 | 399 | ||
| 399 | if (legacy) { | 400 | if (legacy) { |
| 400 | /* We always use new tty termios data so we can do this | 401 | /* We always use new tty termios data so we can do this |
diff --git a/include/linux/tty.h b/include/linux/tty.h index 55964b9490dd..fe5623c9af71 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 | * termios_rwsem - The stable lock order is tty_buffer lock->termios_rwsem. | ||
| 29 | * Subclassing this lock enables the slave pty to hold its | ||
| 30 | * termios_rwsem when claiming the master tty_buffer lock. | ||
| 28 | * tty_buffer lock - slave ptys can claim nested buffer lock when handling | 31 | * tty_buffer lock - slave ptys can claim nested buffer lock when handling |
| 29 | * signal chars. The stable lock order is slave pty, then | 32 | * signal chars. The stable lock order is slave pty, then |
| 30 | * master. | 33 | * master. |
