aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_ldisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/tty_ldisc.c')
-rw-r--r--drivers/char/tty_ldisc.c73
1 files changed, 51 insertions, 22 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index feb55075819b..500e740ec5e4 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -34,6 +34,8 @@
34#include <linux/vt_kern.h> 34#include <linux/vt_kern.h>
35#include <linux/selection.h> 35#include <linux/selection.h>
36 36
37#include <linux/smp_lock.h> /* For the moment */
38
37#include <linux/kmod.h> 39#include <linux/kmod.h>
38#include <linux/nsproxy.h> 40#include <linux/nsproxy.h>
39 41
@@ -443,8 +445,14 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
443static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) 445static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
444{ 446{
445 WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); 447 WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
446 if (ld->ops->open) 448 if (ld->ops->open) {
447 return ld->ops->open(tty); 449 int ret;
450 /* BKL here locks verus a hangup event */
451 lock_kernel();
452 ret = ld->ops->open(tty);
453 unlock_kernel();
454 return ret;
455 }
448 return 0; 456 return 0;
449} 457}
450 458
@@ -545,6 +553,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
545 if (IS_ERR(new_ldisc)) 553 if (IS_ERR(new_ldisc))
546 return PTR_ERR(new_ldisc); 554 return PTR_ERR(new_ldisc);
547 555
556 lock_kernel();
548 /* 557 /*
549 * We need to look at the tty locking here for pty/tty pairs 558 * We need to look at the tty locking here for pty/tty pairs
550 * when both sides try to change in parallel. 559 * when both sides try to change in parallel.
@@ -558,10 +567,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
558 */ 567 */
559 568
560 if (tty->ldisc->ops->num == ldisc) { 569 if (tty->ldisc->ops->num == ldisc) {
570 unlock_kernel();
561 tty_ldisc_put(new_ldisc); 571 tty_ldisc_put(new_ldisc);
562 return 0; 572 return 0;
563 } 573 }
564 574
575 unlock_kernel();
565 /* 576 /*
566 * Problem: What do we do if this blocks ? 577 * Problem: What do we do if this blocks ?
567 * We could deadlock here 578 * We could deadlock here
@@ -582,6 +593,9 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
582 test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); 593 test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
583 mutex_lock(&tty->ldisc_mutex); 594 mutex_lock(&tty->ldisc_mutex);
584 } 595 }
596
597 lock_kernel();
598
585 set_bit(TTY_LDISC_CHANGING, &tty->flags); 599 set_bit(TTY_LDISC_CHANGING, &tty->flags);
586 600
587 /* 601 /*
@@ -592,6 +606,8 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
592 tty->receive_room = 0; 606 tty->receive_room = 0;
593 607
594 o_ldisc = tty->ldisc; 608 o_ldisc = tty->ldisc;
609
610 unlock_kernel();
595 /* 611 /*
596 * Make sure we don't change while someone holds a 612 * Make sure we don't change while someone holds a
597 * reference to the line discipline. The TTY_LDISC bit 613 * reference to the line discipline. The TTY_LDISC bit
@@ -617,12 +633,14 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
617 flush_scheduled_work(); 633 flush_scheduled_work();
618 634
619 mutex_lock(&tty->ldisc_mutex); 635 mutex_lock(&tty->ldisc_mutex);
636 lock_kernel();
620 if (test_bit(TTY_HUPPED, &tty->flags)) { 637 if (test_bit(TTY_HUPPED, &tty->flags)) {
621 /* We were raced by the hangup method. It will have stomped 638 /* We were raced by the hangup method. It will have stomped
622 the ldisc data and closed the ldisc down */ 639 the ldisc data and closed the ldisc down */
623 clear_bit(TTY_LDISC_CHANGING, &tty->flags); 640 clear_bit(TTY_LDISC_CHANGING, &tty->flags);
624 mutex_unlock(&tty->ldisc_mutex); 641 mutex_unlock(&tty->ldisc_mutex);
625 tty_ldisc_put(new_ldisc); 642 tty_ldisc_put(new_ldisc);
643 unlock_kernel();
626 return -EIO; 644 return -EIO;
627 } 645 }
628 646
@@ -664,6 +682,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
664 if (o_work) 682 if (o_work)
665 schedule_delayed_work(&o_tty->buf.work, 1); 683 schedule_delayed_work(&o_tty->buf.work, 1);
666 mutex_unlock(&tty->ldisc_mutex); 684 mutex_unlock(&tty->ldisc_mutex);
685 unlock_kernel();
667 return retval; 686 return retval;
668} 687}
669 688
@@ -687,12 +706,13 @@ static void tty_reset_termios(struct tty_struct *tty)
687/** 706/**
688 * tty_ldisc_reinit - reinitialise the tty ldisc 707 * tty_ldisc_reinit - reinitialise the tty ldisc
689 * @tty: tty to reinit 708 * @tty: tty to reinit
709 * @ldisc: line discipline to reinitialize
690 * 710 *
691 * Switch the tty back to N_TTY line discipline and leave the 711 * Switch the tty to a line discipline and leave the ldisc
692 * ldisc state closed 712 * state closed
693 */ 713 */
694 714
695static void tty_ldisc_reinit(struct tty_struct *tty) 715static void tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
696{ 716{
697 struct tty_ldisc *ld; 717 struct tty_ldisc *ld;
698 718
@@ -702,10 +722,10 @@ static void tty_ldisc_reinit(struct tty_struct *tty)
702 /* 722 /*
703 * Switch the line discipline back 723 * Switch the line discipline back
704 */ 724 */
705 ld = tty_ldisc_get(N_TTY); 725 ld = tty_ldisc_get(ldisc);
706 BUG_ON(IS_ERR(ld)); 726 BUG_ON(IS_ERR(ld));
707 tty_ldisc_assign(tty, ld); 727 tty_ldisc_assign(tty, ld);
708 tty_set_termios_ldisc(tty, N_TTY); 728 tty_set_termios_ldisc(tty, ldisc);
709} 729}
710 730
711/** 731/**
@@ -726,6 +746,8 @@ static void tty_ldisc_reinit(struct tty_struct *tty)
726void tty_ldisc_hangup(struct tty_struct *tty) 746void tty_ldisc_hangup(struct tty_struct *tty)
727{ 747{
728 struct tty_ldisc *ld; 748 struct tty_ldisc *ld;
749 int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
750 int err = 0;
729 751
730 /* 752 /*
731 * FIXME! What are the locking issues here? This may me overdoing 753 * FIXME! What are the locking issues here? This may me overdoing
@@ -753,25 +775,32 @@ void tty_ldisc_hangup(struct tty_struct *tty)
753 wake_up_interruptible_poll(&tty->read_wait, POLLIN); 775 wake_up_interruptible_poll(&tty->read_wait, POLLIN);
754 /* 776 /*
755 * Shutdown the current line discipline, and reset it to 777 * Shutdown the current line discipline, and reset it to
756 * N_TTY. 778 * N_TTY if need be.
779 *
780 * Avoid racing set_ldisc or tty_ldisc_release
757 */ 781 */
758 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { 782 mutex_lock(&tty->ldisc_mutex);
759 /* Avoid racing set_ldisc or tty_ldisc_release */ 783 tty_ldisc_halt(tty);
760 mutex_lock(&tty->ldisc_mutex); 784 /* At this point we have a closed ldisc and we want to
761 tty_ldisc_halt(tty); 785 reopen it. We could defer this to the next open but
762 if (tty->ldisc) { /* Not yet closed */ 786 it means auditing a lot of other paths so this is
763 /* Switch back to N_TTY */ 787 a FIXME */
764 tty_ldisc_reinit(tty); 788 if (tty->ldisc) { /* Not yet closed */
765 /* At this point we have a closed ldisc and we want to 789 if (reset == 0) {
766 reopen it. We could defer this to the next open but 790 tty_ldisc_reinit(tty, tty->termios->c_line);
767 it means auditing a lot of other paths so this is 791 err = tty_ldisc_open(tty, tty->ldisc);
768 a FIXME */ 792 }
793 /* If the re-open fails or we reset then go to N_TTY. The
794 N_TTY open cannot fail */
795 if (reset || err) {
796 tty_ldisc_reinit(tty, N_TTY);
769 WARN_ON(tty_ldisc_open(tty, tty->ldisc)); 797 WARN_ON(tty_ldisc_open(tty, tty->ldisc));
770 tty_ldisc_enable(tty);
771 } 798 }
772 mutex_unlock(&tty->ldisc_mutex); 799 tty_ldisc_enable(tty);
773 tty_reset_termios(tty);
774 } 800 }
801 mutex_unlock(&tty->ldisc_mutex);
802 if (reset)
803 tty_reset_termios(tty);
775} 804}
776 805
777/** 806/**