diff options
author | Arnd Bergmann <arnd@arndb.de> | 2010-06-01 16:53:06 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-10 16:47:43 -0400 |
commit | 60af22d2ed490554cc92c8d0fed0b5b9cf687568 (patch) | |
tree | 6c9d1b2d9b5c409dc6a38f26ed5b7ec0f37a041a /drivers/char/tty_ldisc.c | |
parent | be1bc2889a4db4961ef69f47fb471ecae9f23ade (diff) |
tty: reorder ldisc locking
We need to release the BTM in paste_selection() when
sleeping in tty_ldisc_ref_wait to avoid deadlocks
with tty_ldisc_enable.
In tty_set_ldisc, we now always grab the BTM before
taking the ldisc_mutex in order to avoid AB-BA
deadlocks between the two.
tty_ldisc_halt potentially blocks on a workqueue
function that takes the BTM, so we must release
the BTM before calling it.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/char/tty_ldisc.c')
-rw-r--r-- | drivers/char/tty_ldisc.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 97681ffd6cbd..0f494799da89 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c | |||
@@ -582,6 +582,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
582 | 582 | ||
583 | tty_wait_until_sent(tty, 0); | 583 | tty_wait_until_sent(tty, 0); |
584 | 584 | ||
585 | tty_lock(); | ||
585 | mutex_lock(&tty->ldisc_mutex); | 586 | mutex_lock(&tty->ldisc_mutex); |
586 | 587 | ||
587 | /* | 588 | /* |
@@ -591,13 +592,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
591 | 592 | ||
592 | while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { | 593 | while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { |
593 | mutex_unlock(&tty->ldisc_mutex); | 594 | mutex_unlock(&tty->ldisc_mutex); |
595 | tty_unlock(); | ||
594 | wait_event(tty_ldisc_wait, | 596 | wait_event(tty_ldisc_wait, |
595 | test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); | 597 | test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); |
598 | tty_lock(); | ||
596 | mutex_lock(&tty->ldisc_mutex); | 599 | mutex_lock(&tty->ldisc_mutex); |
597 | } | 600 | } |
598 | 601 | ||
599 | tty_lock(); | ||
600 | |||
601 | set_bit(TTY_LDISC_CHANGING, &tty->flags); | 602 | set_bit(TTY_LDISC_CHANGING, &tty->flags); |
602 | 603 | ||
603 | /* | 604 | /* |
@@ -634,8 +635,8 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
634 | 635 | ||
635 | flush_scheduled_work(); | 636 | flush_scheduled_work(); |
636 | 637 | ||
637 | mutex_lock(&tty->ldisc_mutex); | ||
638 | tty_lock(); | 638 | tty_lock(); |
639 | mutex_lock(&tty->ldisc_mutex); | ||
639 | if (test_bit(TTY_HUPPED, &tty->flags)) { | 640 | if (test_bit(TTY_HUPPED, &tty->flags)) { |
640 | /* We were raced by the hangup method. It will have stomped | 641 | /* We were raced by the hangup method. It will have stomped |
641 | the ldisc data and closed the ldisc down */ | 642 | the ldisc data and closed the ldisc down */ |
@@ -782,7 +783,20 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
782 | * Avoid racing set_ldisc or tty_ldisc_release | 783 | * Avoid racing set_ldisc or tty_ldisc_release |
783 | */ | 784 | */ |
784 | mutex_lock(&tty->ldisc_mutex); | 785 | mutex_lock(&tty->ldisc_mutex); |
785 | tty_ldisc_halt(tty); | 786 | |
787 | /* | ||
788 | * this is like tty_ldisc_halt, but we need to give up | ||
789 | * the BTM before calling cancel_delayed_work_sync, | ||
790 | * which may need to wait for another function taking the BTM | ||
791 | */ | ||
792 | clear_bit(TTY_LDISC, &tty->flags); | ||
793 | tty_unlock(); | ||
794 | cancel_delayed_work_sync(&tty->buf.work); | ||
795 | mutex_unlock(&tty->ldisc_mutex); | ||
796 | |||
797 | tty_lock(); | ||
798 | mutex_lock(&tty->ldisc_mutex); | ||
799 | |||
786 | /* At this point we have a closed ldisc and we want to | 800 | /* At this point we have a closed ldisc and we want to |
787 | reopen it. We could defer this to the next open but | 801 | reopen it. We could defer this to the next open but |
788 | it means auditing a lot of other paths so this is | 802 | it means auditing a lot of other paths so this is |
@@ -853,8 +867,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | |||
853 | * race with the set_ldisc code path. | 867 | * race with the set_ldisc code path. |
854 | */ | 868 | */ |
855 | 869 | ||
870 | tty_unlock(); | ||
856 | tty_ldisc_halt(tty); | 871 | tty_ldisc_halt(tty); |
857 | flush_scheduled_work(); | 872 | flush_scheduled_work(); |
873 | tty_lock(); | ||
858 | 874 | ||
859 | mutex_lock(&tty->ldisc_mutex); | 875 | mutex_lock(&tty->ldisc_mutex); |
860 | /* | 876 | /* |