2.4.28-pre3 tty/ldisc fixes
Subsystems (8)
PATCH 1/1 2.4.28-pre3 tty/ldisc fixes
Here is a first attempt at bringing Alan's 2.6 tty/ldisc fixes to 2.4. I've done some testing with it, but was hoping for broader testing/feedback while all the issues get ironed out. The most notable change is the addition of a wakeup at the end of tty_set_ldisc, for threads waiting for the TTY_LDISC bit to be set.
thanks,
-Jason
Documentation/tty.txt | 194 ++++++++++++++ drivers/bluetooth/hci_ldisc.c | 13 drivers/char/amiserial.c | 17 - drivers/char/cyclades.c | 19 - drivers/char/dz.c | 4 drivers/char/epca.c | 29 +- drivers/char/generic_serial.c | 21 - drivers/char/isicom.c | 17 - drivers/char/moxa.c | 23 - drivers/char/mxser.c | 15 - drivers/char/n_tty.c | 330 ++++++++++++++++++++---- drivers/char/pcmcia/synclink_cs.c | 59 ++-- drivers/char/pcxx.c | 4 drivers/char/pty.c | 4 drivers/char/riscom8.c | 15 - drivers/char/selection.c | 4 drivers/char/serial167.c | 4 drivers/char/sgiserial.c | 4 drivers/char/synclink.c | 64 +++- drivers/char/synclinkmp.c | 60 ++-- drivers/char/tty_io.c | 511 ++++++++++++++++++++++++++++++++------ drivers/char/tty_ioctl.c | 59 +++- drivers/net/ppp_async.c | 18 + drivers/net/ppp_synctty.c | 2 drivers/net/slip.c | 18 - drivers/sbus/char/zs.c | 4 fs/proc/proc_tty.c | 11 include/linux/tty.h | 40 +- include/linux/tty_ldisc.h | 1 29 files changed, 1256 insertions(+), 308 deletions(-)
fs/proc/proc_tty.c renamed from fs/proc/proc_tty.c.bak +6 -5
@@ -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);
@@ -106,12 +104,15 @@ static int tty_ldiscs_read_proc(char *paint i;int len =0 ;off_t begin =0 ; - +struct tty_ldisc *ld; +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 > off+count)break ;if (len+begin < off) {
include/linux/tty.h renamed from include/linux/tty.h.bak +26 -14
@@ -322,26 +322,28 @@ struct tty_struct {* 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))extern void tty_write_flush (struct tty_struct *);extern struct termios tty_std_termios; -extern struct tty_ldisc ldiscs[]; +extern struct tty_ldisc tty_ldiscs[];extern int fg_console, last_console, want_console;extern int kmsg_redirect;
@@ -396,6 +398,16 @@ extern void disassociate_ctty(int priv);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 renamed from include/linux/tty_ldisc.h.bak +1 -0
@@ -129,6 +129,7 @@ struct tty_ldisc { char *fp, int count);int (*receive_room)(struct tty_struct *);void (*write_wakeup)(struct tty_struct *); +int refcount; };#define TTY_LDISC_MAGIC 0x5403
drivers/net/ppp_async.c renamed from drivers/net/ppp_async.c.bak +15 -3
@@ -117,6 +117,9 @@ static struct ppp_channel_ops async_ops* frees the memory that ppp_asynctty_receive is using. The best * way to fix this is to use a rwlock in the tty struct, but for now * we use a single global rwlock for all ttys in ppp line discipline. +* +* FIXME: this is no longer true. The _close path for the ldisc is +* now guaranteed to be sane. */ static rwlock_t disc_data_lock =RW_LOCK_UNLOCKED ;
@@ -139,7 +142,8 @@ static void ap_put(struct asyncppp *ap) }/* -* Called when a tty is put into PPP line discipline. +* Called when a tty is put into PPP line discipline. Called in process +* context. */ static int ppp_asynctty_open (struct tty_struct *tty)
@@ -248,6 +252,11 @@ ppp_asynctty_write(struct tty_struct *ttreturn -EAGAIN ; } +/* +* Called in process context only. May be re-entered by multiple +* ioctl calling threads. +*/ +static int ppp_asynctty_ioctl (struct tty_struct *tty,struct file *file,unsigned int cmd,unsigned long arg)
@@ -714,7 +723,8 @@ flush:/* * Flush output from our internal buffers. -* Called for the TCFLSH ioctl. +* Called for the TCFLSH ioctl. Can be entered in parallel +* but this is covered by the xmit_lock. */ static void ppp_async_flush_output (struct asyncppp *ap)
@@ -819,7 +829,9 @@ input_error(struct asyncppp *ap, int codppp_input_error (&ap->chan, code); } -/* called when the tty driver has data for us. */ +/* Called when the tty driver has data for us. Runs parallel with the +other ldisc functions but will not be re-entered */ +static void ppp_async_input (struct asyncppp *ap,const unsigned char *buf,char *flags,int count)
drivers/net/ppp_synctty.c renamed from drivers/net/ppp_synctty.c.bak +2 -0
@@ -172,6 +172,8 @@ ppp_print_buffer (const char *name, cons* frees the memory that ppp_synctty_receive is using. The best * way to fix this is to use a rwlock in the tty struct, but for now * we use a single global rwlock for all ttys in ppp line discipline. +* +* FIXME: Fixed in tty_io nowdays. */ static rwlock_t disc_data_lock =RW_LOCK_UNLOCKED ;
drivers/net/slip.c renamed from drivers/net/slip.c.bak +12 -6
@@ -670,7 +670,9 @@ static int slip_receive_room(struct tty_* 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)
@@ -826,9 +828,11 @@ sl_alloc(kdev_t line)* 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;
@@ -910,6 +914,9 @@ err_exit: }/* + +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!
@@ -928,9 +935,8 @@ err_exit:/* * 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/char/pcmcia/synclink_cs.c renamed from drivers/char/pcmcia/synclink_cs.c.bak +40 -19
90 lines not on this page · raw message
drivers/char/tty_io.c renamed from drivers/char/tty_io.c.bak +437 -74
752 lines not on this page · raw message
drivers/char/tty_ioctl.c renamed from drivers/char/tty_ioctl.c.bak +46 -13
152 lines not on this page · raw message
drivers/char/amiserial.c renamed from drivers/char/amiserial.c.bak +9 -8
@@ -575,9 +575,7 @@ static void do_softint(void *private_)return ;if (test_and_clear_bit (RS_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); } }
@@ -1041,9 +1039,7 @@ static void rs_flush_buffer(struct tty_s info->xmit.head = info->xmit.tail =0 ;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); }/*
@@ -1526,6 +1522,7 @@ static void rs_close(struct tty_struct *struct async_struct * info = (struct async_struct *)tty->driver_data;struct serial_state *state;unsigned long flags; +struct tty_ldisc *ld;if (!info ||serial_paranoia_check (info, tty->device,"rs_close" ))return ;
@@ -1608,8 +1605,12 @@ static void rs_close(struct tty_struct *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 !=NULL ) { +if (ld->flush_buffer) + ld->flush_buffer (tty); +tty_ldisc_deref (ld); + } tty->closing =0 ; info->event =0 ; info->tty =0 ;
drivers/char/cyclades.c renamed from drivers/char/cyclades.c.bak +10 -9
@@ -1000,10 +1000,7 @@ do_softint(void *private_)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); }#ifdef Z_WAKE
@@ -2801,6 +2798,7 @@ static void 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
@@ -2918,8 +2916,13 @@ cy_close(struct tty_struct *tty, structshutdown (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 ;
@@ -4689,10 +4692,8 @@ cy_flush_buffer(struct tty_struct *tty) }CY_UNLOCK (info, flags); } +tty_wakeup (tty);wake_up_interruptible (&tty->write_wait); -if ((tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) - && tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); }/* cy_flush_buffer */
drivers/char/epca.c renamed from drivers/char/epca.c.bak +19 -10
@@ -524,6 +524,7 @@ static void pc_close(struct tty_struct *if ((ch =verifyChannel (tty)) !=NULL ) {/* Begin if ch != NULL */ +struct tty_ldisc *ld;save_flags (flags);cli ();
@@ -585,8 +586,12 @@ static void pc_close(struct tty_struct *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 ;
@@ -687,12 +692,20 @@ static void pc_hangup(struct tty_struct {/* 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);
@@ -1176,8 +1189,7 @@ static void pc_flush_buffer(struct tty_srestore_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); }/* End pc_flush_buffer */
@@ -2383,9 +2395,7 @@ static void doevent(int crd) {/* 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); }/* End if LOWWAIT */
@@ -2402,9 +2412,7 @@ static void doevent(int crd) {/* 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);
@@ -3255,6 +3263,7 @@ static int pc_ioctl(struct tty_struct *t }else { +/* ldisc lock already held in ioctl */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty); }
drivers/char/generic_serial.c renamed from drivers/char/generic_serial.c.bak +11 -10
@@ -440,9 +440,7 @@ void gs_flush_buffer(struct tty_struct *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 (); }
@@ -582,9 +580,7 @@ void gs_do_softint(void *private_)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 ();
@@ -729,8 +725,9 @@ void gs_close(struct tty_struct * tty, s {unsigned long flags;struct gs_port *port; - -func_enter (); +struct tty_ldisc *ld; + +func_enter ();if (!tty)return ;
@@ -803,8 +800,12 @@ void gs_close(struct tty_struct * tty, sif (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 renamed from drivers/char/isicom.c.bak +10 -7
@@ -502,10 +502,8 @@ static void isicom_bottomhalf(void * datif (!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); }
@@ -1144,6 +1142,7 @@ static void isicom_close(struct tty_strustruct isi_port * port = (struct isi_port *) tty->driver_data;struct isi_board * card = port->card;unsigned long flags; +struct tty_ldisc *ld;if (!port)return ;
@@ -1199,6 +1198,12 @@ static void isicom_close(struct tty_struisicom_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); tty->closing =0 ;
@@ -1671,9 +1676,7 @@ static void isicom_flush_buffer(struct trestore_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); }
drivers/char/moxa.c renamed from drivers/char/moxa.c.bak +11 -12
@@ -620,6 +620,7 @@ static void moxa_close(struct tty_struct {struct moxa_str *ch;int port; +struct tty_ldisc *ld; port =PORTNO (tty);if (port ==MAX_PORTS ) {
@@ -677,8 +678,13 @@ static void moxa_close(struct tty_structif (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 ;
@@ -754,9 +760,7 @@ static void moxa_flush_buffer(struct ttyif (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); }
@@ -992,7 +996,6 @@ static void moxa_poll(unsigned long igno moxaTimer.function = moxa_poll; moxaTimer.expires = jiffies + (HZ /50 ); moxaTimer_on =1 ; -add_timer (&moxaTimer);return ; }for (card =0 ; card <MAX_BOARDS ; card++) {
@@ -1011,9 +1014,7 @@ static void moxa_poll(unsigned long ignoif (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); } }
@@ -1203,9 +1204,7 @@ static void check_xmit_empty(unsigned loif (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);return ; }
drivers/char/mxser.c renamed from drivers/char/mxser.c.bak +9 -6
@@ -725,9 +725,7 @@ static void mxser_do_softint(void *priva tty = info->tty;if (tty) {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); }if (test_and_clear_bit (MXSER_EVENT_HANGUP , &info->event)) {
@@ -810,6 +808,7 @@ static void mxser_close(struct tty_strucstruct 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 ;
@@ -890,6 +889,12 @@ static void mxser_close(struct tty_strucmxser_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 ;
@@ -1051,9 +1056,7 @@ static void mxser_flush_buffer(struct tt info->xmit_cnt = info->xmit_head = info->xmit_tail =0 ;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); } static int mxser_ioctl(struct tty_struct *tty, struct file *file,
drivers/char/n_tty.c renamed from drivers/char/n_tty.c.bak +282 -48
498 lines not on this page · raw message
drivers/char/pty.c renamed from drivers/char/pty.c.bak +4 -0
@@ -137,6 +137,10 @@ static void pty_unthrottle(struct tty_st* (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 renamed from drivers/char/riscom8.c.bak +9 -6
@@ -1133,6 +1133,7 @@ static void rc_close(struct tty_struct *struct riscom_board *bp;unsigned long flags;unsigned long timeout; +struct tty_ldisc *ld;if (!port ||rc_paranoia_check (port, tty->device,"close" ))return ;
@@ -1200,6 +1201,12 @@ static void rc_close(struct tty_struct *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 ;
@@ -1375,9 +1382,7 @@ static void rc_flush_buffer(struct tty_srestore_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); }static int rc_get_modem_info (struct riscom_port * port,unsigned int *value)
@@ -1734,9 +1739,7 @@ static void do_softint(void *private_)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); } }
drivers/char/selection.c renamed from drivers/char/selection.c.bak +4 -0
@@ -290,9 +290,11 @@ int paste_selection(struct tty_struct *t {struct vt_struct *vt = (struct vt_struct *) tty->driver_data;int pasted =0 , count; +struct tty_ldisc *ld;DECLARE_WAITQUEUE (wait, current);poke_blanked_console (); + ld =tty_ldisc_ref_wait (tty);add_wait_queue (&vt->paste_wait, &wait);while (sel_buffer && sel_buffer_lth > pasted) {set_current_state (TASK_INTERRUPTIBLE );
@@ -307,6 +309,8 @@ int paste_selection(struct tty_struct *t }remove_wait_queue (&vt->paste_wait, &wait); current->state =TASK_RUNNING ; + +tty_ldisc_deref (ld);return 0 ; }
drivers/char/synclink.c renamed from drivers/char/synclink.c.bak +41 -23
100 lines not on this page · raw message
drivers/char/synclinkmp.c renamed from drivers/char/synclinkmp.c.bak +39 -21
90 lines not on this page · raw message
drivers/char/dz.c renamed from drivers/char/dz.c.bak +2 -2
@@ -1112,10 +1112,10 @@ static void dz_close(struct tty_struct * 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/pcxx.c renamed from drivers/char/pcxx.c.bak +2 -2
@@ -632,10 +632,10 @@ static void pcxe_close(struct tty_struct** 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/serial167.c renamed from drivers/char/serial167.c.bak +2 -2
@@ -1920,10 +1920,10 @@ cy_close(struct tty_struct * tty, struct 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/sgiserial.c renamed from drivers/char/sgiserial.c.bak +2 -2
@@ -1498,10 +1498,10 @@ static void rs_close(struct tty_struct * 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/sbus/char/zs.c renamed from drivers/sbus/char/zs.c.bak +2 -2
@@ -1605,10 +1605,10 @@ static void zs_close(struct tty_struct * 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/bluetooth/hci_ldisc.c renamed from drivers/bluetooth/hci_ldisc.c.bak +9 -4
@@ -181,6 +181,7 @@ static int hci_uart_flush(struct hci_dev {struct hci_uart *hu = (struct hci_uart *) hdev->driver_data;struct tty_struct *tty = hu->tty; +struct tty_ldisc *ld =tty_ldisc_ref (tty);BT_DBG ("hdev %p tty %p" , hdev, tty);
@@ -188,9 +189,11 @@ static int hci_uart_flush(struct hci_devkfree_skb (hu->tx_skb); hu->tx_skb =NULL ; } -/* Flush any pending characters in the driver and discipline. */ -if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); +if (ld) { +if (ld->flush_buffer) + ld->flush_buffer (tty); +tty_ldisc_deref (ld); + }if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty);
@@ -283,7 +286,9 @@ static int hci_uart_tty_open(struct tty_spin_lock_init (&hu->rx_lock); -/* Flush any pending characters in the driver and line discipline */ +/* Flush any pending characters in the driver and line discipline. */ +/* FIXME: why is this needed. Note don't use ldisc_ref here as the +open path is before the ldisc is referencable */ if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty);
Documentation/tty.txt renamed from Documentation/tty.txt.bak +194 -0
194 lines not on this page · raw message
drivers/char/tty_io.c void do_tty_hangup(void *data) · line 772
Quoted 13 lines · Jason Baron
Here is a first attempt at bringing Alan's 2.6 tty/ldisc fixes to 2.4. I've done some testing with it, but was hoping for broader testing/feedback while all the issues get ironed out. The most notable change is the addition of a wakeup at the end of
tty_set_ldisc, for threads waiting for theTTY_LDISCbit to be set.drivers/char/tty_io.c renamed from drivers/char/tty_io.c.bak +4
-0+ +/* Defer ldisc switch */ +/* tty_deferred_ldisc_switch(N_TTY); +read_lock(&tasklist_lock); for_each_task(p) { if ((tty->session > 0) && (p->session == tty->session) &&
Here the comment is unclosed; is this intentional? Simply closing it at the same line gives a kernel which cannot complete the system boot
process: it prints "init_dev but no ldisc", and then init hangs in uninterruptible sleep with this backtrace:
Adhoc c0188ab7 <tty_ldisc_ref_wait+47/80>
Adhoc c0199c30 <con_write+0/30>
Adhoc c0189648 <tty_write+118/270>
Adhoc c0139728 <chrdev_open+38/50>
Adhoc c01386e3 <dentry_open+e3/190>
Adhoc c0138f16 <sys_write+96/f0>
Adhoc c01385eb <filp_open+4b/60>
Adhoc c014246f <getname+5f/a0>
Adhoc c0138937 <sys_open+57/80>
Quoted 8 lines · Sergey Vlasov
Quoted 5 lines · Jason Baron
Here is a first attempt at bringing Alan's 2.6 tty/ldisc fixes to 2.4. I've done some testing with it, but was hoping for broader testing/feedback while all the issues get ironed out. The most notable change is the addition of a wakeup at the end of
tty_set_ldisc, for threads waiting for theTTY_LDISCbit to be set.
Quoted 12 lines
drivers/char/tty_io.c void do_tty_hangup(void *data) · line 772
Quoted 7 lines
drivers/char/tty_io.c renamed from drivers/char/tty_io.c.bak +4
-0+ +/* Defer ldisc switch */ +/* tty_deferred_ldisc_switch(N_TTY); +read_lock(&tasklist_lock); for_each_task(p) { if ((tty->session > 0) && (p->session == tty->session) && Here the comment is unclosed; is this intentional? Simply closing it at the same line gives a kernel which cannot complete the system boot
process: it prints "init_devbut no ldisc", and then init hangs in uninterruptible sleep with this backtrace:
That comment should be closed. oops. I'm working on a fixed up patch now (for that and a few other things).
-Jason
A message that is not in the archive (sent off-list or not yet received): Pine.LNX.4.44.0410291426240.13340-200000@dhcp83-105.boston.redhat.com
Quoted 19 lines · Jason Baron
Quoted 5 lines · Sergey Vlasov
Here the comment is unclosed; is this intentional? Simply closing it at the same line gives a kernel which cannot complete the system boot
process: it prints "init_devbut no ldisc", and then init hangs in uninterruptible sleep with this backtrace:Quoted 10 lines
Adhoc
c0188ab7<tty_ldisc_ref_wait+47/80>
Adhocc0199c30<con_write+0/30>
Adhocc0189648<tty_write+118/270>
Adhocc0139728<chrdev_open+38/50>
Adhocc01386e3<dentry_open+e3/190>
Adhocc0138f16<sys_write+96/f0>
Adhocc01385eb<filp_open+4b/60>
Adhocc014246f<getname+5f/a0>
Adhocc0138937<sys_open+57/80>
Quoted 3 lines
Here's an updated 2.4 tty patch. I'm not sure if the updated patch would fix the above issue, but it has a lot of changes so it might be worth a try.
This looks better - at least the system boots without hang or oops ;)
However, drivers/net/wan/pc300_tty.c does not compile:
Quoted 4 lines
(quoted diff) +0
-0@@ -699,12 +693,19 @@ static void cpc_tty_rx_task(void * data) cpc_tty = &cpc_tty_area[port]; if ((buf=cpc_tty->buf_rx.first) != 0) {
Review static void cpc_tty_rx_task(void * data) · line 699
Quoted 10 lines
(quoted diff) +4
-6- - if (cpc_tty->tty && (cpc_tty->tty->ldisc.receive_buf)) { - CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); - cpc_tty->tty->ldisc.receive_buf(cpc_tty->tty, (const unsigned char *)buf->data, - &flags, buf->size); - } + + if(cpc_tty->tty) + { + ld = tty_ldisc_ref(cpc_tty);
struct tty_ldisc *ld = tty_ldisc_ref(cpc_tty->tty);
Review static void cpc_tty_rx_task(void * data) · line 702
Quoted 3 lines
(quoted diff) +3
-0+ if(ld) + { + if (ld->receive_buf)) {
if (ld->receive_buf) {Quoted 9 lines
(quoted diff) +6
-0+ CPC_TTY_DBG("%s: call line disc. receive_buf\n",cpc_tty->name); + ld->receive_buf(cpc_tty->tty, (char *)(buf->data), &flags, buf->size); + } + tty_ldisc_deref(ld); + } + } cpc_tty->buf_rx.first = cpc_tty->buf_rx.first->next; kfree((unsigned char *)buf); buf = cpc_tty->buf_rx.first;
Dnia sobota, 30 października 2004 21:19, napisałeś:
Quoted 7 lines · Jason Baron
Quoted 4 lines
Here's an updated 2.4 tty patch. I'm not sure if the updated patch would fix the above issue, but it has a lot of changes so it might be worth a try.
This looks better - at least the system boots without hang or oops ;)
where is an updated 2.4 tty patch ?
Signature · 3 lines
Krzysztof Taraszka ([email protected]) http://cyborg.kernel.pl/~dzimi/ http://dzimi.jogger.pl/
Quoted 12 lines · Krzysztof Taraszka
Dnia sobota, 30 pa¼dziernika 2004 21:19, napisa³e¶:
Quoted 7 lines · Jason Baron
Quoted 4 lines
Here's an updated 2.4 tty patch. I'm not sure if the updated patch would fix the above issue, but it has a lot of changes so it might be worth a try.
This looks better - at least the system boots without hang or oops ;)
where is an updated 2.4 tty patch ?
hmmm...seems like my e-mails keeping getting dropped, perhaps the patch is too large? Here is a link to the patch:
http://people.redhat.com/~jbaron/tty/2.4-tty-V5.patch
-Jason
linux-2.4.28-rc1-tty/drivers/char/n_r3964.c | 3 linux-2.4.28-rc1-tty/Documentation/tty.txt | 194 ++++ linux-2.4.28-rc1-tty/drivers/bluetooth/hci_ldisc.c | 8 linux-2.4.28-rc1-tty/drivers/char/amiserial.c | 12 linux-2.4.28-rc1-tty/drivers/char/cyclades.c | 14 linux-2.4.28-rc1-tty/drivers/char/dz.c | 4 linux-2.4.28-rc1-tty/drivers/char/epca.c | 27 linux-2.4.28-rc1-tty/drivers/char/esp.c | 13 linux-2.4.28-rc1-tty/drivers/char/generic_serial.c | 15 linux-2.4.28-rc1-tty/drivers/char/hvc_console.c | 5 linux-2.4.28-rc1-tty/drivers/char/isicom.c | 14 linux-2.4.28-rc1-tty/drivers/char/moxa.c | 16 linux-2.4.28-rc1-tty/drivers/char/mxser.c | 13 linux-2.4.28-rc1-tty/drivers/char/n_tty.c | 331 ++++++- linux-2.4.28-rc1-tty/drivers/char/pcmcia/synclink_cs.c | 59 - linux-2.4.28-rc1-tty/drivers/char/pcxx.c | 36 linux-2.4.28-rc1-tty/drivers/char/pty.c | 9 linux-2.4.28-rc1-tty/drivers/char/riscom8.c | 12 linux-2.4.28-rc1-tty/drivers/char/rocket.c | 26 linux-2.4.28-rc1-tty/drivers/char/selection.c | 4 linux-2.4.28-rc1-tty/drivers/char/ser_a2232.c | 5 linux-2.4.28-rc1-tty/drivers/char/serial.c | 21 linux-2.4.28-rc1-tty/drivers/char/serial167.c | 21 linux-2.4.28-rc1-tty/drivers/char/serial_tx3912.c | 5 linux-2.4.28-rc1-tty/drivers/char/sgiserial.c | 4 linux-2.4.28-rc1-tty/drivers/char/specialix.c | 15 linux-2.4.28-rc1-tty/drivers/char/stallion.c | 13 linux-2.4.28-rc1-tty/drivers/char/sx.c | 4 linux-2.4.28-rc1-tty/drivers/char/synclink.c | 64 - linux-2.4.28-rc1-tty/drivers/char/synclinkmp.c | 49 - linux-2.4.28-rc1-tty/drivers/char/tty_io.c | 587 +++++++++++--- linux-2.4.28-rc1-tty/drivers/char/tty_ioctl.c | 60 + linux-2.4.28-rc1-tty/drivers/char/vme_scc.c | 8 linux-2.4.28-rc1-tty/drivers/char/vt.c | 3 linux-2.4.28-rc1-tty/drivers/macintosh/macserial.c | 11 linux-2.4.28-rc1-tty/drivers/net/ppp_async.c | 31 linux-2.4.28-rc1-tty/drivers/net/ppp_synctty.c | 15 linux-2.4.28-rc1-tty/drivers/net/slip.c | 20 linux-2.4.28-rc1-tty/drivers/net/wan/pc300_tty.c | 34 linux-2.4.28-rc1-tty/drivers/net/wan/sdla_chdlc.c | 19 linux-2.4.28-rc1-tty/drivers/s390/char/con3215.c | 10 linux-2.4.28-rc1-tty/drivers/sbus/char/aurora.c | 15 linux-2.4.28-rc1-tty/drivers/sbus/char/zs.c | 4 linux-2.4.28-rc1-tty/drivers/tc/zs.c | 13 linux-2.4.28-rc1-tty/drivers/usb/serial/digi_acceleport.c | 12 linux-2.4.28-rc1-tty/drivers/usb/serial/io_edgeport.c | 7 linux-2.4.28-rc1-tty/drivers/usb/serial/io_ti.c | 7 linux-2.4.28-rc1-tty/drivers/usb/serial/keyspan_pda.c | 8 linux-2.4.28-rc1-tty/drivers/usb/serial/mct_u232.c | 6 linux-2.4.28-rc1-tty/fs/proc/proc_tty.c | 11 linux-2.4.28-rc1-tty/include/linux/tty.h | 41 linux-2.4.28-rc1-tty/include/linux/tty_ldisc.h | 9 52 files changed, 1368 insertions(+), 579 deletions(-)
Quoted 10 lines · Jason Baron
Quoted 7 lines · Krzysztof Taraszka
Dnia sobota, 30 pa?dziernika 2004 21:19, napisa?e?:
Quoted 6 lines · Jason Baron
Quoted 4 lines
Here's an updated 2.4 tty patch. I'm not sure if the updated patch would fix the above issue, but it has a lot of changes so it might be worth a try.
Quoted 8 lines
Quoted 3 lines
Quoted 1 line
This looks better - at least the system boots without hang or oops ;)
where is an updated 2.4 tty patch ?
hmmm...seems like my e-mails keeping getting dropped, perhaps the patch is too large? Here is a link to the patch:
Finally I have found the bug which prevented SieFS (slink) from working. The bug was in drivers/char/tty_ioctl.c:
@@ -131,16 +141,20 @@ static void change_termios(struct tty_st
}
}
- if (tty->driver.set_termios)
- (*tty->driver.set_termios)(tty, &old_termios);
+ ld = tty_ldisc_ref(tty);
+ if (ld != NULL) {
+ if (ld->set_termios)
+ (ld->set_termios)(tty, &old_termios);
+ tty_ldisc_deref(ld);
+ }
+ spin_unlock_irqrestore(&tty_termios_lock, flags);
- if (tty->ldisc.set_termios)
- (*tty->ldisc.set_termios)(tty, &old_termios);
}
The call to tty->driver.set_termios was lost, therefore the serial port speed was not set properly.
Simply adding this call back does not work, because set_termios handlers in usbserial use semaphores for locking, and therefore cannot be called while holding the tty_termios_lock spinlock. Because of this, some more backporting from 2.6.x is needed - Alan Cox has already changed tty_termios_lock to a per-tty semaphore in 2.6.x, this change is needed for 2.4.x too.
The patches are in separate emails: first is the backport of the termios locking changes, second patch adds back lost call to tty->driver.set_termios (which is safe after first patch).
PATCH 1/1 Update termios to use per tty semaphore (backport from 2.6.x)
This is a 2.4.x backport of the termios locking changes made in 2.6.x:
# 2004/10/02 15:46:35-07:00 [email protected]
# [PATCH] Update termios to use per tty semaphore
#
# This makes the agreed change of termios locking to be semaphore based # sleep locking. This is needed for USB in particular as it has to use # messaging to issue terminal mode changes. # # This code passes Torvalds test grades 0, 1 and 2 (it looks ok, it # compiles and it booted). It does mean that a driver cannot take an # atomic peek at termios data during an interrupt. Nobody seems to be # doing this although some of the driver receive paths for line # disciplines will eventually want to (n_tty currently doesn't do this # locked on the receive path). Since the ldisc is given a chance to copy # any essential bits on the ->set_termios path this seems not to be a # problem.
include/linux/tty.h renamed from include/linux/tty.h.termios +1 -0
@@ -261,6 +261,7 @@ struct tty_struct {int magic;struct tty_driver driver;struct tty_ldisc ldisc; +struct semaphore termios_sem;struct termios *termios, *termios_locked;int pgrp;int session;
drivers/char/tty_io.c renamed from drivers/char/tty_io.c.termios +5 -8
@@ -118,8 +118,6 @@ extern void disable_early_printk(void);#define TTY_PARANOIA_CHECK 1#define CHECK_TTY_COUNT 1 -/* Lock for tty_termios changes - private to tty_io/tty_ioctl */ -spinlock_t tty_termios_lock =SPIN_LOCK_UNLOCKED ;struct termios tty_std_termios;/* for the benefit of tty drivers */ struct tty_driver *tty_drivers;/* linked list of tty drivers */
@@ -269,10 +267,9 @@ static int check_tty_count(struct tty_ststatic void tty_set_termios_ldisc (struct tty_struct *tty,int num) { -unsigned long flags; -spin_lock_irqsave (&tty_termios_lock, flags); +down (&tty->termios_sem); tty->termios->c_line = num; -spin_unlock_irqrestore (&tty_termios_lock, flags); +up (&tty->termios_sem); }/*
@@ -803,10 +800,9 @@ void do_tty_hangup(void *data)if (tty->driver.flags &TTY_DRIVER_RESET_TERMIOS ) { -unsigned long flags; -spin_lock_irqsave (&tty_termios_lock, flags); +down (&tty->termios_sem); *tty->termios = tty->driver.init_termios; -spin_unlock_irqrestore (&tty_termios_lock, flags); +up (&tty->termios_sem); }/* Defer ldisc switch */
@@ -2452,6 +2448,7 @@ static void initialize_tty_struct(struct tty->flip.tqueue.routine = flush_to_ldisc; tty->flip.tqueue.data = tty;init_MUTEX (&tty->flip.pty_sem); +init_MUTEX (&tty->termios_sem);init_waitqueue_head (&tty->write_wait);init_waitqueue_head (&tty->read_wait); tty->tq_hangup.routine = do_tty_hangup;
drivers/char/tty_ioctl.c renamed from drivers/char/tty_ioctl.c.termios +8 -13
@@ -29,8 +29,6 @@#undef DEBUG -extern spinlock_t tty_termios_lock; -/* * Internal flag options for termios setting behavior */
@@ -99,7 +97,6 @@ static void change_termios(struct tty_stint canon_change;struct termios old_termios = *tty->termios;struct tty_ldisc *ld; -unsigned long flags;/* * Perform the actual termios internal changes under lock.
@@ -107,7 +104,7 @@ static void change_termios(struct tty_st/* FIXME: we need to decide on some locking/ordering semantics for the set_termios notification eventually */ -spin_lock_irqsave (&tty_termios_lock, flags); +down (&tty->termios_sem); *tty->termios = *new_termios;unset_locked_termios (tty->termios, &old_termios, tty->termios_locked);
@@ -147,8 +144,7 @@ static void change_termios(struct tty_st (ld->set_termios)(tty, &old_termios);tty_ldisc_deref (ld); } -spin_unlock_irqrestore (&tty_termios_lock, flags); - +up (&tty->termios_sem); }static int set_termios (struct tty_struct * tty,unsigned long arg,int opt)
@@ -244,13 +240,13 @@ static int get_sgttyb(struct tty_structstruct sgttyb tmp;unsigned long flags; -spin_lock_irqsave (&tty_termios_lock, flags); +down (&tty->termios_sem); tmp.sg_ispeed =0 ; tmp.sg_ospeed =0 ; tmp.sg_erase = tty->termios->c_cc[VERASE ]; tmp.sg_kill = tty->termios->c_cc[VKILL ]; tmp.sg_flags =get_sgflags (tty); -spin_unlock_irqrestore (&tty_termios_lock, flags); +up (&tty->termios_sem);return copy_to_user (sgttyb, &tmp,sizeof (tmp)) ? -EFAULT :0 ; }
@@ -286,19 +282,18 @@ static int set_sgttyb(struct tty_structint retval;struct sgttyb tmp;struct termios termios; -unsigned long flags; retval =tty_check_change (tty);if (retval)return retval;if (copy_from_user (&tmp, sgttyb,sizeof (tmp)))return -EFAULT ; -spin_lock_irqsave (&tty_termios_lock, flags); +down (&tty->termios_sem); termios = *tty->termios; termios.c_cc[VERASE ] = tmp.sg_erase; termios.c_cc[VKILL ] = tmp.sg_kill;set_sgflags (&termios, tmp.sg_flags); -spin_unlock_irqrestore (&tty_termios_lock, flags); +up (&tty->termios_sem);change_termios (tty, &termios);return 0 ; }
@@ -533,11 +528,11 @@ int n_tty_ioctl(struct tty_struct * tty,case TIOCSSOFTCAR :if (get_user (arg, (unsigned int *) arg))return -EFAULT ; -spin_lock_irqsave (&tty_termios_lock, flags); +down (&tty->termios_sem); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL ) | (arg ?CLOCAL :0 )); -spin_unlock_irqrestore (&tty_termios_lock, flags); +up (&tty->termios_sem);return 0 ;default :return -ENOIOCTLCMD ;
Documentation/tty.txt renamed from Documentation/tty.txt.termios +2 -2
@@ -158,8 +158,8 @@ write_room() - Return the number of char ioctl() - Called when an ioctl may be for the driver -set_termios() - Called on termios change, may get parallel calls, - may block for now (may change that) +set_termios() - Called on termios change, serialized against + itself by a semaphore. May sleep. set_ldisc() - Notifier for discipline change. At the point this is done the discipline is not yet usable. Can now
PATCH 1/1 Add back lost call to tty->driver.set_termios
In reply to Sergey VlasovThe call to tty->driver.set_termios in change_termios() has been lost; after termios locking changes it can be put back safely.
drivers/char/tty_ioctl.c renamed from drivers/char/tty_ioctl.c.set_termios +3 -0
@@ -138,6 +138,9 @@ static void change_termios(struct tty_st } } +if (tty->driver.set_termios) + (*tty->driver.set_termios)(tty, &old_termios); + ld =tty_ldisc_ref (tty);if (ld !=NULL ) {if (ld->set_termios)
Quoted 6 lines · Sergey Vlasov
Quoted 3 lines · Jason Baron
Here's an updated 2.4 tty patch. I'm not sure if the updated patch would fix the above issue, but it has a lot of changes so it might be worth a try.
This looks better - at least the system boots without hang or oops ;)
However, this seems to break SieFS 0.2
(http://mirror01.users.i.com.ua/~dmitry_z/siefs/; 0.4 is broken with Siemens x55 models): even "slink i" does not work:
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {c_iflags=0x5, c_oflags=0, c_cflags=0xebe, c_lflags=0, c_line=0, c_cc[VMIN]=0, c_cc[VTIME]=2, c_cc="\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}) = 0 ioctl(3, SNDCTL_TMR_START or TCSETS, {c_iflags=0x5, c_oflags=0, c_cflags=0x1eb1, c_lflags=0, c_line=0, c_cc[VMIN]=0, c_cc[VTIME]=2, c_cc="\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}) = 0 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {c_iflags=0x5, c_oflags=0, c_cflags=0x1eb1, c_lflags=0, c_line=0, c_cc[VMIN]=0, c_cc[VTIME]=2, c_cc="\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}) = 0 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {c_iflags=0x5, c_oflags=0, c_cflags=0x1eb1, c_lflags=0, c_line=0, c_cc[VMIN]=0, c_cc[VTIME]=2, c_cc="\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}) = 0 ioctl(3, SNDCTL_TMR_START or TCSETS, {c_iflags=0x5, c_oflags=0, c_cflags=0x1eb1, c_lflags=0, c_line=0, c_cc[VMIN]=0, c_cc[VTIME]=3, c_cc="\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}) = 0 ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {c_iflags=0x5, c_oflags=0, c_cflags=0x1eb1, c_lflags=0, c_line=0, c_cc[VMIN]=0, c_cc[VTIME]=3, c_cc="\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"}) = 0 write(3, "\2\1\3\24", 4) = 4read(3, "", 1) = 0
There is no responce to the packet. Without the tty patch SieFS works; 2.6.9 (where locking fixes are already applied) also works.
The bug might really be in the pl2303 driver (the 2.4 version is missing some patches which are in 2.6.x). Will try to investigate this further...