From: Roman Zippel <zippel@linux-m68k.org>

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

Alan said:

The problem looks valid. The behaviour of 'traditional unix' appears to
be the following

	If you exceed the line limit then beep and drop the character
	Always allow EOL to complete a canonical line input
	Always do signal/control processing if enabled


Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 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	2005-03-16 21:42:03.000000000 -0800
+++ 25-akpm/drivers/char/n_tty.c	2005-03-16 21:42:03.000000000 -0800
@@ -770,10 +770,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;
@@ -790,10 +788,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;
@@ -862,12 +858,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;
 }
 
 /**
@@ -1473,13 +1466,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;
_