diff options
| author | Peter Hurley <[email protected]> | 2014-11-05 12:12:45 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <[email protected]> | 2014-11-05 18:24:10 -0800 |
| commit | c8483bc9deff9bf9118aaab2e840b973b75cac3e (patch) | |
| tree | 4c6af9da2f1b01525014c8680f4d3c8955b54e12 | |
| parent | 3ee175d9d9f9be0e345f7237ee921e58f68afdd7 (diff) | |
tty: Invert tty_lock/ldisc_sem lock order
Dropping the tty lock to acquire the tty->ldisc_sem allows several
race conditions (such as hangup while changing the ldisc) which requires
extra states and testing. The ldisc_sem->tty_lock lock order has
not been required since tty buffer ownership was moved to tty_port.
Reviewed-by: Alan Cox <[email protected]>
Signed-off-by: Peter Hurley <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
| -rw-r--r-- | drivers/tty/tty_ldisc.c | 7 |
1 files changed, 3 insertions, 4 deletions
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 332a622b7203..28858ebe2912 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -523,9 +523,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); + tty_lock(tty); retval = tty_ldisc_lock_pair_timeout(tty, o_tty, 5 * HZ); if (retval) { tty_ldisc_put(new_ldisc); + tty_unlock(tty); return retval; } @@ -536,11 +538,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (tty->ldisc->ops->num == ldisc) { tty_ldisc_enable_pair(tty, o_tty); tty_ldisc_put(new_ldisc); + tty_unlock(tty); return 0; } old_ldisc = tty->ldisc; - tty_lock(tty); if (test_bit(TTY_HUPPING, &tty->flags) || test_bit(TTY_HUPPED, &tty->flags)) { @@ -675,8 +677,6 @@ void tty_ldisc_hangup(struct tty_struct *tty) wake_up_interruptible_poll(&tty->write_wait, POLLOUT); wake_up_interruptible_poll(&tty->read_wait, POLLIN); - tty_unlock(tty); - /* * Shutdown the current line discipline, and reset it to * N_TTY if need be. @@ -684,7 +684,6 @@ void tty_ldisc_hangup(struct tty_struct *tty) * Avoid racing set_ldisc or tty_ldisc_release */ tty_ldisc_lock_pair(tty, tty->link); - tty_lock(tty); if (tty->ldisc) { |