diff options
Diffstat (limited to 'drivers/tty/tty_mutex.c')
| -rw-r--r-- | drivers/tty/tty_mutex.c | 82 |
1 files changed, 54 insertions, 28 deletions
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 133697540c7..2e41abebbcb 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -1,47 +1,73 @@ -/* - * drivers/char/tty_lock.c - */ #include <linux/tty.h> #include <linux/module.h> #include <linux/kallsyms.h> #include <linux/semaphore.h> #include <linux/sched.h> -/* - * The 'big tty mutex' - * - * This mutex is taken and released by tty_lock() and tty_unlock(), - * replacing the older big kernel lock. - * It can no longer be taken recursively, and does not get - * released implicitly while sleeping. - * - * Don't use in new code. - */ -static DEFINE_MUTEX(big_tty_mutex); -struct task_struct *__big_tty_mutex_owner; -EXPORT_SYMBOL_GPL(__big_tty_mutex_owner); +/* Legacy tty mutex glue */ + +enum { + TTY_MUTEX_NORMAL, + TTY_MUTEX_NESTED, +}; /* * Getting the big tty mutex. */ -void __lockfunc tty_lock(void) -{ - struct task_struct *task = current; - WARN_ON(__big_tty_mutex_owner == task); +static void __lockfunc tty_lock_nested(struct tty_struct *tty, + unsigned int subclass) +{ + if (tty->magic != TTY_MAGIC) { + pr_err("L Bad %p\n", tty); + WARN_ON(1); + return; + } + tty_kref_get(tty); + mutex_lock_nested(&tty->legacy_mutex, subclass); +} - mutex_lock(&big_tty_mutex); - __big_tty_mutex_owner = task; +void __lockfunc tty_lock(struct tty_struct *tty) +{ + return tty_lock_nested(tty, TTY_MUTEX_NORMAL); } EXPORT_SYMBOL(tty_lock); -void __lockfunc tty_unlock(void) +void __lockfunc tty_unlock(struct tty_struct *tty) { - struct task_struct *task = current; + if (tty->magic != TTY_MAGIC) { + pr_err("U Bad %p\n", tty); + WARN_ON(1); + return; + } + mutex_unlock(&tty->legacy_mutex); + tty_kref_put(tty); +} +EXPORT_SYMBOL(tty_unlock); - WARN_ON(__big_tty_mutex_owner != task); - __big_tty_mutex_owner = NULL; +/* + * 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) +{ + if (tty < tty2) { + tty_lock(tty); + tty_lock_nested(tty2, TTY_MUTEX_NESTED); + } else { + if (tty2 && tty2 != tty) + tty_lock(tty2); + tty_lock_nested(tty, TTY_MUTEX_NESTED); + } +} +EXPORT_SYMBOL(tty_lock_pair); - mutex_unlock(&big_tty_mutex); +void __lockfunc tty_unlock_pair(struct tty_struct *tty, + struct tty_struct *tty2) +{ + tty_unlock(tty); + if (tty2 && tty2 != tty) + tty_unlock(tty2); } -EXPORT_SYMBOL(tty_unlock); +EXPORT_SYMBOL(tty_unlock_pair); |
