aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/n_tty.c
diff options
context:
space:
mode:
authorJoe Peterson <joe@skyrush.com>2009-01-02 08:43:32 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-02 13:19:37 -0500
commitacc71bbad33478973dbed68ebbc2d76dac9a51bd (patch)
tree6cf78a3f0de9811bdc30739ccd01a4db6c4b3baf /drivers/char/n_tty.c
parenta59c0d6f14315a3f300f6f3786137213727e4c47 (diff)
n_tty: Fix hanfling of buffer full corner cases
Fix the handling of input characters when the tty buffer is full or nearly full. This includes tests that are done in n_tty_receive_char() and handling of PARMRK. Problems with the buffer-full tests done in receive_char() caused characters to be lost at times when the buffer(s) filled. Also, these full conditions would often only be detected with echo on, and PARMRK was not accounted for properly in all cases. One symptom of these problems, in addition to lost characters, was early termination from unix commands like tr and cat when ^Q was used to break from a stopped tty with full buffers (note that breaking out was often previously not possible, due to the pty getting in "gridlock", which will be addressed in another patch). Note space is always reserved at the end of the buffer for a newline (or EOF/EOL) in canonical mode. Signed-off-by: Joe Peterson <joe@skyrush.com> Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/n_tty.c')
-rw-r--r--drivers/char/n_tty.c55
1 files changed, 38 insertions, 17 deletions
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 30b0426b3788..4b1e96b65ab0 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -1107,6 +1107,7 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty,
1107static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) 1107static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
1108{ 1108{
1109 unsigned long flags; 1109 unsigned long flags;
1110 int parmrk;
1110 1111
1111 if (tty->raw) { 1112 if (tty->raw) {
1112 put_tty_queue(c, tty); 1113 put_tty_queue(c, tty);
@@ -1144,21 +1145,24 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
1144 */ 1145 */
1145 if (!test_bit(c, tty->process_char_map) || tty->lnext) { 1146 if (!test_bit(c, tty->process_char_map) || tty->lnext) {
1146 tty->lnext = 0; 1147 tty->lnext = 0;
1147 if (L_ECHO(tty)) { 1148 parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
1148 finish_erasing(tty); 1149 if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
1149 if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { 1150 /* beep if no space */
1150 /* beep if no space */ 1151 if (L_ECHO(tty)) {
1151 echo_char_raw('\a', tty); 1152 echo_char_raw('\a', tty);
1152 process_echoes(tty); 1153 process_echoes(tty);
1153 return;
1154 } 1154 }
1155 return;
1156 }
1157 if (L_ECHO(tty)) {
1158 finish_erasing(tty);
1155 /* Record the column of first canon char. */ 1159 /* Record the column of first canon char. */
1156 if (tty->canon_head == tty->read_head) 1160 if (tty->canon_head == tty->read_head)
1157 echo_set_canon_col(tty); 1161 echo_set_canon_col(tty);
1158 echo_char(c, tty); 1162 echo_char(c, tty);
1159 process_echoes(tty); 1163 process_echoes(tty);
1160 } 1164 }
1161 if (I_PARMRK(tty) && c == (unsigned char) '\377') 1165 if (parmrk)
1162 put_tty_queue(c, tty); 1166 put_tty_queue(c, tty);
1163 put_tty_queue(c, tty); 1167 put_tty_queue(c, tty);
1164 return; 1168 return;
@@ -1250,15 +1254,22 @@ send_signal:
1250 return; 1254 return;
1251 } 1255 }
1252 if (c == '\n') { 1256 if (c == '\n') {
1253 if (L_ECHO(tty) || L_ECHONL(tty)) { 1257 if (tty->read_cnt >= N_TTY_BUF_SIZE) {
1254 if (tty->read_cnt >= N_TTY_BUF_SIZE-1) 1258 if (L_ECHO(tty)) {
1255 echo_char_raw('\a', tty); 1259 echo_char_raw('\a', tty);
1260 process_echoes(tty);
1261 }
1262 return;
1263 }
1264 if (L_ECHO(tty) || L_ECHONL(tty)) {
1256 echo_char_raw('\n', tty); 1265 echo_char_raw('\n', tty);
1257 process_echoes(tty); 1266 process_echoes(tty);
1258 } 1267 }
1259 goto handle_newline; 1268 goto handle_newline;
1260 } 1269 }
1261 if (c == EOF_CHAR(tty)) { 1270 if (c == EOF_CHAR(tty)) {
1271 if (tty->read_cnt >= N_TTY_BUF_SIZE)
1272 return;
1262 if (tty->canon_head != tty->read_head) 1273 if (tty->canon_head != tty->read_head)
1263 set_bit(TTY_PUSH, &tty->flags); 1274 set_bit(TTY_PUSH, &tty->flags);
1264 c = __DISABLED_CHAR; 1275 c = __DISABLED_CHAR;
@@ -1266,12 +1277,19 @@ send_signal:
1266 } 1277 }
1267 if ((c == EOL_CHAR(tty)) || 1278 if ((c == EOL_CHAR(tty)) ||
1268 (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) { 1279 (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
1280 parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
1281 ? 1 : 0;
1282 if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
1283 if (L_ECHO(tty)) {
1284 echo_char_raw('\a', tty);
1285 process_echoes(tty);
1286 }
1287 return;
1288 }
1269 /* 1289 /*
1270 * XXX are EOL_CHAR and EOL2_CHAR echoed?!? 1290 * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
1271 */ 1291 */
1272 if (L_ECHO(tty)) { 1292 if (L_ECHO(tty)) {
1273 if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
1274 echo_char_raw('\a', tty);
1275 /* Record the column of first canon char. */ 1293 /* Record the column of first canon char. */
1276 if (tty->canon_head == tty->read_head) 1294 if (tty->canon_head == tty->read_head)
1277 echo_set_canon_col(tty); 1295 echo_set_canon_col(tty);
@@ -1282,7 +1300,7 @@ send_signal:
1282 * XXX does PARMRK doubling happen for 1300 * XXX does PARMRK doubling happen for
1283 * EOL_CHAR and EOL2_CHAR? 1301 * EOL_CHAR and EOL2_CHAR?
1284 */ 1302 */
1285 if (I_PARMRK(tty) && c == (unsigned char) '\377') 1303 if (parmrk)
1286 put_tty_queue(c, tty); 1304 put_tty_queue(c, tty);
1287 1305
1288handle_newline: 1306handle_newline:
@@ -1299,14 +1317,17 @@ handle_newline:
1299 } 1317 }
1300 } 1318 }
1301 1319
1302 if (L_ECHO(tty)) { 1320 parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
1303 finish_erasing(tty); 1321 if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
1304 if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { 1322 /* beep if no space */
1305 /* beep if no space */ 1323 if (L_ECHO(tty)) {
1306 echo_char_raw('\a', tty); 1324 echo_char_raw('\a', tty);
1307 process_echoes(tty); 1325 process_echoes(tty);
1308 return;
1309 } 1326 }
1327 return;
1328 }
1329 if (L_ECHO(tty)) {
1330 finish_erasing(tty);
1310 if (c == '\n') 1331 if (c == '\n')
1311 echo_char_raw('\n', tty); 1332 echo_char_raw('\n', tty);
1312 else { 1333 else {
@@ -1318,7 +1339,7 @@ handle_newline:
1318 process_echoes(tty); 1339 process_echoes(tty);
1319 } 1340 }
1320 1341
1321 if (I_PARMRK(tty) && c == (unsigned char) '\377') 1342 if (parmrk)
1322 put_tty_queue(c, tty); 1343 put_tty_queue(c, tty);
1323 1344
1324 put_tty_queue(c, tty); 1345 put_tty_queue(c, tty);