Commit 11dbf203 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Greg Kroah-Hartman

tty: avoid recursive BTM in pty_close

When the console has been redirected, a hangup of the tty
will cause tty_release to be called under the big tty_mutex,
which leads to a deadlock because hangup is also called
under the BTM.

This moves the BTM deeper into the tty_hangup function so
we can close the redirected tty without holding the BTM.
In case of pty, we now need to drop the BTM before
calling tty_vhangup.
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Acked-by: default avatarAlan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: John Kacur <jkacur@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent a0821df6
...@@ -62,7 +62,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp) ...@@ -62,7 +62,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
if (tty->driver == ptm_driver) if (tty->driver == ptm_driver)
devpts_pty_kill(tty->link); devpts_pty_kill(tty->link);
#endif #endif
tty_vhangup_locked(tty->link); tty_unlock();
tty_vhangup(tty->link);
tty_lock();
} }
} }
......
...@@ -471,7 +471,7 @@ void tty_wakeup(struct tty_struct *tty) ...@@ -471,7 +471,7 @@ void tty_wakeup(struct tty_struct *tty)
EXPORT_SYMBOL_GPL(tty_wakeup); EXPORT_SYMBOL_GPL(tty_wakeup);
/** /**
* do_tty_hangup - actual handler for hangup events * __tty_hangup - actual handler for hangup events
* @work: tty device * @work: tty device
* *
* This can be called by the "eventd" kernel thread. That is process * This can be called by the "eventd" kernel thread. That is process
...@@ -492,7 +492,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup); ...@@ -492,7 +492,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
* tasklist_lock to walk task list for hangup event * tasklist_lock to walk task list for hangup event
* ->siglock to protect ->signal/->sighand * ->siglock to protect ->signal/->sighand
*/ */
void tty_vhangup_locked(struct tty_struct *tty) void __tty_hangup(struct tty_struct *tty)
{ {
struct file *cons_filp = NULL; struct file *cons_filp = NULL;
struct file *filp, *f = NULL; struct file *filp, *f = NULL;
...@@ -512,10 +512,12 @@ void tty_vhangup_locked(struct tty_struct *tty) ...@@ -512,10 +512,12 @@ void tty_vhangup_locked(struct tty_struct *tty)
} }
spin_unlock(&redirect_lock); spin_unlock(&redirect_lock);
tty_lock();
/* inuse_filps is protected by the single tty lock, /* inuse_filps is protected by the single tty lock,
this really needs to change if we want to flush the this really needs to change if we want to flush the
workqueue with the lock held */ workqueue with the lock held */
check_tty_count(tty, "do_tty_hangup"); check_tty_count(tty, "tty_hangup");
file_list_lock(); file_list_lock();
/* This breaks for file handles being sent over AF_UNIX sockets ? */ /* This breaks for file handles being sent over AF_UNIX sockets ? */
...@@ -594,6 +596,9 @@ void tty_vhangup_locked(struct tty_struct *tty) ...@@ -594,6 +596,9 @@ void tty_vhangup_locked(struct tty_struct *tty)
*/ */
set_bit(TTY_HUPPED, &tty->flags); set_bit(TTY_HUPPED, &tty->flags);
tty_ldisc_enable(tty); tty_ldisc_enable(tty);
tty_unlock();
if (f) if (f)
fput(f); fput(f);
} }
...@@ -603,9 +608,7 @@ static void do_tty_hangup(struct work_struct *work) ...@@ -603,9 +608,7 @@ static void do_tty_hangup(struct work_struct *work)
struct tty_struct *tty = struct tty_struct *tty =
container_of(work, struct tty_struct, hangup_work); container_of(work, struct tty_struct, hangup_work);
tty_lock(); __tty_hangup(tty);
tty_vhangup_locked(tty);
tty_unlock();
} }
/** /**
...@@ -643,13 +646,12 @@ void tty_vhangup(struct tty_struct *tty) ...@@ -643,13 +646,12 @@ void tty_vhangup(struct tty_struct *tty)
printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
#endif #endif
tty_lock(); __tty_hangup(tty);
tty_vhangup_locked(tty);
tty_unlock();
} }
EXPORT_SYMBOL(tty_vhangup); EXPORT_SYMBOL(tty_vhangup);
/** /**
* tty_vhangup_self - process vhangup for own ctty * tty_vhangup_self - process vhangup for own ctty
* *
...@@ -727,10 +729,8 @@ void disassociate_ctty(int on_exit) ...@@ -727,10 +729,8 @@ void disassociate_ctty(int on_exit)
if (tty) { if (tty) {
tty_pgrp = get_pid(tty->pgrp); tty_pgrp = get_pid(tty->pgrp);
if (on_exit) { if (on_exit) {
tty_lock();
if (tty->driver->type != TTY_DRIVER_TYPE_PTY) if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup_locked(tty); tty_vhangup(tty);
tty_unlock();
} }
tty_kref_put(tty); tty_kref_put(tty);
} else if (on_exit) { } else if (on_exit) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment