From: Roman Zippel > Does that make sense to you? Maybe the "input full, but no canon_data" > special case would be better handled in the read path, rather than the > write path? There might be no reader at this time. The basic problem is that this should be handled in the receive_buf path, but for that it had to return the numbers of characters written (or dropped in the no canon_data case). Relying on receive_room value instead is rather bogus. Below is a new patch, which also fixes problems with very long lines. 1. if receive_room() returns a small number, write_chan() has to continue writing, otherwise it will sleep with nobody waking it up. 2. we mustn't simply drop eol characters in n_tty_receive_char otherwise canon_data isn't increased and the reader isn't woken up. Signed-off-by: Andrew Morton --- 25-akpm/drivers/char/n_tty.c | 33 +++++++++++++++------------------ 1 files changed, 15 insertions(+), 18 deletions(-) diff -puN drivers/char/n_tty.c~tty-output-lossage-fix drivers/char/n_tty.c --- 25/drivers/char/n_tty.c~tty-output-lossage-fix Wed Feb 16 14:51:23 2005 +++ 25-akpm/drivers/char/n_tty.c Wed Feb 16 14:51:23 2005 @@ -768,10 +768,8 @@ send_signal: } if (c == '\n') { if (L_ECHO(tty) || L_ECHONL(tty)) { - if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) put_char('\a', tty); - return; - } opost('\n', tty); } goto handle_newline; @@ -788,10 +786,8 @@ send_signal: * XXX are EOL_CHAR and EOL2_CHAR echoed?!? */ if (L_ECHO(tty)) { - if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { + if (tty->read_cnt >= N_TTY_BUF_SIZE-1) put_char('\a', tty); - return; - } /* Record the column of first canon char. */ if (tty->canon_head == tty->read_head) tty->canon_column = tty->column; @@ -860,12 +856,9 @@ static int n_tty_receive_room(struct tty * that erase characters will be handled. Other excess * characters will be beeped. */ - if (tty->icanon && !tty->canon_data) - return N_TTY_BUF_SIZE; - - if (left > 0) - return left; - return 0; + if (left <= 0) + left = tty->icanon && !tty->canon_data; + return left; } /** @@ -1471,13 +1464,17 @@ static ssize_t write_chan(struct tty_str if (tty->driver->flush_chars) tty->driver->flush_chars(tty); } else { - c = tty->driver->write(tty, b, nr); - if (c < 0) { - retval = c; - goto break_out; + while (nr > 0) { + c = tty->driver->write(tty, b, nr); + if (c < 0) { + retval = c; + goto break_out; + } + if (!c) + break; + b += c; + nr -= c; } - b += c; - nr -= c; } if (!nr) break; _