2.2.27-pre2 tty/ldisc fixes
Subsystems (6)
Network drivers Arm i.MX and Layerscape TTY layer and serial drivers Char and misc drivers +2 more subsystems
PATCH 1/1 2.2.27-pre2 tty/ldisc fixes
Here is a first attempt at bringing Alan's 2.6 and Jason's 2.4 tty/ldisc fixes to 2.2.
Need testing and feedback.
Signature · 3 lines
Krzysztof Taraszka ([email protected]) http://cyborg.kernel.pl/~dzimi/ http://dzimi.jogger.pl/
drivers/char/cyclades.c +9 -9
@@ -1019,10 +1019,7 @@wake_up_interruptible (&info->delta_msr_wait); }if (test_and_clear_bit (Cy_EVENT_WRITE_WAKEUP, &info->event)) { -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) - && tty->ldisc.write_wakeup){ - (tty->ldisc.write_wakeup)(tty); - } +tty_wakeup (tty);wake_up_interruptible (&tty->write_wait);wake_up_interruptible (&tty->poll_wait); }
@@ -2821,6 +2818,7 @@ cy_close(struct tty_struct *tty, struct file *filp) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; +struct tty_ldisc *ld;unsigned long flags;#ifdef CY_DEBUG_OTHER
@@ -2938,8 +2936,12 @@shutdown (info);if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); -if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); + ld =tty_ldisc_ref (tty); +if (ld) { +if (ld->flush_buffer) + ld->flush_buffer (tty); +tty_ldisc_deref (ld); + }CY_LOCK (info, flags); tty->closing =0 ;
@@ -4701,11 +4703,9 @@ }CY_UNLOCK (info, flags); } +tty_wakeup (tty);wake_up_interruptible (&tty->write_wait);wake_up_interruptible (&tty->poll_wait); -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); }/* cy_flush_buffer */
drivers/char/dz.c +2 -2
@@ -1084,10 +1084,10 @@ info->event =0 ; info->tty =0 ; -if (tty->ldisc.num != ldiscs[N_TTY ].num) { +if (tty->ldisc.num !=N_TTY ) {if (tty->ldisc.close) (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY ]; + tty->ldisc = *(tty_ldisc_get (N_TTY )); tty->termios->c_line =N_TTY ;if (tty->ldisc.open) (tty->ldisc.open)(tty);
drivers/char/epca.c +22 -13
@@ -572,7 +572,8 @@if ((ch =verifyChannel (tty)) !=NULL ) {/* Begin if ch != NULL */ - +struct tty_ldisc *ld; +save_flags (flags);cli ();
@@ -633,8 +634,12 @@if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); -if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); + ld =tty_ldisc_ref (tty); +if (ld !=NULL ) { +if (ld->flush_buffer) + ld->flush_buffer (tty); +tty_ldisc_deref (ld); + }shutdown (ch); tty->closing =0 ;
@@ -737,12 +742,20 @@ {/* Begin if ch != NULL */ unsigned long flags; - +struct tty_ldisc *ld; +save_flags (flags);cli ();if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); + ld =tty_ldisc_ref (tty); +if (ld !=NULL ) { +if (ld->flush_buffer) + ld->flush_buffer (tty); +tty_ldisc_deref (ld); + } +if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty);
@@ -1227,9 +1240,8 @@wake_up_interruptible (&tty->write_wait);wake_up_interruptible (&tty->poll_wait); -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - +tty_wakeup (tty); + }/* End pc_flush_buffer */ /* ------------------ Begin pc_flush_chars ---------------------- */
@@ -2443,9 +2455,7 @@ {/* Begin if LOWWAIT */ ch->statusflags &= ~LOWWAIT ; -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); +tty_wakeup (tty);wake_up_interruptible (&tty->write_wait);wake_up_interruptible (&tty->poll_wait); }/* End if LOWWAIT */
@@ -2462,9 +2472,7 @@ {/* Begin if EMPTYWAIT */ ch->statusflags &= ~EMPTYWAIT ; -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); +tty_wakeup (tty);wake_up_interruptible (&tty->write_wait);wake_up_interruptible (&tty->poll_wait);
@@ -3327,6 +3335,7 @@tty_wait_until_sent (tty,0 ); }else +/* ldisc lock already held in ioctl */ {if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty);
drivers/char/generic_serial.c +11 -10
@@ -453,9 +453,7 @@restore_flags (flags);wake_up_interruptible (&tty->write_wait); -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); +tty_wakeup (tty);func_exit (); }
@@ -595,9 +593,7 @@if (!tty)return ;if (test_and_clear_bit (RS_EVENT_WRITE_WAKEUP , &port->event)) { -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); +tty_wakeup (tty);wake_up_interruptible (&tty->write_wait); }func_exit ();
@@ -740,8 +736,9 @@ {unsigned long flags;struct gs_port *port; - -func_enter (); +struct tty_ldisc *ld; + +func_enter ();if (!tty)return ;
@@ -818,8 +815,12 @@if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); -if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); + ld =tty_ldisc_ref (tty); +if (ld !=NULL ) { +if (ld->flush_buffer) + ld->flush_buffer (tty); +tty_ldisc_deref (ld); + } tty->closing =0 ; port->event =0 ;
drivers/char/isicom.c +11 -8
@@ -621,10 +621,8 @@if (!tty)return ; - -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + +tty_wakeup (tty);wake_up_interruptible (&tty->write_wait); }
@@ -1349,7 +1347,8 @@struct isi_port * port = (struct isi_port *) tty->driver_data;struct isi_board * card;unsigned long flags; - +struct tty_ldisc *ld; +#ifdef ISICOM_DEBUG printk (KERN_DEBUG "ISICOM: Close start!!!.\n" );#endif
@@ -1417,6 +1416,12 @@isicom_shutdown_port (port);if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); + ld =tty_ldisc_ref (tty); +if (ld !=NULL ) { +if (ld->flush_buffer) + ld->flush_buffer (tty); +tty_ldisc_deref (ld); + }if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty);
@@ -1912,9 +1917,7 @@spin_unlock_irqrestore (&card->card_lock, flags);wake_up_interruptible (&tty->write_wait); -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); +tty_wakeup (tty); }
drivers/char/moxa.c +11 -12
@@ -616,6 +616,7 @@ {struct moxa_str *ch;int port; +struct tty_ldisc *ld; port =PORTNO (tty);if (port ==MAX_PORTS ) {
@@ -673,8 +674,13 @@if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); -if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); + + ld =tty_ldisc_ref (tty); +if (ld !=NULL ) { +if (ld->flush_buffer) + ld->flush_buffer (tty); +tty_ldisc_deref (ld); + } tty->closing =0 ; ch->event =0 ; ch->tty =0 ;
@@ -750,9 +756,7 @@if (ch ==NULL )return ;MoxaPortFlushData (ch->port,1 ); -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); +tty_wakeup (tty);wake_up_interruptible (&tty->write_wait);wake_up_interruptible (&tty->poll_wait); }
@@ -989,7 +993,6 @@ moxaTimer.function = moxa_poll; moxaTimer.expires = jiffies + (HZ /50 ); moxaTimer_on =1 ; -add_timer (&moxaTimer);return ; }for (card =0 ; card <MAX_BOARDS ; card++) {
@@ -1008,9 +1011,7 @@if (MoxaPortTxQueue (ch->port) <=WAKEUP_CHARS ) {if (!tp->stopped) { ch->statusflags &= ~LOWWAIT ; -if ((tp->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tp->ldisc.write_wakeup) - (tp->ldisc.write_wakeup) (tp); +tty_wakeup (tp);wake_up_interruptible (&tp->write_wait);wake_up_interruptible (&tp->poll_wait); }
@@ -1199,9 +1200,7 @@if (ch->tty && (ch->statusflags &EMPTYWAIT )) {if (MoxaPortTxQueue (ch->port) ==0 ) { ch->statusflags &= ~EMPTYWAIT ; -if ((ch->tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - ch->tty->ldisc.write_wakeup) - (ch->tty->ldisc.write_wakeup) (ch->tty); +tty_wakeup (ch->tty);wake_up_interruptible (&ch->tty->write_wait);wake_up_interruptible (&ch->tty->poll_wait);return ;
drivers/char/mxser.c +9 -6
@@ -712,9 +712,7 @@if (!tty)return ;if (test_and_clear_bit (MXSER_EVENT_TXLOW , &info->event)) { -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); +tty_wakeup (tty);wake_up_interruptible (&tty->write_wait);wake_up_interruptible (&tty->poll_wait); }
@@ -796,6 +794,7 @@struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;unsigned long flags;unsigned long timeout; +struct tty_ldisc *ld;if (PORTNO (tty) ==MXSER_PORTS )return ;
@@ -876,6 +875,12 @@mxser_shutdown (info);if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); + ld =tty_ldisc_ref (tty); +if (ld) { +if (ld->flush_buffer) + ld->flush_buffer (tty); +tty_ldisc_deref (ld); + }if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty); tty->closing =0 ;
@@ -1013,9 +1018,7 @@restore_flags (flags);wake_up_interruptible (&tty->write_wait);wake_up_interruptible (&tty->poll_wait); -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup) (tty); +tty_wakeup (tty); } static int mxser_ioctl(struct tty_struct *tty, struct file *file,
drivers/char/n_tty.c +263 -30
459 lines not on this page · raw message
drivers/char/pcxx.c +2 -2
@@ -621,10 +621,10 @@** please send me a note. [email protected] ** Don't know either what this is supposed to do [email protected]. */ -if (tty->ldisc.num != ldiscs[N_TTY ].num) { +if (tty->ldisc.num !=N_TTY ) {if (tty->ldisc.close) (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY ]; + tty->ldisc = *(tty_ldisc_get (N_TTY )); tty->termios->c_line =N_TTY ;if (tty->ldisc.open) (tty->ldisc.open)(tty);
drivers/char/pty.c +4 -0
@@ -134,6 +134,10 @@* (2) avoid redundant copying for cases where count >> receive_room * N.B. Calls from user space may now return an error code instead of * a count. +* +* FIXME: Our pty_write method is called with our ldisc lock held but +* not our partners. We can't just take the other one blindly without ++ * risking deadlocks. There is also the small matter of TTY_DONT_FLIP */ static int pty_write (struct tty_struct * tty,int from_user,const unsigned char *buf,int count)
drivers/char/riscom8.c +10 -7
@@ -1110,7 +1110,8 @@struct riscom_board *bp;unsigned long flags;unsigned long timeout; - +struct tty_ldisc *ld; +if (!port ||rc_paranoia_check (port, tty->device,"close" ))return ;
@@ -1180,6 +1181,12 @@rc_shutdown_port (bp, port);if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); + ld =tty_ldisc_ref (tty); +if (ld !=NULL ) { +if (ld->flush_buffer) + ld->flush_buffer (tty); +tty_ldisc_deref (ld); + }if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty); tty->closing =0 ;
@@ -1358,9 +1365,7 @@wake_up_interruptible (&tty->write_wait);wake_up_interruptible (&tty->poll_wait); -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); +tty_wakeup (tty); }static int rc_get_modem_info (struct riscom_port * port,unsigned int *value)
@@ -1736,9 +1741,7 @@return ;if (test_and_clear_bit (RS_EVENT_WRITE_WAKEUP , &port->event)) { -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); +tty_wakeup (tty);wake_up_interruptible (&tty->write_wait);wake_up_interruptible (&tty->poll_wait); }
drivers/char/selection.c +4 -0
@@ -296,9 +296,11 @@ {struct vt_struct *vt = (struct vt_struct *) tty->driver_data;int pasted =0 , count; +struct tty_ldisc *ld;struct wait_queue wait = { current,NULL };poke_blanked_console (); + ld =tty_ldisc_ref_wait (tty);add_wait_queue (&vt->paste_wait, &wait);while (sel_buffer && sel_buffer_lth > pasted) { current->state =TASK_INTERRUPTIBLE ;
@@ -313,6 +315,8 @@ }remove_wait_queue (&vt->paste_wait, &wait); current->state =TASK_RUNNING ; + +tty_ldisc_deref (ld);return 0 ; }
drivers/char/serial167.c +2 -2
@@ -1943,10 +1943,10 @@ tty->ldisc.flush_buffer (tty); info->event =0 ; info->tty =0 ; -if (tty->ldisc.num != ldiscs[N_TTY ].num) { +if (tty->ldisc.num !=N_TTY ) {if (tty->ldisc.close) (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY ]; + tty->ldisc = *(tty_ldisc_get (N_TTY )); tty->termios->c_line =N_TTY ;if (tty->ldisc.open) (tty->ldisc.open)(tty);
drivers/char/synclink.c +43 -24
103 lines not on this page · raw message
drivers/char/tty_io.c +434 -75
747 lines not on this page · raw message
drivers/char/tty_ioctl.c +48 -13
159 lines not on this page · raw message
drivers/net/slip.c +12 -6
@@ -669,7 +669,9 @@* Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when * a block of SLIP data has been received, which can now be decapsulated -* and sent on to some IP layer for further processing. +* and sent on to some IP layer for further processing. This will not +* be re-entered while running but other ldisc functions may be called +* in parallel */ static void slip_receive_buf (struct tty_struct *tty,const unsigned char *cp,char *fp,int count)
@@ -824,9 +826,11 @@* SLIP line discipline is called for. Because we are * sure the tty line exists, we only have to link it to * a free SLIP channel... +* +* Called in process context serialized from other ldisc calls. */ -static int -slip_open (struct tty_struct *tty) + +static int slip_open (struct tty_struct *tty) {struct slip *sl;int err;
@@ -908,6 +912,9 @@ }/* + +FIXME: 1,2 are fixed 3 was never true anyway. +Let me to blame a bit. 1. TTY module calls this funstion on soft interrupt. 2. TTY module calls this function WITH MASKED INTERRUPTS!
@@ -926,9 +933,8 @@/* * Close down a SLIP channel. -* This means flushing out any pending queues, and then restoring the -* TTY line discipline to what it was before it got hooked to SLIP -* (which usually is TTY again). +* This means flushing out any pending queues, and then returning. This +* call is serialized against other ldisc functions */ static void slip_close (struct tty_struct *tty)
drivers/sbus/char/zs.c +2 -2
@@ -1606,10 +1606,10 @@ tty->closing =0 ; info->event =0 ; info->tty =0 ; -if (tty->ldisc.num != ldiscs[N_TTY ].num) { +if (tty->ldisc.num !=N_TTY ) {if (tty->ldisc.close) (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY ]; + tty->ldisc = *(tty_ldisc_get (N_TTY )); tty->termios->c_line =N_TTY ;if (tty->ldisc.open) (tty->ldisc.open)(tty);
drivers/sgi/char/sgiserial.c +2 -2
@@ -1465,10 +1465,10 @@ tty->closing =0 ; info->event =0 ; info->tty =0 ; -if (tty->ldisc.num != ldiscs[N_TTY ].num) { +if (tty->ldisc.num !=N_TTY ) {if (tty->ldisc.close) (tty->ldisc.close)(tty); - tty->ldisc = ldiscs[N_TTY ]; + tty->ldisc = *(tty_ldisc_get (N_TTY )); tty->termios->c_line =N_TTY ;if (tty->ldisc.open) (tty->ldisc.open)(tty);
fs/proc/proc_tty.c +6 -4
@@ -15,8 +15,6 @@#include <asm/bitops.h> extern struct tty_driver *tty_drivers;/* linked list of tty drivers */ -extern struct tty_ldisc ldiscs[]; -static int tty_drivers_read_proc (char *page,char **start,off_t off,int count,int *eof,void *data);
@@ -112,16 +110,20 @@int len =0 ;off_t begin =0 ;off_t end; +struct tty_ldisc *ld; end = off + count;/* XXX: undefined on overflow per ISO C99 */ if (end < off)return -EINVAL ;for (i=0 ; i <NR_LDISCS ; i++) { -if (!(ldiscs[i].flags &LDISC_FLAG_DEFINED )) + ld =tty_ldisc_get (i); +if (ld ==NULL ) +continue ; len +=sprintf (page+len,"%-10s %2d\n" , - ldiscs[i].name ? ldiscs[i].name :"???" , i); + ld->name ? ld->name :"???" , i); +tty_ldisc_put (i);if (len+begin > end)break ;if (len+begin < off) {
include/linux/tty.h +26 -14
@@ -319,19 +319,21 @@* tty->write. Thus, you must use the inline functions set_bit() and * clear_bit() to make things atomic. */ -#define TTY_THROTTLED 0 -#define TTY_IO_ERROR 1 -#define TTY_OTHER_CLOSED 2 -#define TTY_EXCLUSIVE 3 -#define TTY_DEBUG 4 -#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 -#define TTY_NO_WRITE_SPLIT 17 +#define TTY_THROTTLED 0/* Call unthrottle() at threshold min */ +#define TTY_IO_ERROR 1/* Canse an I/O error (may be no ldisc too) */ +#define TTY_OTHER_CLOSED 2/* Other side (if any) has closed */ +#define TTY_EXCLUSIVE 3/* Exclusive open mode */ +#define TTY_DEBUG 4/* Debugging */ +#define TTY_DO_WRITE_WAKEUP 5/* Call write_wakeup after queuing new */ +#define TTY_PUSH 6/* n_tty private */ +#define TTY_CLOSING 7/* ->close() in progress */ +#define TTY_DONT_FLIP 8/* Defer buffer flip */ +#define TTY_LDISC 9/* Line discipline attached */ +#define TTY_HW_COOK_OUT 14/* Hardware can do output cooking */ +#define TTY_HW_COOK_IN 15/* Hardware can do input cooking */ +#define TTY_PTY_LOCK 16/* pty private */ +#define TTY_NO_WRITE_SPLIT 17/* Preserve write boundaries to driver */ +#define TTY_HUPPED 18/* Post driver->hangup() */ #define TTY_WRITE_FLUSH (tty) tty_write_flush((tty))
@@ -339,7 +341,7 @@extern struct termios tty_std_termios;extern struct tty_struct * redirect; -extern struct tty_ldisc ldiscs[]; +extern struct tty_ldisc tty_ldiscs[];extern int fg_console, last_console, want_console;extern int kmsg_redirect;
@@ -393,6 +395,16 @@extern void tty_flip_buffer_push (struct tty_struct *tty);extern int tty_get_baud_rate (struct tty_struct *tty); +extern struct tty_ldisc *tty_ldisc_ref (struct tty_struct *); +extern void tty_ldisc_deref (struct tty_ldisc *); +extern struct tty_ldisc *tty_ldisc_ref_wait (struct tty_struct *); + +extern struct tty_ldisc *tty_ldisc_get (int ); +extern void tty_ldisc_put (int ); + +extern void tty_wakeup (struct tty_struct *tty); + +/* n_tty.c */ extern struct tty_ldisc tty_ldisc_N_TTY;
include/linux/tty_ldisc.h +1 -0
@@ -129,6 +129,7 @@ char *fp, int count);int (*receive_room)(struct tty_struct *);void (*write_wakeup)(struct tty_struct *); +int refcount; };#define TTY_LDISC_MAGIC 0x5403