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. |