Patchs to the tty layer...

tytso@mit.edu
Fri, 8 Jan 1999 08:29:24 -0500


Hi Linus,

Here are my final set of patches to the tty code for 2.2.0. I
apologize that it's taken a while before I was ready to send these to
you. A combination of pre-Christmastime busyness plus my travel
schedule meant that I didn't have time to do final review on this until
now.

There are several changes bundled up into this one patch. I think they
are all safe for application into Linux 2.2.0, but if you want to pass
on one or more of them for 2.2.0, let me know and I can resend you a
patch with those changes taken out. (I've sent them to you in one whole
chunk because changes are all intertwined in the tty files.)

1) I've fixed up the comments and made one change to the code conerning
how the console driver access the ttytab array without knowing
whether or not the tty is actually opened, and possibly calling tty
functions on a closed tty. The comments are wrong; the keyboard
driver is committing an abstraction violation by trying to access
the tty directly. Fixing it would require messing with too much of
the code, so I've cleaned up the comments and changed the console
driver to clear tty->private_data when it closes the last tty on the
console driver. This will prevent the keyboard layer from trying to
call the tty functions on a closed tty.

2) I've added a new tty flag, TTY_DONT_FLIP, which suspends n_tty
buffer handling on a per-tty basis, instead of disabling all n_tty
buffer handling via diable_bh(TQUEUE_BH).

3) I've addressed the race condition pointed out by Andreas Schwab,
where if one process try to read from the tty() while copy_to_user()
sleeps, tty->read_cnt can go negative.

4) I've added support for some standard higher speed baud rates, both
in the termbits files and in the central tty routines which convert
the CBAUD bits to a buad rate. Since making changes here requires
libc changes before an application program can use them, it's better
to add these new baud rates now so that the libc folks can pick up
the changes and add support into newer libraries. I've checked
through various UART data sheets and these are the most commonly
used baud rates. (In the long term, we really are going to have to
put an integer field containing desired input and output baud rate
into the termios structure; but as this requires adding a new
structure, it's going to be a real pain.)

I've been running with all of these changes for quite a while now
(before 2.1.128 or so), so I'm quite confident they're stable.

- Ted

Patch generated: on Fri Jan 8 08:06:37 EST 1999 by tytso@rsts-11.mit.edu
against Linux version 2.2.0

===================================================================
RCS file: drivers/char/RCS/keyboard.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/keyboard.c
--- drivers/char/keyboard.c 1999/01/06 18:58:40 1.1
+++ drivers/char/keyboard.c 1999/01/06 18:58:50
@@ -202,8 +202,13 @@

tty = ttytab? ttytab[fg_console]: NULL;
if (tty && (!tty->driver_data)) {
- /* This is to workaround ugly bug in tty_io.c, which
- does not do locking when it should */
+ /*
+ * We touch the tty structure via the the ttytab array
+ * without knowing whether or not tty is open, which
+ * is inherently dangerous. We currently rely on that
+ * fact that console_open sets tty->driver_data when
+ * it opens it, and clears it when it closes it.
+ */
tty = NULL;
}
kbd = kbd_table + fg_console;
===================================================================
RCS file: drivers/char/RCS/console.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/console.c
--- drivers/char/console.c 1999/01/06 18:58:40 1.1
+++ drivers/char/console.c 1999/01/06 18:58:50
@@ -2231,6 +2231,12 @@
return 0;
}

+static void con_close(struct tty_struct *tty, struct file * filp)
+{
+ if (tty->count == 1)
+ tty->driver_data = 0;
+}
+
static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear)
{
int j, k ;
@@ -2292,6 +2298,7 @@
console_driver.termios_locked = console_termios_locked;

console_driver.open = con_open;
+ console_driver.close = con_close;
console_driver.write = con_write;
console_driver.write_room = con_write_room;
console_driver.put_char = con_put_char;
===================================================================
RCS file: drivers/char/RCS/tty_io.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/tty_io.c
--- drivers/char/tty_io.c 1999/01/06 18:58:40 1.1
+++ drivers/char/tty_io.c 1999/01/06 18:58:51
@@ -866,12 +866,7 @@
* Failures after this point use release_mem to clean up, so
* there's no need to null out the local pointers.
*/
- driver->table[idx] = tty; /* FIXME: this is broken and
- probably causes ^D bug. tty->private_date does not (yet) point
- to a console, if keypress comes now, await armagedon.
-
- also, driver->table is accessed from interrupt for vt case,
- and this does not look like atomic access at all. */
+ driver->table[idx] = tty;

if (!*tp_loc)
*tp_loc = tp;
@@ -1846,6 +1841,10 @@
int count;
unsigned long flags;

+ if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
+ queue_task(&tty->flip.tqueue, &tq_timer);
+ return;
+ }
if (tty->flip.buf_num) {
cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
@@ -1872,14 +1871,22 @@

/*
* Routine which returns the baud rate of the tty
- */
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
+ *
+ * Note that the baud_table needs to be kept in sync with the
+ * include/asm/termbits.h file.
*/
static int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+ 9600, 19200, 38400, 57600, 115200, 230400, 460800,
+#ifdef __sparc__
+ 76800, 153600, 307200, 614400, 921600
+#else
+ 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
+ 2500000, 3000000, 3500000, 4000000
+#endif
+};
+
+static int n_baud_table = sizeof(baud_table)/sizeof(int);

int tty_get_baud_rate(struct tty_struct *tty)
{
@@ -1890,7 +1897,7 @@
i = cflag & CBAUD;
if (i & CBAUDEX) {
i &= ~CBAUDEX;
- if (i < 1 || i > 4)
+ if (i < 1 || i+15 >= n_baud_table)
tty->termios->c_cflag &= ~CBAUDEX;
else
i += 15;
@@ -1930,6 +1937,7 @@
tty->flip.pty_sem = MUTEX;
tty->tq_hangup.routine = do_tty_hangup;
tty->tq_hangup.data = tty;
+ sema_init(&tty->atomic_read, 1);
}

/*
===================================================================
RCS file: drivers/char/RCS/n_tty.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/n_tty.c
--- drivers/char/n_tty.c 1999/01/06 18:58:41 1.1
+++ drivers/char/n_tty.c 1999/01/06 18:58:51
@@ -73,7 +73,8 @@
*/
static void check_unthrottle(struct tty_struct * tty)
{
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+ if (tty->count &&
+ test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
tty->driver.unthrottle)
tty->driver.unthrottle(tty);
}
@@ -923,15 +924,19 @@

add_wait_queue(&tty->read_wait, &wait);

- disable_bh(TQUEUE_BH);
+ if (down_interruptible(&tty->atomic_read))
+ return -ERESTARTSYS;
+ set_bit(TTY_DONT_FLIP, &tty->flags);
while (nr) {
/* First test for status change. */
if (tty->packet && tty->link->ctrl_status) {
+ unsigned char cs;
if (b != buf)
break;
- put_user(tty->link->ctrl_status, b++);
- nr--;
+ cs = tty->link->ctrl_status;
tty->link->ctrl_status = 0;
+ put_user(cs, b++);
+ nr--;
break;
}
/* This statement must be first before checking for input
@@ -960,9 +965,9 @@
retval = -ERESTARTSYS;
break;
}
- enable_bh(TQUEUE_BH);
+ clear_bit(TTY_DONT_FLIP, &tty->flags);
timeout = schedule_timeout(timeout);
- disable_bh(TQUEUE_BH);
+ set_bit(TTY_DONT_FLIP, &tty->flags);
continue;
}
current->state = TASK_RUNNING;
@@ -1024,7 +1029,8 @@
if (time)
timeout = time;
}
- enable_bh(TQUEUE_BH);
+ clear_bit(TTY_DONT_FLIP, &tty->flags);
+ up(&tty->atomic_read);
remove_wait_queue(&tty->read_wait, &wait);

if (!waitqueue_active(&tty->read_wait))
===================================================================
RCS file: include/linux/RCS/tty.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/tty.h
--- include/linux/tty.h 1999/01/06 18:58:41 1.1
+++ include/linux/tty.h 1999/01/06 19:21:36
@@ -299,6 +299,7 @@
int canon_data;
unsigned long canon_head;
unsigned int canon_column;
+ struct semaphore atomic_read;
};

/* tty magic number */
@@ -320,6 +321,7 @@
#define TTY_DO_WRITE_WAKEUP 5
#define TTY_PUSH 6
#define TTY_CLOSING 7
+#define TTY_DONT_FLIP 8
#define TTY_HW_COOK_OUT 14
#define TTY_HW_COOK_IN 15
#define TTY_PTY_LOCK 16
===================================================================
RCS file: include/asm-i386/RCS/termbits.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-i386/termbits.h
--- include/asm-i386/termbits.h 1999/01/06 18:58:41 1.1
+++ include/asm-i386/termbits.h 1999/01/06 18:58:51
@@ -117,10 +117,21 @@
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
-#define B57600 0010001
-#define B115200 0010002
-#define B230400 0010003
-#define B460800 0010004
+#define B57600 0010001
+#define B115200 0010002
+#define B230400 0010003
+#define B460800 0010004
+#define B500000 0010005
+#define B576000 0010006
+#define B921600 0010007
+#define B1000000 0010010
+#define B1152000 0010011
+#define B1500000 0010012
+#define B2000000 0010013
+#define B2500000 0010014
+#define B3000000 0010015
+#define B3500000 0010016
+#define B4000000 0010017
#define CIBAUD 002003600000 /* input baud rate (not used) */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
===================================================================
RCS file: include/asm-alpha/RCS/termbits.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-alpha/termbits.h
--- include/asm-alpha/termbits.h 1999/01/06 18:58:41 1.1
+++ include/asm-alpha/termbits.h 1999/01/06 18:58:51
@@ -125,6 +125,17 @@
#define B115200 00021
#define B230400 00022
#define B460800 00023
+#define B500000 00024
+#define B576000 00025
+#define B921600 00026
+#define B1000000 00027
+#define B1152000 00030
+#define B1500000 00031
+#define B2000000 00032
+#define B2500000 00033
+#define B3000000 00034
+#define B3500000 00035
+#define B4000000 00036

#define CSIZE 00001400
#define CS5 00000000
===================================================================
RCS file: include/asm-arm/RCS/termbits.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-arm/termbits.h
--- include/asm-arm/termbits.h 1999/01/06 18:58:41 1.1
+++ include/asm-arm/termbits.h 1999/01/06 18:58:51
@@ -117,10 +117,21 @@
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
-#define B57600 0010001
-#define B115200 0010002
-#define B230400 0010003
-#define B460800 0010004
+#define B57600 0010001
+#define B115200 0010002
+#define B230400 0010003
+#define B460800 0010004
+#define B500000 0010005
+#define B576000 0010006
+#define B921600 0010007
+#define B1000000 0010010
+#define B1152000 0010011
+#define B1500000 0010012
+#define B2000000 0010013
+#define B2500000 0010014
+#define B3000000 0010015
+#define B3500000 0010016
+#define B4000000 0010017
#define CIBAUD 002003600000 /* input baud rate (not used) */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
===================================================================
RCS file: include/asm-m68k/RCS/termbits.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-m68k/termbits.h
--- include/asm-m68k/termbits.h 1999/01/06 18:58:41 1.1
+++ include/asm-m68k/termbits.h 1999/01/06 18:58:51
@@ -118,10 +118,21 @@
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
-#define B57600 0010001
-#define B115200 0010002
-#define B230400 0010003
-#define B460800 0010004
+#define B57600 0010001
+#define B115200 0010002
+#define B230400 0010003
+#define B460800 0010004
+#define B500000 0010005
+#define B576000 0010006
+#define B921600 0010007
+#define B1000000 0010010
+#define B1152000 0010011
+#define B1500000 0010012
+#define B2000000 0010013
+#define B2500000 0010014
+#define B3000000 0010015
+#define B3500000 0010016
+#define B4000000 0010017
#define CIBAUD 002003600000 /* input baud rate (not used) */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
===================================================================
RCS file: include/asm-mips/RCS/termbits.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-mips/termbits.h
--- include/asm-mips/termbits.h 1999/01/06 18:58:41 1.1
+++ include/asm-mips/termbits.h 1999/01/06 18:58:51
@@ -153,10 +153,21 @@
#define CLOCAL 0004000 /* Ignore modem status lines. */
#if defined (__USE_BSD) || defined (__KERNEL__)
#define CBAUDEX 0010000
-#define B57600 0010001
-#define B115200 0010002
-#define B230400 0010003
-#define B460800 0010004
+#define B57600 0010001
+#define B115200 0010002
+#define B230400 0010003
+#define B460800 0010004
+#define B500000 0010005
+#define B576000 0010006
+#define B921600 0010007
+#define B1000000 0010010
+#define B1152000 0010011
+#define B1500000 0010012
+#define B2000000 0010013
+#define B2500000 0010014
+#define B3000000 0010015
+#define B3500000 0010016
+#define B4000000 0010017
#define CIBAUD 002003600000 /* input baud rate (not used) */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
===================================================================
RCS file: include/asm-ppc/RCS/termbits.h,v
retrieving revision 1.1
diff -u -r1.1 include/asm-ppc/termbits.h
--- include/asm-ppc/termbits.h 1999/01/06 18:58:41 1.1
+++ include/asm-ppc/termbits.h 1999/01/06 18:58:51
@@ -126,6 +126,17 @@
#define B115200 00021
#define B230400 00022
#define B460800 00023
+#define B500000 00024
+#define B576000 00025
+#define B921600 00026
+#define B1000000 00027
+#define B1152000 00030
+#define B1500000 00031
+#define B2000000 00032
+#define B2500000 00033
+#define B3000000 00034
+#define B3500000 00035
+#define B4000000 00036

#define CSIZE 00001400
#define CS5 00000000

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/