diff options
Diffstat (limited to 'drivers/char/tty_ldisc.c')
| -rw-r--r-- | drivers/char/tty_ldisc.c | 43 |
1 files changed, 30 insertions, 13 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 500e740ec5e4..412f9775d19c 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c | |||
| @@ -440,6 +440,8 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) | |||
| 440 | * | 440 | * |
| 441 | * A helper opening method. Also a convenient debugging and check | 441 | * A helper opening method. Also a convenient debugging and check |
| 442 | * point. | 442 | * point. |
| 443 | * | ||
| 444 | * Locking: always called with BTM already held. | ||
| 443 | */ | 445 | */ |
| 444 | 446 | ||
| 445 | static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) | 447 | static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) |
| @@ -447,10 +449,9 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) | |||
| 447 | WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); | 449 | WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); |
| 448 | if (ld->ops->open) { | 450 | if (ld->ops->open) { |
| 449 | int ret; | 451 | int ret; |
| 450 | /* BKL here locks verus a hangup event */ | 452 | /* BTM here locks versus a hangup event */ |
| 451 | lock_kernel(); | 453 | WARN_ON(!tty_locked()); |
| 452 | ret = ld->ops->open(tty); | 454 | ret = ld->ops->open(tty); |
| 453 | unlock_kernel(); | ||
| 454 | return ret; | 455 | return ret; |
| 455 | } | 456 | } |
| 456 | return 0; | 457 | return 0; |
| @@ -553,7 +554,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 553 | if (IS_ERR(new_ldisc)) | 554 | if (IS_ERR(new_ldisc)) |
| 554 | return PTR_ERR(new_ldisc); | 555 | return PTR_ERR(new_ldisc); |
| 555 | 556 | ||
| 556 | lock_kernel(); | 557 | tty_lock(); |
| 557 | /* | 558 | /* |
| 558 | * We need to look at the tty locking here for pty/tty pairs | 559 | * We need to look at the tty locking here for pty/tty pairs |
| 559 | * when both sides try to change in parallel. | 560 | * when both sides try to change in parallel. |
| @@ -567,12 +568,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 567 | */ | 568 | */ |
| 568 | 569 | ||
| 569 | if (tty->ldisc->ops->num == ldisc) { | 570 | if (tty->ldisc->ops->num == ldisc) { |
| 570 | unlock_kernel(); | 571 | tty_unlock(); |
| 571 | tty_ldisc_put(new_ldisc); | 572 | tty_ldisc_put(new_ldisc); |
| 572 | return 0; | 573 | return 0; |
| 573 | } | 574 | } |
| 574 | 575 | ||
| 575 | unlock_kernel(); | 576 | tty_unlock(); |
| 576 | /* | 577 | /* |
| 577 | * Problem: What do we do if this blocks ? | 578 | * Problem: What do we do if this blocks ? |
| 578 | * We could deadlock here | 579 | * We could deadlock here |
| @@ -580,6 +581,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 580 | 581 | ||
| 581 | tty_wait_until_sent(tty, 0); | 582 | tty_wait_until_sent(tty, 0); |
| 582 | 583 | ||
| 584 | tty_lock(); | ||
| 583 | mutex_lock(&tty->ldisc_mutex); | 585 | mutex_lock(&tty->ldisc_mutex); |
| 584 | 586 | ||
| 585 | /* | 587 | /* |
| @@ -589,13 +591,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 589 | 591 | ||
| 590 | while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { | 592 | while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { |
| 591 | mutex_unlock(&tty->ldisc_mutex); | 593 | mutex_unlock(&tty->ldisc_mutex); |
| 594 | tty_unlock(); | ||
| 592 | wait_event(tty_ldisc_wait, | 595 | wait_event(tty_ldisc_wait, |
| 593 | test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); | 596 | test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); |
| 597 | tty_lock(); | ||
| 594 | mutex_lock(&tty->ldisc_mutex); | 598 | mutex_lock(&tty->ldisc_mutex); |
| 595 | } | 599 | } |
| 596 | 600 | ||
| 597 | lock_kernel(); | ||
| 598 | |||
| 599 | set_bit(TTY_LDISC_CHANGING, &tty->flags); | 601 | set_bit(TTY_LDISC_CHANGING, &tty->flags); |
| 600 | 602 | ||
| 601 | /* | 603 | /* |
| @@ -607,7 +609,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 607 | 609 | ||
| 608 | o_ldisc = tty->ldisc; | 610 | o_ldisc = tty->ldisc; |
| 609 | 611 | ||
| 610 | unlock_kernel(); | 612 | tty_unlock(); |
| 611 | /* | 613 | /* |
| 612 | * Make sure we don't change while someone holds a | 614 | * Make sure we don't change while someone holds a |
| 613 | * reference to the line discipline. The TTY_LDISC bit | 615 | * reference to the line discipline. The TTY_LDISC bit |
| @@ -632,15 +634,15 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 632 | 634 | ||
| 633 | flush_scheduled_work(); | 635 | flush_scheduled_work(); |
| 634 | 636 | ||
| 637 | tty_lock(); | ||
| 635 | mutex_lock(&tty->ldisc_mutex); | 638 | mutex_lock(&tty->ldisc_mutex); |
| 636 | lock_kernel(); | ||
| 637 | if (test_bit(TTY_HUPPED, &tty->flags)) { | 639 | if (test_bit(TTY_HUPPED, &tty->flags)) { |
| 638 | /* We were raced by the hangup method. It will have stomped | 640 | /* We were raced by the hangup method. It will have stomped |
| 639 | the ldisc data and closed the ldisc down */ | 641 | the ldisc data and closed the ldisc down */ |
| 640 | clear_bit(TTY_LDISC_CHANGING, &tty->flags); | 642 | clear_bit(TTY_LDISC_CHANGING, &tty->flags); |
| 641 | mutex_unlock(&tty->ldisc_mutex); | 643 | mutex_unlock(&tty->ldisc_mutex); |
| 642 | tty_ldisc_put(new_ldisc); | 644 | tty_ldisc_put(new_ldisc); |
| 643 | unlock_kernel(); | 645 | tty_unlock(); |
| 644 | return -EIO; | 646 | return -EIO; |
| 645 | } | 647 | } |
| 646 | 648 | ||
| @@ -682,7 +684,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
| 682 | if (o_work) | 684 | if (o_work) |
| 683 | schedule_delayed_work(&o_tty->buf.work, 1); | 685 | schedule_delayed_work(&o_tty->buf.work, 1); |
| 684 | mutex_unlock(&tty->ldisc_mutex); | 686 | mutex_unlock(&tty->ldisc_mutex); |
| 685 | unlock_kernel(); | 687 | tty_unlock(); |
| 686 | return retval; | 688 | return retval; |
| 687 | } | 689 | } |
| 688 | 690 | ||
| @@ -780,7 +782,20 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
| 780 | * Avoid racing set_ldisc or tty_ldisc_release | 782 | * Avoid racing set_ldisc or tty_ldisc_release |
| 781 | */ | 783 | */ |
| 782 | mutex_lock(&tty->ldisc_mutex); | 784 | mutex_lock(&tty->ldisc_mutex); |
| 783 | tty_ldisc_halt(tty); | 785 | |
| 786 | /* | ||
| 787 | * this is like tty_ldisc_halt, but we need to give up | ||
| 788 | * the BTM before calling cancel_delayed_work_sync, | ||
| 789 | * which may need to wait for another function taking the BTM | ||
| 790 | */ | ||
| 791 | clear_bit(TTY_LDISC, &tty->flags); | ||
| 792 | tty_unlock(); | ||
| 793 | cancel_delayed_work_sync(&tty->buf.work); | ||
| 794 | mutex_unlock(&tty->ldisc_mutex); | ||
| 795 | |||
| 796 | tty_lock(); | ||
| 797 | mutex_lock(&tty->ldisc_mutex); | ||
| 798 | |||
| 784 | /* At this point we have a closed ldisc and we want to | 799 | /* At this point we have a closed ldisc and we want to |
| 785 | reopen it. We could defer this to the next open but | 800 | reopen it. We could defer this to the next open but |
| 786 | it means auditing a lot of other paths so this is | 801 | it means auditing a lot of other paths so this is |
| @@ -851,8 +866,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) | |||
| 851 | * race with the set_ldisc code path. | 866 | * race with the set_ldisc code path. |
| 852 | */ | 867 | */ |
| 853 | 868 | ||
| 869 | tty_unlock(); | ||
| 854 | tty_ldisc_halt(tty); | 870 | tty_ldisc_halt(tty); |
| 855 | flush_scheduled_work(); | 871 | flush_scheduled_work(); |
| 872 | tty_lock(); | ||
| 856 | 873 | ||
| 857 | mutex_lock(&tty->ldisc_mutex); | 874 | mutex_lock(&tty->ldisc_mutex); |
| 858 | /* | 875 | /* |
