aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2010-06-18 08:58:07 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-10 16:47:44 -0400
commit11dbf203922dc70a340417c895c95fb96f6b7068 (patch)
tree7c79b79c74a184a7d67d3f54af4e37dee930d11e /drivers/char
parenta0821df6e57c8af0053963d0d08c8d5198ea077d (diff)
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: Arnd Bergmann <arnd@arndb.de> Acked-by: Alan 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: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/pty.c4
-rw-r--r--drivers/char/tty_io.c24
2 files changed, 15 insertions, 13 deletions
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index f2d7a76fab54..ad46eae1f9bb 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -62,7 +62,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
62 if (tty->driver == ptm_driver) 62 if (tty->driver == ptm_driver)
63 devpts_pty_kill(tty->link); 63 devpts_pty_kill(tty->link);
64#endif 64#endif
65 tty_vhangup_locked(tty->link); 65 tty_unlock();
66 tty_vhangup(tty->link);
67 tty_lock();
66 } 68 }
67} 69}
68 70
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index dcf7d368639e..4c4030c12d3a 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -471,7 +471,7 @@ void tty_wakeup(struct tty_struct *tty)
471EXPORT_SYMBOL_GPL(tty_wakeup); 471EXPORT_SYMBOL_GPL(tty_wakeup);
472 472
473/** 473/**
474 * do_tty_hangup - actual handler for hangup events 474 * __tty_hangup - actual handler for hangup events
475 * @work: tty device 475 * @work: tty device
476 * 476 *
477 * This can be called by the "eventd" kernel thread. That is process 477 * This can be called by the "eventd" kernel thread. That is process
@@ -492,7 +492,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
492 * tasklist_lock to walk task list for hangup event 492 * tasklist_lock to walk task list for hangup event
493 * ->siglock to protect ->signal/->sighand 493 * ->siglock to protect ->signal/->sighand
494 */ 494 */
495void tty_vhangup_locked(struct tty_struct *tty) 495void __tty_hangup(struct tty_struct *tty)
496{ 496{
497 struct file *cons_filp = NULL; 497 struct file *cons_filp = NULL;
498 struct file *filp, *f = NULL; 498 struct file *filp, *f = NULL;
@@ -512,10 +512,12 @@ void tty_vhangup_locked(struct tty_struct *tty)
512 } 512 }
513 spin_unlock(&redirect_lock); 513 spin_unlock(&redirect_lock);
514 514
515 tty_lock();
516
515 /* inuse_filps is protected by the single tty lock, 517 /* inuse_filps is protected by the single tty lock,
516 this really needs to change if we want to flush the 518 this really needs to change if we want to flush the
517 workqueue with the lock held */ 519 workqueue with the lock held */
518 check_tty_count(tty, "do_tty_hangup"); 520 check_tty_count(tty, "tty_hangup");
519 521
520 file_list_lock(); 522 file_list_lock();
521 /* This breaks for file handles being sent over AF_UNIX sockets ? */ 523 /* This breaks for file handles being sent over AF_UNIX sockets ? */
@@ -594,6 +596,9 @@ void tty_vhangup_locked(struct tty_struct *tty)
594 */ 596 */
595 set_bit(TTY_HUPPED, &tty->flags); 597 set_bit(TTY_HUPPED, &tty->flags);
596 tty_ldisc_enable(tty); 598 tty_ldisc_enable(tty);
599
600 tty_unlock();
601
597 if (f) 602 if (f)
598 fput(f); 603 fput(f);
599} 604}
@@ -603,9 +608,7 @@ static void do_tty_hangup(struct work_struct *work)
603 struct tty_struct *tty = 608 struct tty_struct *tty =
604 container_of(work, struct tty_struct, hangup_work); 609 container_of(work, struct tty_struct, hangup_work);
605 610
606 tty_lock(); 611 __tty_hangup(tty);
607 tty_vhangup_locked(tty);
608 tty_unlock();
609} 612}
610 613
611/** 614/**
@@ -643,13 +646,12 @@ void tty_vhangup(struct tty_struct *tty)
643 646
644 printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); 647 printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
645#endif 648#endif
646 tty_lock(); 649 __tty_hangup(tty);
647 tty_vhangup_locked(tty);
648 tty_unlock();
649} 650}
650 651
651EXPORT_SYMBOL(tty_vhangup); 652EXPORT_SYMBOL(tty_vhangup);
652 653
654
653/** 655/**
654 * tty_vhangup_self - process vhangup for own ctty 656 * tty_vhangup_self - process vhangup for own ctty
655 * 657 *
@@ -727,10 +729,8 @@ void disassociate_ctty(int on_exit)
727 if (tty) { 729 if (tty) {
728 tty_pgrp = get_pid(tty->pgrp); 730 tty_pgrp = get_pid(tty->pgrp);
729 if (on_exit) { 731 if (on_exit) {
730 tty_lock();
731 if (tty->driver->type != TTY_DRIVER_TYPE_PTY) 732 if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
732 tty_vhangup_locked(tty); 733 tty_vhangup(tty);
733 tty_unlock();
734 } 734 }
735 tty_kref_put(tty); 735 tty_kref_put(tty);
736 } else if (on_exit) { 736 } else if (on_exit) {