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 | |
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')
-rw-r--r-- | drivers/char/selection.c | 9 | ||||
-rw-r--r-- | drivers/char/tty_ldisc.c | 24 |
2 files changed, 27 insertions, 6 deletions
diff --git a/drivers/char/selection.c b/drivers/char/selection.c index 85211a3a5811..75889cd9375f 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c | |||
@@ -319,8 +319,13 @@ int paste_selection(struct tty_struct *tty) | |||
319 | poke_blanked_console(); | 319 | poke_blanked_console(); |
320 | release_console_sem(); | 320 | release_console_sem(); |
321 | 321 | ||
322 | ld = tty_ldisc_ref_wait(tty); | 322 | ld = tty_ldisc_ref(tty); |
323 | 323 | if (!ld) { | |
324 | tty_unlock(); | ||
325 | ld = tty_ldisc_ref_wait(tty); | ||
326 | tty_lock(); | ||
327 | } | ||
328 | |||
324 | add_wait_queue(&vc->paste_wait, &wait); | 329 | add_wait_queue(&vc->paste_wait, &wait); |
325 | while (sel_buffer && sel_buffer_lth > pasted) { | 330 | while (sel_buffer && sel_buffer_lth > pasted) { |
326 | set_current_state(TASK_INTERRUPTIBLE); | 331 | set_current_state(TASK_INTERRUPTIBLE); |
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 | /* |