aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/tty/n_tty.c45
-rw-r--r--drivers/tty/pty.c1
-rw-r--r--include/linux/tty.h3
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
1096static void isig(int sig, struct tty_struct *tty) 1100static 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)
1203static void 1225static void
1204n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) 1226n_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.