Messages in this thread Patch in this message | ![/](/images/icornerl.gif) | | Date | Mon, 21 Jul 1997 18:25:01 -0400 | From | Bill Hawes <> | Subject | Re: 2.0.30 serial.c, ppp.c and pppd-2.2 questions |
| |
Hi Rob,
After studying your flip buffer overflow problem for a while, I have a theory that might explain why it's overflowing.
The flip buffer is flipped on the timer queue, and when the n_tty.c code needs to exclude input briefly, it disables the timer queue. Under heavy paging load, the system may have to service page faults while the timer queue is disabled. This means there's a slight probability that the timer queue would be disabled at the jiffy tick, so it might miss a turn.
This small probability could become significant if you have many ttys in use; if any tty gets a page fault with the queue disabled, _all_ ttys might lose their turn to flip the buffer. (Even ptys disable the timer, and they don't even use the flip buffer!). I did a test a while back to see what sections of code are interrupted by page faults while in copy_xx_user, and n_tty.c was second only after pipe.c in interruptions.
I've put together a small patch against 2.0.30 to test this out. It works by defining a per-tty disable count, so that instead of disabling the whole timer queue, only the flip code for one tty is disabled. I've tested it thoroughly for at least 30 seconds, and it didn't break anything :-) So if you feel like experimenting, this may help with the overflow problems ...
Perhaps others can comment on this, but to me it makes much more sense for a tty to disable only its own flip buffer.
Regards, Bill--- linux-2.0.30/drivers/char/n_tty.c.old Mon Sep 2 08:18:26 1996 +++ linux-2.0.30/drivers/char/n_tty.c Mon Jul 21 17:47:39 1997 @@ -40,6 +40,9 @@ #define CONSOLE_DEV MKDEV(TTY_MAJOR,0) +#define disable_flip(tty) (tty)->flip.disabled++; +#define enable_flip(tty) (tty)->flip.disabled--; + #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif @@ -859,9 +862,9 @@ while (1) { int eol; - disable_bh(TQUEUE_BH); + disable_flip(tty); if (!tty->read_cnt) { - enable_bh(TQUEUE_BH); + enable_flip(tty); break; } eol = clear_bit(tty->read_tail, @@ -870,7 +873,7 @@ tty->read_tail = ((tty->read_tail+1) & (N_TTY_BUF_SIZE-1)); tty->read_cnt--; - enable_bh(TQUEUE_BH); + enable_flip(tty); if (!eol) { put_user(c, b++); if (--nr) @@ -887,10 +890,10 @@ break; } } else { - disable_bh(TQUEUE_BH); + disable_flip(tty); copy_from_read_buf(tty, &b, &nr); copy_from_read_buf(tty, &b, &nr); - enable_bh(TQUEUE_BH); + enable_flip(tty); } /* If there is enough space in the read buffer now, let the --- linux-2.0.30/drivers/char/tty_io.c.old Thu Oct 31 07:34:58 1996 +++ linux-2.0.30/drivers/char/tty_io.c Mon Jul 21 17:42:35 1997 @@ -1721,6 +1721,12 @@ char *fp; int count; + /* + * Check the disabled count + */ + if (tty->flip.disabled) + return; + if (tty->flip.buf_num) { cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE; fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; --- linux-2.0.30/include/linux/tty.h.old Sun Apr 27 16:22:13 1997 +++ linux-2.0.30/include/linux/tty.h Mon Jul 21 17:44:17 1997 @@ -96,6 +96,7 @@ unsigned char *flag_buf_ptr; int count; int buf_num; + int disabled; }; /* | ![\](/images/icornerr.gif) |