diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2014-06-16 09:17:06 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-07-10 19:06:49 -0400 |
commit | e359a4e38d229d53e28905863a1fabf41debd591 (patch) | |
tree | c70f7762dac31dad62188b7b8bb2140bea8b311a /drivers/tty/serial/crisv10.c | |
parent | 5fda7a0e715c32c6dd9a39ebce8429eeafb64b7d (diff) |
tty: Remove tty_hung_up_p() tests from tty drivers' open()
Since at least before 2.6.30, it has not been possible to observe
a hung up file pointer in a tty driver's open() method unless/until
the driver open() releases the tty_lock() (eg., before blocking).
This is because tty_open() adds the file pointer while holding
the tty_lock() _and_ doesn't release the lock until after calling
the tty driver's open() method. [ Before tty_lock(), this was
lock_kernel(). ]
Since __tty_hangup() first waits on the tty_lock() before
enumerating and hanging up the open file pointers, either
__tty_hangup() will wait for the tty_lock() or tty_open() will
not yet have added the file pointer. For example,
CPU 0 | CPU 1
|
tty_open | __tty_hangup
.. | ..
tty_lock | ..
tty_reopen | tty_lock / blocks
.. |
tty_add_file(tty, filp) |
.. |
tty->ops->open(tty, filp) |
tty_port_open |
tty_port_block_til_ready |
.. |
while (1) |
.. |
tty_unlock | / unblocks
schedule | for each filp on tty->tty_files
| f_ops = tty_hung_up_fops;
| ..
| tty_unlock
tty_lock |
.. |
tty_unlock |
Note that since tty_port_block_til_ready() and similar drop
the tty_lock while blocking, when woken, the file pointer
must then be tested for having been hung up.
Also, fix bit-rotted drivers that used extra_count to track the
port->count bump.
CC: Mikael Starvik <starvik@axis.com>
CC: Samuel Ortiz <samuel@sortiz.org>
CC: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Acked-by: Jesper Nilsson <jesper.nilsson@axis.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/crisv10.c')
-rw-r--r-- | drivers/tty/serial/crisv10.c | 15 |
1 files changed, 5 insertions, 10 deletions
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index d567ac5d3af4..58e6f61a87e4 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c | |||
@@ -3831,14 +3831,13 @@ block_til_ready(struct tty_struct *tty, struct file * filp, | |||
3831 | DECLARE_WAITQUEUE(wait, current); | 3831 | DECLARE_WAITQUEUE(wait, current); |
3832 | unsigned long flags; | 3832 | unsigned long flags; |
3833 | int retval; | 3833 | int retval; |
3834 | int do_clocal = 0, extra_count = 0; | 3834 | int do_clocal = 0; |
3835 | 3835 | ||
3836 | /* | 3836 | /* |
3837 | * If the device is in the middle of being closed, then block | 3837 | * If the device is in the middle of being closed, then block |
3838 | * until it's done, and then try again. | 3838 | * until it's done, and then try again. |
3839 | */ | 3839 | */ |
3840 | if (tty_hung_up_p(filp) || | 3840 | if (info->port.flags & ASYNC_CLOSING) { |
3841 | (info->port.flags & ASYNC_CLOSING)) { | ||
3842 | wait_event_interruptible_tty(tty, info->port.close_wait, | 3841 | wait_event_interruptible_tty(tty, info->port.close_wait, |
3843 | !(info->port.flags & ASYNC_CLOSING)); | 3842 | !(info->port.flags & ASYNC_CLOSING)); |
3844 | #ifdef SERIAL_DO_RESTART | 3843 | #ifdef SERIAL_DO_RESTART |
@@ -3879,10 +3878,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, | |||
3879 | info->line, info->port.count); | 3878 | info->line, info->port.count); |
3880 | #endif | 3879 | #endif |
3881 | local_irq_save(flags); | 3880 | local_irq_save(flags); |
3882 | if (!tty_hung_up_p(filp)) { | 3881 | info->port.count--; |
3883 | extra_count++; | ||
3884 | info->port.count--; | ||
3885 | } | ||
3886 | local_irq_restore(flags); | 3882 | local_irq_restore(flags); |
3887 | info->port.blocked_open++; | 3883 | info->port.blocked_open++; |
3888 | while (1) { | 3884 | while (1) { |
@@ -3921,7 +3917,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, | |||
3921 | } | 3917 | } |
3922 | set_current_state(TASK_RUNNING); | 3918 | set_current_state(TASK_RUNNING); |
3923 | remove_wait_queue(&info->port.open_wait, &wait); | 3919 | remove_wait_queue(&info->port.open_wait, &wait); |
3924 | if (extra_count) | 3920 | if (!tty_hung_up_p(filp)) |
3925 | info->port.count++; | 3921 | info->port.count++; |
3926 | info->port.blocked_open--; | 3922 | info->port.blocked_open--; |
3927 | #ifdef SERIAL_DEBUG_OPEN | 3923 | #ifdef SERIAL_DEBUG_OPEN |
@@ -3976,8 +3972,7 @@ rs_open(struct tty_struct *tty, struct file * filp) | |||
3976 | /* | 3972 | /* |
3977 | * If the port is in the middle of closing, bail out now | 3973 | * If the port is in the middle of closing, bail out now |
3978 | */ | 3974 | */ |
3979 | if (tty_hung_up_p(filp) || | 3975 | if (info->port.flags & ASYNC_CLOSING) { |
3980 | (info->port.flags & ASYNC_CLOSING)) { | ||
3981 | wait_event_interruptible_tty(tty, info->port.close_wait, | 3976 | wait_event_interruptible_tty(tty, info->port.close_wait, |
3982 | !(info->port.flags & ASYNC_CLOSING)); | 3977 | !(info->port.flags & ASYNC_CLOSING)); |
3983 | #ifdef SERIAL_DO_RESTART | 3978 | #ifdef SERIAL_DO_RESTART |