From f53a2ade0bb9f2a81f473e6469155172a96b7c38 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 9 Oct 2009 12:56:41 +0100 Subject: tty: esp: remove broken driver The ESP driver has been marked broken for years. It's an old ISA device that clearly nobody cares about any more. Remove it Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- include/linux/Kbuild | 1 - include/linux/hayesesp.h | 114 ----------------------------------------------- 2 files changed, 115 deletions(-) delete mode 100644 include/linux/hayesesp.h (limited to 'include') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 5a5385749e16..f72914db2a11 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -214,7 +214,6 @@ unifdef-y += futex.h unifdef-y += fs.h unifdef-y += gameport.h unifdef-y += generic_serial.h -unifdef-y += hayesesp.h unifdef-y += hdlcdrv.h unifdef-y += hdlc.h unifdef-y += hdreg.h diff --git a/include/linux/hayesesp.h b/include/linux/hayesesp.h deleted file mode 100644 index 92b08cfe4a75..000000000000 --- a/include/linux/hayesesp.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef HAYESESP_H -#define HAYESESP_H - -struct hayes_esp_config { - short flow_on; - short flow_off; - short rx_trigger; - short tx_trigger; - short pio_threshold; - unsigned char rx_timeout; - char dma_channel; -}; - -#ifdef __KERNEL__ - -#define ESP_DMA_CHANNEL 0 -#define ESP_RX_TRIGGER 768 -#define ESP_TX_TRIGGER 768 -#define ESP_FLOW_OFF 1016 -#define ESP_FLOW_ON 944 -#define ESP_RX_TMOUT 128 -#define ESP_PIO_THRESHOLD 32 - -#define ESP_IN_MAJOR 57 /* major dev # for dial in */ -#define ESP_OUT_MAJOR 58 /* major dev # for dial out */ -#define ESPC_SCALE 3 -#define UART_ESI_BASE 0x00 -#define UART_ESI_SID 0x01 -#define UART_ESI_RX 0x02 -#define UART_ESI_TX 0x02 -#define UART_ESI_CMD1 0x04 -#define UART_ESI_CMD2 0x05 -#define UART_ESI_STAT1 0x04 -#define UART_ESI_STAT2 0x05 -#define UART_ESI_RWS 0x07 - -#define UART_IER_DMA_TMOUT 0x80 -#define UART_IER_DMA_TC 0x08 - -#define ESI_SET_IRQ 0x04 -#define ESI_SET_DMA_TMOUT 0x05 -#define ESI_SET_SRV_MASK 0x06 -#define ESI_SET_ERR_MASK 0x07 -#define ESI_SET_FLOW_CNTL 0x08 -#define ESI_SET_FLOW_CHARS 0x09 -#define ESI_SET_FLOW_LVL 0x0a -#define ESI_SET_TRIGGER 0x0b -#define ESI_SET_RX_TIMEOUT 0x0c -#define ESI_SET_FLOW_TMOUT 0x0d -#define ESI_WRITE_UART 0x0e -#define ESI_READ_UART 0x0f -#define ESI_SET_MODE 0x10 -#define ESI_GET_ERR_STAT 0x12 -#define ESI_GET_UART_STAT 0x13 -#define ESI_GET_RX_AVAIL 0x14 -#define ESI_GET_TX_AVAIL 0x15 -#define ESI_START_DMA_RX 0x16 -#define ESI_START_DMA_TX 0x17 -#define ESI_ISSUE_BREAK 0x1a -#define ESI_FLUSH_RX 0x1b -#define ESI_FLUSH_TX 0x1c -#define ESI_SET_BAUD 0x1d -#define ESI_SET_ENH_IRQ 0x1f -#define ESI_SET_REINTR 0x20 -#define ESI_SET_PRESCALAR 0x23 -#define ESI_NO_COMMAND 0xff - -#define ESP_STAT_RX_TIMEOUT 0x01 -#define ESP_STAT_DMA_RX 0x02 -#define ESP_STAT_DMA_TX 0x04 -#define ESP_STAT_NEVER_DMA 0x08 -#define ESP_STAT_USE_PIO 0x10 - -#define ESP_MAGIC 0x53ee -#define ESP_XMIT_SIZE 4096 - -struct esp_struct { - int magic; - struct tty_port port; - spinlock_t lock; - int io_port; - int irq; - int read_status_mask; - int ignore_status_mask; - int timeout; - int stat_flags; - int custom_divisor; - int close_delay; - unsigned short closing_wait; - unsigned short closing_wait2; - int IER; /* Interrupt Enable Register */ - int MCR; /* Modem control register */ - unsigned long last_active; - int line; - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - wait_queue_head_t break_wait; - struct async_icount icount; /* kernel counters for the 4 input interrupts */ - struct hayes_esp_config config; /* port configuration */ - struct esp_struct *next_port; /* For the linked list */ -}; - -struct esp_pio_buffer { - unsigned char data[1024]; - struct esp_pio_buffer *next; -}; - -#endif /* __KERNEL__ */ - - -#endif /* ESP_H */ - -- cgit v1.2.3 From 64bc397914265a9ead8d73b63bb31ab3bdd25f67 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 6 Oct 2009 16:06:11 +0100 Subject: tty_port: add "tty_port_open" helper For the moment this just moves the USB logic over and fixes the 'what if we open and hangup at the same time' race noticed by Oliver Neukum. Signed-off-by: Alan Cox Cc: Alan Stern Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/char/tty_port.c | 36 +++++++++++++++++++++++++++++- drivers/usb/serial/usb-serial.c | 49 +++++++++++++++++------------------------ include/linux/tty.h | 10 ++++++++- 3 files changed, 64 insertions(+), 31 deletions(-) (limited to 'include') diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c index c63f3d33914a..b22a61a4fbe5 100644 --- a/drivers/char/tty_port.c +++ b/drivers/char/tty_port.c @@ -99,10 +99,11 @@ EXPORT_SYMBOL(tty_port_tty_set); static void tty_port_shutdown(struct tty_port *port) { + mutex_lock(&port->mutex); if (port->ops->shutdown && test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) port->ops->shutdown(port); - + mutex_unlock(&port->mutex); } /** @@ -381,3 +382,36 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty, tty_port_tty_set(port, NULL); } EXPORT_SYMBOL(tty_port_close); + +int tty_port_open(struct tty_port *port, struct tty_struct *tty, + struct file *filp) +{ + spin_lock_irq(&port->lock); + if (!tty_hung_up_p(filp)) + ++port->count; + spin_unlock_irq(&port->lock); + tty_port_tty_set(port, tty); + + /* + * Do the device-specific open only if the hardware isn't + * already initialized. Serialize open and shutdown using the + * port mutex. + */ + + mutex_lock(&port->mutex); + + if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) { + if (port->ops->activate) { + int retval = port->ops->activate(port, tty); + if (retval) { + mutex_unlock(&port->mutex); + return retval; + } + } + set_bit(ASYNCB_INITIALIZED, &port->flags); + } + mutex_unlock(&port->mutex); + return tty_port_block_til_ready(port, tty, filp); +} + +EXPORT_SYMBOL(tty_port_open); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index bd3fa7ff15b1..b0649d92251f 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -247,41 +247,31 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) return retval; } -static int serial_open(struct tty_struct *tty, struct file *filp) +static int serial_activate(struct tty_port *tport, struct tty_struct *tty) { - struct usb_serial_port *port = tty->driver_data; + struct usb_serial_port *port = + container_of(tport, struct usb_serial_port, port); struct usb_serial *serial = port->serial; int retval; - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&port->port.lock); - if (!tty_hung_up_p(filp)) - ++port->port.count; - spin_unlock_irq(&port->port.lock); - tty_port_tty_set(&port->port, tty); + if (mutex_lock_interruptible(&port->mutex)) + return -ERESTARTSYS; + mutex_lock(&serial->disc_mutex); + if (serial->disconnected) + retval = -ENODEV; + else + retval = port->serial->type->open(tty, port); + mutex_unlock(&serial->disc_mutex); + mutex_unlock(&port->mutex); + return retval; +} - /* Do the device-specific open only if the hardware isn't - * already initialized. - */ - if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) { - if (mutex_lock_interruptible(&port->mutex)) - return -ERESTARTSYS; - mutex_lock(&serial->disc_mutex); - if (serial->disconnected) - retval = -ENODEV; - else - retval = port->serial->type->open(tty, port); - mutex_unlock(&serial->disc_mutex); - mutex_unlock(&port->mutex); - if (retval) - return retval; - set_bit(ASYNCB_INITIALIZED, &port->port.flags); - } +static int serial_open(struct tty_struct *tty, struct file *filp) +{ + struct usb_serial_port *port = tty->driver_data; - /* Now do the correct tty layer semantics */ - retval = tty_port_block_til_ready(&port->port, tty, filp); - return retval; + dbg("%s - port %d", __func__, port->number); + return tty_port_open(&port->port, tty, filp); } /** @@ -725,6 +715,7 @@ static void serial_dtr_rts(struct tty_port *port, int on) static const struct tty_port_operations serial_port_ops = { .carrier_raised = serial_carrier_raised, .dtr_rts = serial_dtr_rts, + .activate = serial_activate, }; int usb_serial_probe(struct usb_interface *interface, diff --git a/include/linux/tty.h b/include/linux/tty.h index f0f43d08d8b8..6352ac257fcb 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -190,9 +190,15 @@ struct tty_port_operations { /* Control the DTR line */ void (*dtr_rts)(struct tty_port *port, int raise); /* Called when the last close completes or a hangup finishes - IFF the port was initialized. Do not use to free resources */ + IFF the port was initialized. Do not use to free resources. Called + under the port mutex to serialize against activate/shutdowns */ void (*shutdown)(struct tty_port *port); void (*drop)(struct tty_port *port); + /* Called under the port mutex from tty_port_open, serialized using + the port mutex */ + /* FIXME: long term getting the tty argument *out* of this would be + good for consoles */ + int (*activate)(struct tty_port *port, struct tty_struct *tty); }; struct tty_port { @@ -467,6 +473,8 @@ extern int tty_port_close_start(struct tty_port *port, extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); extern void tty_port_close(struct tty_port *port, struct tty_struct *tty, struct file *filp); +extern int tty_port_open(struct tty_port *port, + struct tty_struct *tty, struct file *filp); extern inline int tty_port_users(struct tty_port *port) { return port->count + port->blocked_open; -- cgit v1.2.3 From 82fc5943430e3cbf15033ed4186a73f90906345d Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 6 Oct 2009 16:06:46 +0100 Subject: usb_serial: Kill port mutex The tty port has a port mutex used for all the port related locking so we don't need the one in the USB serial layer any more. Signed-off-by: Alan Cox Cc: Alan Stern Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/opticon.c | 4 ++-- drivers/usb/serial/usb-serial.c | 1 - include/linux/usb/serial.h | 3 --- 3 files changed, 2 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 80f59b6350cb..c03fdc0242dd 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -501,12 +501,12 @@ static int opticon_resume(struct usb_interface *intf) struct usb_serial_port *port = serial->port[0]; int result; - mutex_lock(&port->mutex); + mutex_lock(&port->port.mutex); if (port->port.count) result = usb_submit_urb(priv->bulk_read_urb, GFP_NOIO); else result = 0; - mutex_unlock(&port->mutex); + mutex_unlock(&port->port.mutex); return result; } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 829a46684e1d..4543f359be75 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -897,7 +897,6 @@ int usb_serial_probe(struct usb_interface *interface, spin_lock_init(&port->lock); /* Keep this for private driver use for the moment but should probably go away */ - mutex_init(&port->mutex); INIT_WORK(&port->work, usb_serial_port_work); serial->port[i] = port; port->dev.parent = &interface->dev; diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index ce911ebf91e8..acf6e457c04b 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -39,8 +39,6 @@ enum port_dev_state { * @serial: pointer back to the struct usb_serial owner of this port. * @port: pointer to the corresponding tty_port for this port. * @lock: spinlock to grab when updating portions of this structure. - * @mutex: mutex used to synchronize serial_open() and serial_close() - * access for this port. * @number: the number of the port (the minor number). * @interrupt_in_buffer: pointer to the interrupt in buffer for this port. * @interrupt_in_urb: pointer to the interrupt in struct urb for this port. @@ -77,7 +75,6 @@ struct usb_serial_port { struct usb_serial *serial; struct tty_port port; spinlock_t lock; - struct mutex mutex; unsigned char number; unsigned char *interrupt_in_buffer; -- cgit v1.2.3 From 44e4909e453eaa09c7de409fc9ee4ebefd986c1c Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 30 Nov 2009 13:16:41 +0000 Subject: tty: tty_port: Change the buffer allocator locking We want to be able to do this without regard for the activate/own open method being used which causes a problem using port->mutex. Add another mutex for now. Once everything uses port_open to do buffer allocs we can kill it back off Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/char/tty_port.c | 9 +++++---- include/linux/tty.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c index dd471d63fae2..3ef644a2e517 100644 --- a/drivers/char/tty_port.c +++ b/drivers/char/tty_port.c @@ -25,6 +25,7 @@ void tty_port_init(struct tty_port *port) init_waitqueue_head(&port->close_wait); init_waitqueue_head(&port->delta_msr_wait); mutex_init(&port->mutex); + mutex_init(&port->buf_mutex); spin_lock_init(&port->lock); port->close_delay = (50 * HZ) / 100; port->closing_wait = (3000 * HZ) / 100; @@ -34,10 +35,10 @@ EXPORT_SYMBOL(tty_port_init); int tty_port_alloc_xmit_buf(struct tty_port *port) { /* We may sleep in get_zeroed_page() */ - mutex_lock(&port->mutex); + mutex_lock(&port->buf_mutex); if (port->xmit_buf == NULL) port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); - mutex_unlock(&port->mutex); + mutex_unlock(&port->buf_mutex); if (port->xmit_buf == NULL) return -ENOMEM; return 0; @@ -46,12 +47,12 @@ EXPORT_SYMBOL(tty_port_alloc_xmit_buf); void tty_port_free_xmit_buf(struct tty_port *port) { - mutex_lock(&port->mutex); + mutex_lock(&port->buf_mutex); if (port->xmit_buf != NULL) { free_page((unsigned long)port->xmit_buf); port->xmit_buf = NULL; } - mutex_unlock(&port->mutex); + mutex_unlock(&port->buf_mutex); } EXPORT_SYMBOL(tty_port_free_xmit_buf); diff --git a/include/linux/tty.h b/include/linux/tty.h index 6352ac257fcb..e9269ca1542a 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -212,6 +212,7 @@ struct tty_port { wait_queue_head_t delta_msr_wait; /* Modem status change */ unsigned long flags; /* TTY flags ASY_*/ struct mutex mutex; /* Locking */ + struct mutex buf_mutex; /* Buffer alloc lock */ unsigned char *xmit_buf; /* Optional buffer */ unsigned int close_delay; /* Close port delay */ unsigned int closing_wait; /* Delay for output */ -- cgit v1.2.3 From 568aafc627e2978509e8a80c640ba534d1e843cc Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 30 Nov 2009 13:17:14 +0000 Subject: tty: tty_port: Add a kref object to the tty port Users of tty port need a way to refcount ports when hotplugging is involved. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/char/tty_port.c | 18 ++++++++++++++++++ include/linux/tty.h | 12 ++++++++++++ 2 files changed, 30 insertions(+) (limited to 'include') diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c index 84006de2900f..be492dd66437 100644 --- a/drivers/char/tty_port.c +++ b/drivers/char/tty_port.c @@ -29,6 +29,7 @@ void tty_port_init(struct tty_port *port) spin_lock_init(&port->lock); port->close_delay = (50 * HZ) / 100; port->closing_wait = (3000 * HZ) / 100; + kref_init(&port->kref); } EXPORT_SYMBOL(tty_port_init); @@ -56,6 +57,23 @@ void tty_port_free_xmit_buf(struct tty_port *port) } EXPORT_SYMBOL(tty_port_free_xmit_buf); +static void tty_port_destructor(struct kref *kref) +{ + struct tty_port *port = container_of(kref, struct tty_port, kref); + if (port->xmit_buf) + free_page((unsigned long)port->xmit_buf); + if (port->ops->destruct) + port->ops->destruct(port); + else + kfree(port); +} + +void tty_port_put(struct tty_port *port) +{ + if (port) + kref_put(&port->kref, tty_port_destructor); +} +EXPORT_SYMBOL(tty_port_put); /** * tty_port_tty_get - get a tty reference diff --git a/include/linux/tty.h b/include/linux/tty.h index e9269ca1542a..e6da667ba34d 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -199,6 +199,8 @@ struct tty_port_operations { /* FIXME: long term getting the tty argument *out* of this would be good for consoles */ int (*activate)(struct tty_port *port, struct tty_struct *tty); + /* Called on the final put of a port */ + void (*destruct)(struct tty_port *port); }; struct tty_port { @@ -219,6 +221,7 @@ struct tty_port { int drain_delay; /* Set to zero if no pure time based drain is needed else set to size of fifo */ + struct kref kref; /* Ref counter */ }; /* @@ -461,6 +464,15 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay); extern void tty_port_init(struct tty_port *port); extern int tty_port_alloc_xmit_buf(struct tty_port *port); extern void tty_port_free_xmit_buf(struct tty_port *port); +extern void tty_port_put(struct tty_port *port); + +extern inline struct tty_port *tty_port_get(struct tty_port *port) +{ + if (port) + kref_get(&port->kref); + return port; +} + extern struct tty_struct *tty_port_tty_get(struct tty_port *port); extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); extern int tty_port_carrier_raised(struct tty_port *port); -- cgit v1.2.3 From 6ed847d8efd08658ece10c9129cd511c8d7452cd Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 30 Nov 2009 13:17:30 +0000 Subject: tty: isicom: sort out the board init logic Split this into two flags - INIT meaning the board is set up and ACTIVE meaning the board has ports open. Remove the broken HUPCL casing and push the counts somewhere sensible. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/char/isicom.c | 41 +++++++++++------------------------------ include/linux/isicom.h | 1 + 2 files changed, 12 insertions(+), 30 deletions(-) (limited to 'include') diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index e7be3ec6d21c..1e91c302ee42 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -793,21 +793,19 @@ static inline void isicom_setup_board(struct isi_board *bp) { int channel; struct isi_port *port; - unsigned long flags; - spin_lock_irqsave(&bp->card_lock, flags); - if (bp->status & BOARD_ACTIVE) { - spin_unlock_irqrestore(&bp->card_lock, flags); - return; - } - port = bp->ports; - bp->status |= BOARD_ACTIVE; - for (channel = 0; channel < bp->port_count; channel++, port++) - drop_dtr_rts(port); bp->count++; - spin_unlock_irqrestore(&bp->card_lock, flags); + if (!(bp->status & BOARD_INIT)) { + port = bp->ports; + for (channel = 0; channel < bp->port_count; channel++, port++) + drop_dtr_rts(port); + } + bp->status |= BOARD_ACTIVE | BOARD_INIT; } +/* Activate and thus setup board are protected from races against shutdown + by the tty_port mutex */ + static int isicom_activate(struct tty_port *tport, struct tty_struct *tty) { struct isi_port *port = container_of(tport, struct isi_port, port); @@ -884,19 +882,10 @@ static int isicom_open(struct tty_struct *tty, struct file *filp) /* close et all */ -static inline void isicom_shutdown_board(struct isi_board *bp) -{ - if (bp->status & BOARD_ACTIVE) - bp->status &= ~BOARD_ACTIVE; -} - /* card->lock HAS to be held */ static void isicom_shutdown_port(struct isi_port *port) { struct isi_board *card = port->card; - struct tty_struct *tty; - - tty = tty_port_tty_get(&port->port); tty_port_free_xmit_buf(&port->port); if (--card->count < 0) { @@ -904,17 +893,9 @@ static void isicom_shutdown_port(struct isi_port *port) card->base, card->count); card->count = 0; } - /* last port was closed, shutdown that board too */ - if (tty && C_HUPCL(tty)) { - /* FIXME: this logic is bogus - it's the old logic that was - bogus before but it still wants fixing */ - if (!card->count) { - if (card->status & BOARD_ACTIVE) - card->status &= ~BOARD_ACTIVE; - } - } - tty_kref_put(tty); + if (!card->count) + card->status &= BOARD_ACTIVE; } static void isicom_flush_buffer(struct tty_struct *tty) diff --git a/include/linux/isicom.h b/include/linux/isicom.h index bbd42197298f..b92e05650639 100644 --- a/include/linux/isicom.h +++ b/include/linux/isicom.h @@ -67,6 +67,7 @@ #define FIRMWARE_LOADED 0x0001 #define BOARD_ACTIVE 0x0002 +#define BOARD_INIT 0x0004 /* isi_port status bitmap */ -- cgit v1.2.3 From eeb89d918c2fa2b809e464136bbafdaec2aacb30 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 30 Nov 2009 13:18:29 +0000 Subject: tty: push the BKL down into the handlers a bit Start trying to untangle the remaining BKL mess Updated to fix missing unlock_kernel noted by Dan Carpenter Signed-off-by: Alan "I must be out of my tree" Cox Signed-off-by: Greg Kroah-Hartman --- drivers/char/pty.c | 2 +- drivers/char/tty_io.c | 141 +++++++++++++++++++++++++++-------------------- drivers/char/tty_ldisc.c | 13 +++++ include/linux/tty.h | 2 +- 4 files changed, 95 insertions(+), 63 deletions(-) (limited to 'include') diff --git a/drivers/char/pty.c b/drivers/char/pty.c index d86c0bc05c1c..385c44b3034f 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -659,7 +659,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp) if (!retval) return 0; out1: - tty_release_dev(filp); + tty_release(inode, filp); return retval; out: devpts_kill_index(inode, index); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 59499ee0fe6a..1e2413093615 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -142,7 +142,6 @@ ssize_t redirected_tty_write(struct file *, const char __user *, size_t, loff_t *); static unsigned int tty_poll(struct file *, poll_table *); static int tty_open(struct inode *, struct file *); -static int tty_release(struct inode *, struct file *); long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); #ifdef CONFIG_COMPAT static long tty_compat_ioctl(struct file *file, unsigned int cmd, @@ -1017,14 +1016,16 @@ out: void tty_write_message(struct tty_struct *tty, char *msg) { - lock_kernel(); if (tty) { mutex_lock(&tty->atomic_write_lock); - if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) + lock_kernel(); + if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { + unlock_kernel(); tty->ops->write(tty, msg, strlen(msg)); + } else + unlock_kernel(); tty_write_unlock(tty); } - unlock_kernel(); return; } @@ -1202,14 +1203,21 @@ static int tty_driver_install_tty(struct tty_driver *driver, struct tty_struct *tty) { int idx = tty->index; + int ret; - if (driver->ops->install) - return driver->ops->install(driver, tty); + if (driver->ops->install) { + lock_kernel(); + ret = driver->ops->install(driver, tty); + unlock_kernel(); + return ret; + } if (tty_init_termios(tty) == 0) { + lock_kernel(); tty_driver_kref_get(driver); tty->count++; driver->ttys[idx] = tty; + unlock_kernel(); return 0; } return -ENOMEM; @@ -1302,10 +1310,14 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, struct tty_struct *tty; int retval; + lock_kernel(); /* Check if pty master is being opened multiple times */ if (driver->subtype == PTY_TYPE_MASTER && - (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) + (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) { + unlock_kernel(); return ERR_PTR(-EIO); + } + unlock_kernel(); /* * First time open is complex, especially for PTY devices. @@ -1335,8 +1347,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, * If we fail here just call release_tty to clean up. No need * to decrement the use counts, as release_tty doesn't care. */ - + lock_kernel(); retval = tty_ldisc_setup(tty, tty->link); + unlock_kernel(); if (retval) goto release_mem_out; return tty; @@ -1350,7 +1363,9 @@ release_mem_out: if (printk_ratelimit()) printk(KERN_INFO "tty_init_dev: ldisc open failed, " "clearing slot %d\n", idx); + lock_kernel(); release_tty(tty, idx); + unlock_kernel(); return ERR_PTR(retval); } @@ -1464,7 +1479,17 @@ static void release_tty(struct tty_struct *tty, int idx) tty_kref_put(tty); } -/* +/** + * tty_release - vfs callback for close + * @inode: inode of tty + * @filp: file pointer for handle to tty + * + * Called the last time each file handle is closed that references + * this tty. There may however be several such references. + * + * Locking: + * Takes bkl. See tty_release_dev + * * Even releasing the tty structures is a tricky business.. We have * to be very careful that the structures are all released at the * same time, as interrupts might otherwise get the wrong pointers. @@ -1472,20 +1497,20 @@ static void release_tty(struct tty_struct *tty, int idx) * WSH 09/09/97: rewritten to avoid some nasty race conditions that could * lead to double frees or releasing memory still in use. */ -void tty_release_dev(struct file *filp) + +int tty_release(struct inode *inode, struct file *filp) { struct tty_struct *tty, *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; int devpts; int idx; char buf[64]; - struct inode *inode; - inode = filp->f_path.dentry->d_inode; tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, inode, "tty_release_dev")) - return; + return 0; + lock_kernel(); check_tty_count(tty, "tty_release_dev"); tty_fasync(-1, filp, 0); @@ -1500,19 +1525,22 @@ void tty_release_dev(struct file *filp) if (idx < 0 || idx >= tty->driver->num) { printk(KERN_DEBUG "tty_release_dev: bad idx when trying to " "free (%s)\n", tty->name); - return; + unlock_kernel(); + return 0; } if (!devpts) { if (tty != tty->driver->ttys[idx]) { + unlock_kernel(); printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty " "for (%s)\n", idx, tty->name); - return; + return 0; } if (tty->termios != tty->driver->termios[idx]) { + unlock_kernel(); printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios " "for (%s)\n", idx, tty->name); - return; + return 0; } } #endif @@ -1526,26 +1554,30 @@ void tty_release_dev(struct file *filp) if (tty->driver->other && !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { if (o_tty != tty->driver->other->ttys[idx]) { + unlock_kernel(); printk(KERN_DEBUG "tty_release_dev: other->table[%d] " "not o_tty for (%s)\n", idx, tty->name); - return; + return 0 ; } if (o_tty->termios != tty->driver->other->termios[idx]) { + unlock_kernel(); printk(KERN_DEBUG "tty_release_dev: other->termios[%d] " "not o_termios for (%s)\n", idx, tty->name); - return; + return 0; } if (o_tty->link != tty) { + unlock_kernel(); printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n"); - return; + return 0; } } #endif if (tty->ops->close) tty->ops->close(tty, filp); + unlock_kernel(); /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1568,6 +1600,7 @@ void tty_release_dev(struct file *filp) opens on /dev/tty */ mutex_lock(&tty_mutex); + lock_kernel(); tty_closing = tty->count <= 1; o_tty_closing = o_tty && (o_tty->count <= (pty_master ? 1 : 0)); @@ -1598,6 +1631,7 @@ void tty_release_dev(struct file *filp) printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue " "active!\n", tty_name(tty, buf)); + unlock_kernel(); mutex_unlock(&tty_mutex); schedule(); } @@ -1661,8 +1695,10 @@ void tty_release_dev(struct file *filp) mutex_unlock(&tty_mutex); /* check whether both sides are closing ... */ - if (!tty_closing || (o_tty && !o_tty_closing)) - return; + if (!tty_closing || (o_tty && !o_tty_closing)) { + unlock_kernel(); + return 0; + } #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "freeing tty structure..."); @@ -1680,10 +1716,12 @@ void tty_release_dev(struct file *filp) /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); + unlock_kernel(); + return 0; } /** - * __tty_open - open a tty device + * tty_open - open a tty device * @inode: inode of device file * @filp: file pointer to tty * @@ -1703,7 +1741,7 @@ void tty_release_dev(struct file *filp) * ->siglock protects ->signal/->sighand */ -static int __tty_open(struct inode *inode, struct file *filp) +static int tty_open(struct inode *inode, struct file *filp) { struct tty_struct *tty = NULL; int noctty, retval; @@ -1720,10 +1758,12 @@ retry_open: retval = 0; mutex_lock(&tty_mutex); + lock_kernel(); if (device == MKDEV(TTYAUX_MAJOR, 0)) { tty = get_current_tty(); if (!tty) { + unlock_kernel(); mutex_unlock(&tty_mutex); return -ENXIO; } @@ -1755,12 +1795,14 @@ retry_open: goto got_driver; } } + unlock_kernel(); mutex_unlock(&tty_mutex); return -ENODEV; } driver = get_tty_driver(device, &index); if (!driver) { + unlock_kernel(); mutex_unlock(&tty_mutex); return -ENODEV; } @@ -1770,6 +1812,7 @@ got_driver: tty = tty_driver_lookup_tty(driver, inode, index); if (IS_ERR(tty)) { + unlock_kernel(); mutex_unlock(&tty_mutex); return PTR_ERR(tty); } @@ -1784,8 +1827,10 @@ got_driver: mutex_unlock(&tty_mutex); tty_driver_kref_put(driver); - if (IS_ERR(tty)) + if (IS_ERR(tty)) { + unlock_kernel(); return PTR_ERR(tty); + } filp->private_data = tty; file_move(filp, &tty->tty_files); @@ -1813,11 +1858,15 @@ got_driver: printk(KERN_DEBUG "error %d in opening %s...", retval, tty->name); #endif - tty_release_dev(filp); - if (retval != -ERESTARTSYS) + tty_release(inode, filp); + if (retval != -ERESTARTSYS) { + unlock_kernel(); return retval; - if (signal_pending(current)) + } + if (signal_pending(current)) { + unlock_kernel(); return retval; + } schedule(); /* * Need to reset f_op in case a hangup happened. @@ -1826,8 +1875,11 @@ got_driver: filp->f_op = &tty_fops; goto retry_open; } + unlock_kernel(); + mutex_lock(&tty_mutex); + lock_kernel(); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && @@ -1835,44 +1887,13 @@ got_driver: tty->session == NULL) __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); + unlock_kernel(); mutex_unlock(&tty_mutex); return 0; } -/* BKL pushdown: scary code avoidance wrapper */ -static int tty_open(struct inode *inode, struct file *filp) -{ - int ret; - - lock_kernel(); - ret = __tty_open(inode, filp); - unlock_kernel(); - return ret; -} - - -/** - * tty_release - vfs callback for close - * @inode: inode of tty - * @filp: file pointer for handle to tty - * - * Called the last time each file handle is closed that references - * this tty. There may however be several such references. - * - * Locking: - * Takes bkl. See tty_release_dev - */ - -static int tty_release(struct inode *inode, struct file *filp) -{ - lock_kernel(); - tty_release_dev(filp); - unlock_kernel(); - return 0; -} - /** * tty_poll - check tty status * @filp: file being polled @@ -2317,9 +2338,7 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) if (get_user(ldisc, p)) return -EFAULT; - lock_kernel(); ret = tty_set_ldisc(tty, ldisc); - unlock_kernel(); return ret; } diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index feb55075819b..d914e77f7f01 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -34,6 +34,8 @@ #include #include +#include /* For the moment */ + #include #include @@ -545,6 +547,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); + lock_kernel(); /* * We need to look at the tty locking here for pty/tty pairs * when both sides try to change in parallel. @@ -558,6 +561,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) */ if (tty->ldisc->ops->num == ldisc) { + unlock_kernel(); tty_ldisc_put(new_ldisc); return 0; } @@ -569,6 +573,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_wait_until_sent(tty, 0); + unlock_kernel(); mutex_lock(&tty->ldisc_mutex); /* @@ -582,6 +587,9 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); mutex_lock(&tty->ldisc_mutex); } + + lock_kernel(); + set_bit(TTY_LDISC_CHANGING, &tty->flags); /* @@ -592,6 +600,8 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty->receive_room = 0; o_ldisc = tty->ldisc; + + unlock_kernel(); /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit @@ -617,12 +627,14 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) flush_scheduled_work(); mutex_lock(&tty->ldisc_mutex); + lock_kernel(); if (test_bit(TTY_HUPPED, &tty->flags)) { /* We were raced by the hangup method. It will have stomped the ldisc data and closed the ldisc down */ clear_bit(TTY_LDISC_CHANGING, &tty->flags); mutex_unlock(&tty->ldisc_mutex); tty_ldisc_put(new_ldisc); + unlock_kernel(); return -EIO; } @@ -664,6 +676,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (o_work) schedule_delayed_work(&o_tty->buf.work, 1); mutex_unlock(&tty->ldisc_mutex); + unlock_kernel(); return retval; } diff --git a/include/linux/tty.h b/include/linux/tty.h index e6da667ba34d..405a9035fe40 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -449,7 +449,7 @@ extern void initialize_tty_struct(struct tty_struct *tty, struct tty_driver *driver, int idx); extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, int first_ok); -extern void tty_release_dev(struct file *filp); +extern int tty_release(struct inode *inode, struct file *filp); extern int tty_init_termios(struct tty_struct *tty); extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty); -- cgit v1.2.3