summaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_ldisc.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-13 19:02:05 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-13 19:02:05 +0100
commit67ad058d97b8cff441211b791d97e5f776b81210 (patch)
tree4ee85611b11fe91a8a8eb1f7561484e7abb2f85a /drivers/tty/tty_ldisc.c
parentMerge tag 'usb-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/greg... (diff)
parentdrivers/tty/serial: delete unused MODULE_DEVICE_TABLE from atmel_serial.c (diff)
downloadlinux-67ad058d97b8cff441211b791d97e5f776b81210.tar.xz
linux-67ad058d97b8cff441211b791d97e5f776b81210.zip
Merge tag 'tty-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial updates from Greg KH: "Here is the big serial/tty driver update for 4.5-rc1. Lots of driver updates and some tty core changes. All of these have been in linux-next and the details are in the shortlog" * tag 'tty-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (127 commits) drivers/tty/serial: delete unused MODULE_DEVICE_TABLE from atmel_serial.c serial: sh-sci: Remove cpufreq notifier to fix crash/deadlock serial: 8250: of: Fix the driver and actually compile the 8250_of tty: amba-pl011: use iotype instead of access_32b to track 32-bit I/O tty: amba-pl011: fix earlycon register offsets serial: sh-sci: Drop the sci_fck clock fallback sh: sh7734: Correct SCIF type for BRG sh: Remove sci_ick clock alias sh: Rename sci_ick and sci_fck clock to fck serial: sh-sci: Add support for optional BRG on (H)SCIF serial: sh-sci: Add support for optional external (H)SCK input serial: sh-sci: Prepare for multiple sampling clock sources serial: sh-sci: Correct SCIF type on R-Car for BRG serial: sh-sci: Correct SCIF type on RZ/A1H serial: sh-sci: Replace struct sci_port_info by type/regtype encoding serial: sh-sci: Add BRG register definitions serial: sh-sci: Take into account sampling rate for max baud rate serial: sh-sci: Merge sci_scbrr_calc() and sci_baud_calc_hscif() serial: sh-sci: Avoid calculating the receive margin for HSCIF serial: sh-sci: Improve bit rate error calculation for HSCIF ...
Diffstat (limited to 'drivers/tty/tty_ldisc.c')
-rw-r--r--drivers/tty/tty_ldisc.c51
1 files changed, 21 insertions, 30 deletions
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 629e3c865072..a054d03c22e7 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -185,7 +185,7 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc)
*
* Complement of tty_ldisc_get().
*/
-static inline void tty_ldisc_put(struct tty_ldisc *ld)
+static void tty_ldisc_put(struct tty_ldisc *ld)
{
if (WARN_ON_ONCE(!ld))
return;
@@ -417,6 +417,10 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
* they are not on hot paths so a little discipline won't do
* any harm.
*
+ * The line discipline-related tty_struct fields are reset to
+ * prevent the ldisc driver from re-using stale information for
+ * the new ldisc instance.
+ *
* Locking: takes termios_rwsem
*/
@@ -425,6 +429,9 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
down_write(&tty->termios_rwsem);
tty->termios.c_line = num;
up_write(&tty->termios_rwsem);
+
+ tty->disc_data = NULL;
+ tty->receive_room = 0;
}
/**
@@ -529,34 +536,21 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty_lock(tty);
retval = tty_ldisc_lock(tty, 5 * HZ);
- if (retval) {
- tty_ldisc_put(new_ldisc);
- tty_unlock(tty);
- return retval;
- }
+ if (retval)
+ goto err;
- /*
- * Check the no-op case
- */
+ /* Check the no-op case */
+ if (tty->ldisc->ops->num == ldisc)
+ goto out;
- if (tty->ldisc->ops->num == ldisc) {
- tty_ldisc_unlock(tty);
- tty_ldisc_put(new_ldisc);
- tty_unlock(tty);
- return 0;
+ if (test_bit(TTY_HUPPED, &tty->flags)) {
+ /* We were raced by hangup */
+ retval = -EIO;
+ goto out;
}
old_ldisc = tty->ldisc;
- 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 */
- tty_ldisc_unlock(tty);
- tty_ldisc_put(new_ldisc);
- tty_unlock(tty);
- return -EIO;
- }
-
/* Shutdown the old discipline. */
tty_ldisc_close(tty, old_ldisc);
@@ -582,18 +576,15 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
the old ldisc (if it was restored as part of error cleanup
above). In either case, releasing a single reference from
the old ldisc is correct. */
-
- tty_ldisc_put(old_ldisc);
-
- /*
- * Allow ldisc referencing to occur again
- */
+ new_ldisc = old_ldisc;
+out:
tty_ldisc_unlock(tty);
/* Restart the work queue in case no characters kick it off. Safe if
already running */
tty_buffer_restart_work(tty->port);
-
+err:
+ tty_ldisc_put(new_ldisc); /* drop the extra reference */
tty_unlock(tty);
return retval;
}