diff options
-rw-r--r-- | drivers/tty/tty_io.c | 10 | ||||
-rw-r--r-- | drivers/tty/tty_mutex.c | 32 | ||||
-rw-r--r-- | include/linux/tty.h | 7 |
3 files changed, 21 insertions, 28 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index bd7cde3c56ef..4ecee2856ece 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1790,7 +1790,9 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->ops->close) tty->ops->close(tty, filp); - tty_unlock(tty); + /* If tty is pty master, lock the slave pty (stable lock order) */ + tty_lock_slave(o_tty); + /* * 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 @@ -1804,8 +1806,6 @@ int tty_release(struct inode *inode, struct file *filp) * Thus this test wouldn't be triggered at the time the slave closed, * so we do it now. */ - tty_lock_pair(tty, o_tty); - while (1) { do_sleep = 0; @@ -1879,7 +1879,9 @@ int tty_release(struct inode *inode, struct file *filp) /* check whether both sides are closing ... */ final = !tty->count && !(o_tty && o_tty->count); - tty_unlock_pair(tty, o_tty); + tty_unlock_slave(o_tty); + tty_unlock(tty); + /* At this point, the tty->count == 0 should ensure a dead tty cannot be re-opened by a racing opener */ diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 2e41abebbcba..f43e995c7a0f 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -4,6 +4,11 @@ #include <linux/semaphore.h> #include <linux/sched.h> +/* + * Nested tty locks are necessary for releasing pty pairs. + * The stable lock order is master pty first, then slave pty. + */ + /* Legacy tty mutex glue */ enum { @@ -45,29 +50,18 @@ void __lockfunc tty_unlock(struct tty_struct *tty) } EXPORT_SYMBOL(tty_unlock); -/* - * Getting the big tty mutex for a pair of ttys with lock ordering - * On a non pty/tty pair tty2 can be NULL which is just fine. - */ -void __lockfunc tty_lock_pair(struct tty_struct *tty, - struct tty_struct *tty2) +void __lockfunc tty_lock_slave(struct tty_struct *tty) { - if (tty < tty2) { - tty_lock(tty); - tty_lock_nested(tty2, TTY_MUTEX_NESTED); - } else { - if (tty2 && tty2 != tty) - tty_lock(tty2); + if (tty && tty != tty->link) { + WARN_ON(!mutex_is_locked(&tty->link->legacy_mutex) || + !tty->driver->type == TTY_DRIVER_TYPE_PTY || + !tty->driver->type == PTY_TYPE_SLAVE); tty_lock_nested(tty, TTY_MUTEX_NESTED); } } -EXPORT_SYMBOL(tty_lock_pair); -void __lockfunc tty_unlock_pair(struct tty_struct *tty, - struct tty_struct *tty2) +void __lockfunc tty_unlock_slave(struct tty_struct *tty) { - tty_unlock(tty); - if (tty2 && tty2 != tty) - tty_unlock(tty2); + if (tty && tty != tty->link) + tty_unlock(tty); } -EXPORT_SYMBOL(tty_unlock_pair); diff --git a/include/linux/tty.h b/include/linux/tty.h index af1a7f3e4e4a..a07b4b415db8 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -638,11 +638,8 @@ extern long vt_compat_ioctl(struct tty_struct *tty, /* functions for preparation of BKL removal */ extern void __lockfunc tty_lock(struct tty_struct *tty); extern void __lockfunc tty_unlock(struct tty_struct *tty); -extern void __lockfunc tty_lock_pair(struct tty_struct *tty, - struct tty_struct *tty2); -extern void __lockfunc tty_unlock_pair(struct tty_struct *tty, - struct tty_struct *tty2); - +extern void __lockfunc tty_lock_slave(struct tty_struct *tty); +extern void __lockfunc tty_unlock_slave(struct tty_struct *tty); /* * this shall be called only from where BTM is held (like close) * |