diff options
Diffstat (limited to 'drivers/tty/tty_io.c')
-rw-r--r-- | drivers/tty/tty_io.c | 170 |
1 files changed, 118 insertions, 52 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 05400acbc456..cbf5a5040908 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c | |||
@@ -533,6 +533,60 @@ void tty_wakeup(struct tty_struct *tty) | |||
533 | EXPORT_SYMBOL_GPL(tty_wakeup); | 533 | EXPORT_SYMBOL_GPL(tty_wakeup); |
534 | 534 | ||
535 | /** | 535 | /** |
536 | * tty_signal_session_leader - sends SIGHUP to session leader | ||
537 | * @tty controlling tty | ||
538 | * @exit_session if non-zero, signal all foreground group processes | ||
539 | * | ||
540 | * Send SIGHUP and SIGCONT to the session leader and its process group. | ||
541 | * Optionally, signal all processes in the foreground process group. | ||
542 | * | ||
543 | * Returns the number of processes in the session with this tty | ||
544 | * as their controlling terminal. This value is used to drop | ||
545 | * tty references for those processes. | ||
546 | */ | ||
547 | static int tty_signal_session_leader(struct tty_struct *tty, int exit_session) | ||
548 | { | ||
549 | struct task_struct *p; | ||
550 | int refs = 0; | ||
551 | struct pid *tty_pgrp = NULL; | ||
552 | |||
553 | read_lock(&tasklist_lock); | ||
554 | if (tty->session) { | ||
555 | do_each_pid_task(tty->session, PIDTYPE_SID, p) { | ||
556 | spin_lock_irq(&p->sighand->siglock); | ||
557 | if (p->signal->tty == tty) { | ||
558 | p->signal->tty = NULL; | ||
559 | /* We defer the dereferences outside fo | ||
560 | the tasklist lock */ | ||
561 | refs++; | ||
562 | } | ||
563 | if (!p->signal->leader) { | ||
564 | spin_unlock_irq(&p->sighand->siglock); | ||
565 | continue; | ||
566 | } | ||
567 | __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); | ||
568 | __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); | ||
569 | put_pid(p->signal->tty_old_pgrp); /* A noop */ | ||
570 | spin_lock(&tty->ctrl_lock); | ||
571 | tty_pgrp = get_pid(tty->pgrp); | ||
572 | if (tty->pgrp) | ||
573 | p->signal->tty_old_pgrp = get_pid(tty->pgrp); | ||
574 | spin_unlock(&tty->ctrl_lock); | ||
575 | spin_unlock_irq(&p->sighand->siglock); | ||
576 | } while_each_pid_task(tty->session, PIDTYPE_SID, p); | ||
577 | } | ||
578 | read_unlock(&tasklist_lock); | ||
579 | |||
580 | if (tty_pgrp) { | ||
581 | if (exit_session) | ||
582 | kill_pgrp(tty_pgrp, SIGHUP, exit_session); | ||
583 | put_pid(tty_pgrp); | ||
584 | } | ||
585 | |||
586 | return refs; | ||
587 | } | ||
588 | |||
589 | /** | ||
536 | * __tty_hangup - actual handler for hangup events | 590 | * __tty_hangup - actual handler for hangup events |
537 | * @work: tty device | 591 | * @work: tty device |
538 | * | 592 | * |
@@ -554,15 +608,13 @@ EXPORT_SYMBOL_GPL(tty_wakeup); | |||
554 | * tasklist_lock to walk task list for hangup event | 608 | * tasklist_lock to walk task list for hangup event |
555 | * ->siglock to protect ->signal/->sighand | 609 | * ->siglock to protect ->signal/->sighand |
556 | */ | 610 | */ |
557 | static void __tty_hangup(struct tty_struct *tty) | 611 | static void __tty_hangup(struct tty_struct *tty, int exit_session) |
558 | { | 612 | { |
559 | struct file *cons_filp = NULL; | 613 | struct file *cons_filp = NULL; |
560 | struct file *filp, *f = NULL; | 614 | struct file *filp, *f = NULL; |
561 | struct task_struct *p; | ||
562 | struct tty_file_private *priv; | 615 | struct tty_file_private *priv; |
563 | int closecount = 0, n; | 616 | int closecount = 0, n; |
564 | unsigned long flags; | 617 | int refs; |
565 | int refs = 0; | ||
566 | 618 | ||
567 | if (!tty) | 619 | if (!tty) |
568 | return; | 620 | return; |
@@ -599,39 +651,18 @@ static void __tty_hangup(struct tty_struct *tty) | |||
599 | } | 651 | } |
600 | spin_unlock(&tty_files_lock); | 652 | spin_unlock(&tty_files_lock); |
601 | 653 | ||
654 | refs = tty_signal_session_leader(tty, exit_session); | ||
655 | /* Account for the p->signal references we killed */ | ||
656 | while (refs--) | ||
657 | tty_kref_put(tty); | ||
658 | |||
602 | /* | 659 | /* |
603 | * it drops BTM and thus races with reopen | 660 | * it drops BTM and thus races with reopen |
604 | * we protect the race by TTY_HUPPING | 661 | * we protect the race by TTY_HUPPING |
605 | */ | 662 | */ |
606 | tty_ldisc_hangup(tty); | 663 | tty_ldisc_hangup(tty); |
607 | 664 | ||
608 | read_lock(&tasklist_lock); | 665 | spin_lock_irq(&tty->ctrl_lock); |
609 | if (tty->session) { | ||
610 | do_each_pid_task(tty->session, PIDTYPE_SID, p) { | ||
611 | spin_lock_irq(&p->sighand->siglock); | ||
612 | if (p->signal->tty == tty) { | ||
613 | p->signal->tty = NULL; | ||
614 | /* We defer the dereferences outside fo | ||
615 | the tasklist lock */ | ||
616 | refs++; | ||
617 | } | ||
618 | if (!p->signal->leader) { | ||
619 | spin_unlock_irq(&p->sighand->siglock); | ||
620 | continue; | ||
621 | } | ||
622 | __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); | ||
623 | __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); | ||
624 | put_pid(p->signal->tty_old_pgrp); /* A noop */ | ||
625 | spin_lock_irqsave(&tty->ctrl_lock, flags); | ||
626 | if (tty->pgrp) | ||
627 | p->signal->tty_old_pgrp = get_pid(tty->pgrp); | ||
628 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
629 | spin_unlock_irq(&p->sighand->siglock); | ||
630 | } while_each_pid_task(tty->session, PIDTYPE_SID, p); | ||
631 | } | ||
632 | read_unlock(&tasklist_lock); | ||
633 | |||
634 | spin_lock_irqsave(&tty->ctrl_lock, flags); | ||
635 | clear_bit(TTY_THROTTLED, &tty->flags); | 666 | clear_bit(TTY_THROTTLED, &tty->flags); |
636 | clear_bit(TTY_PUSH, &tty->flags); | 667 | clear_bit(TTY_PUSH, &tty->flags); |
637 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | 668 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); |
@@ -640,11 +671,7 @@ static void __tty_hangup(struct tty_struct *tty) | |||
640 | tty->session = NULL; | 671 | tty->session = NULL; |
641 | tty->pgrp = NULL; | 672 | tty->pgrp = NULL; |
642 | tty->ctrl_status = 0; | 673 | tty->ctrl_status = 0; |
643 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | 674 | spin_unlock_irq(&tty->ctrl_lock); |
644 | |||
645 | /* Account for the p->signal references we killed */ | ||
646 | while (refs--) | ||
647 | tty_kref_put(tty); | ||
648 | 675 | ||
649 | /* | 676 | /* |
650 | * If one of the devices matches a console pointer, we | 677 | * If one of the devices matches a console pointer, we |
@@ -666,7 +693,6 @@ static void __tty_hangup(struct tty_struct *tty) | |||
666 | */ | 693 | */ |
667 | set_bit(TTY_HUPPED, &tty->flags); | 694 | set_bit(TTY_HUPPED, &tty->flags); |
668 | clear_bit(TTY_HUPPING, &tty->flags); | 695 | clear_bit(TTY_HUPPING, &tty->flags); |
669 | tty_ldisc_enable(tty); | ||
670 | 696 | ||
671 | tty_unlock(tty); | 697 | tty_unlock(tty); |
672 | 698 | ||
@@ -679,7 +705,7 @@ static void do_tty_hangup(struct work_struct *work) | |||
679 | struct tty_struct *tty = | 705 | struct tty_struct *tty = |
680 | container_of(work, struct tty_struct, hangup_work); | 706 | container_of(work, struct tty_struct, hangup_work); |
681 | 707 | ||
682 | __tty_hangup(tty); | 708 | __tty_hangup(tty, 0); |
683 | } | 709 | } |
684 | 710 | ||
685 | /** | 711 | /** |
@@ -717,7 +743,7 @@ void tty_vhangup(struct tty_struct *tty) | |||
717 | 743 | ||
718 | printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); | 744 | printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); |
719 | #endif | 745 | #endif |
720 | __tty_hangup(tty); | 746 | __tty_hangup(tty, 0); |
721 | } | 747 | } |
722 | 748 | ||
723 | EXPORT_SYMBOL(tty_vhangup); | 749 | EXPORT_SYMBOL(tty_vhangup); |
@@ -741,6 +767,27 @@ void tty_vhangup_self(void) | |||
741 | } | 767 | } |
742 | 768 | ||
743 | /** | 769 | /** |
770 | * tty_vhangup_session - hangup session leader exit | ||
771 | * @tty: tty to hangup | ||
772 | * | ||
773 | * The session leader is exiting and hanging up its controlling terminal. | ||
774 | * Every process in the foreground process group is signalled SIGHUP. | ||
775 | * | ||
776 | * We do this synchronously so that when the syscall returns the process | ||
777 | * is complete. That guarantee is necessary for security reasons. | ||
778 | */ | ||
779 | |||
780 | static void tty_vhangup_session(struct tty_struct *tty) | ||
781 | { | ||
782 | #ifdef TTY_DEBUG_HANGUP | ||
783 | char buf[64]; | ||
784 | |||
785 | printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf)); | ||
786 | #endif | ||
787 | __tty_hangup(tty, 1); | ||
788 | } | ||
789 | |||
790 | /** | ||
744 | * tty_hung_up_p - was tty hung up | 791 | * tty_hung_up_p - was tty hung up |
745 | * @filp: file pointer of tty | 792 | * @filp: file pointer of tty |
746 | * | 793 | * |
@@ -797,18 +844,18 @@ void disassociate_ctty(int on_exit) | |||
797 | 844 | ||
798 | tty = get_current_tty(); | 845 | tty = get_current_tty(); |
799 | if (tty) { | 846 | if (tty) { |
800 | struct pid *tty_pgrp = get_pid(tty->pgrp); | 847 | if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) { |
801 | if (on_exit) { | 848 | tty_vhangup_session(tty); |
802 | if (tty->driver->type != TTY_DRIVER_TYPE_PTY) | 849 | } else { |
803 | tty_vhangup(tty); | 850 | struct pid *tty_pgrp = tty_get_pgrp(tty); |
804 | } | 851 | if (tty_pgrp) { |
805 | tty_kref_put(tty); | 852 | kill_pgrp(tty_pgrp, SIGHUP, on_exit); |
806 | if (tty_pgrp) { | ||
807 | kill_pgrp(tty_pgrp, SIGHUP, on_exit); | ||
808 | if (!on_exit) | ||
809 | kill_pgrp(tty_pgrp, SIGCONT, on_exit); | 853 | kill_pgrp(tty_pgrp, SIGCONT, on_exit); |
810 | put_pid(tty_pgrp); | 854 | put_pid(tty_pgrp); |
855 | } | ||
811 | } | 856 | } |
857 | tty_kref_put(tty); | ||
858 | |||
812 | } else if (on_exit) { | 859 | } else if (on_exit) { |
813 | struct pid *old_pgrp; | 860 | struct pid *old_pgrp; |
814 | spin_lock_irq(¤t->sighand->siglock); | 861 | spin_lock_irq(¤t->sighand->siglock); |
@@ -1344,9 +1391,7 @@ static int tty_reopen(struct tty_struct *tty) | |||
1344 | } | 1391 | } |
1345 | tty->count++; | 1392 | tty->count++; |
1346 | 1393 | ||
1347 | mutex_lock(&tty->ldisc_mutex); | ||
1348 | WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); | 1394 | WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); |
1349 | mutex_unlock(&tty->ldisc_mutex); | ||
1350 | 1395 | ||
1351 | return 0; | 1396 | return 0; |
1352 | } | 1397 | } |
@@ -1463,6 +1508,17 @@ void tty_free_termios(struct tty_struct *tty) | |||
1463 | } | 1508 | } |
1464 | EXPORT_SYMBOL(tty_free_termios); | 1509 | EXPORT_SYMBOL(tty_free_termios); |
1465 | 1510 | ||
1511 | /** | ||
1512 | * tty_flush_works - flush all works of a tty | ||
1513 | * @tty: tty device to flush works for | ||
1514 | * | ||
1515 | * Sync flush all works belonging to @tty. | ||
1516 | */ | ||
1517 | static void tty_flush_works(struct tty_struct *tty) | ||
1518 | { | ||
1519 | flush_work(&tty->SAK_work); | ||
1520 | flush_work(&tty->hangup_work); | ||
1521 | } | ||
1466 | 1522 | ||
1467 | /** | 1523 | /** |
1468 | * release_one_tty - release tty structure memory | 1524 | * release_one_tty - release tty structure memory |
@@ -1548,6 +1604,7 @@ static void release_tty(struct tty_struct *tty, int idx) | |||
1548 | tty_free_termios(tty); | 1604 | tty_free_termios(tty); |
1549 | tty_driver_remove_tty(tty->driver, tty); | 1605 | tty_driver_remove_tty(tty->driver, tty); |
1550 | tty->port->itty = NULL; | 1606 | tty->port->itty = NULL; |
1607 | cancel_work_sync(&tty->port->buf.work); | ||
1551 | 1608 | ||
1552 | if (tty->link) | 1609 | if (tty->link) |
1553 | tty_kref_put(tty->link); | 1610 | tty_kref_put(tty->link); |
@@ -1777,12 +1834,21 @@ int tty_release(struct inode *inode, struct file *filp) | |||
1777 | return 0; | 1834 | return 0; |
1778 | 1835 | ||
1779 | #ifdef TTY_DEBUG_HANGUP | 1836 | #ifdef TTY_DEBUG_HANGUP |
1780 | printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__); | 1837 | printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf)); |
1781 | #endif | 1838 | #endif |
1782 | /* | 1839 | /* |
1783 | * Ask the line discipline code to release its structures | 1840 | * Ask the line discipline code to release its structures |
1784 | */ | 1841 | */ |
1785 | tty_ldisc_release(tty, o_tty); | 1842 | tty_ldisc_release(tty, o_tty); |
1843 | |||
1844 | /* Wait for pending work before tty destruction commmences */ | ||
1845 | tty_flush_works(tty); | ||
1846 | if (o_tty) | ||
1847 | tty_flush_works(o_tty); | ||
1848 | |||
1849 | #ifdef TTY_DEBUG_HANGUP | ||
1850 | printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf)); | ||
1851 | #endif | ||
1786 | /* | 1852 | /* |
1787 | * The release_tty function takes care of the details of clearing | 1853 | * The release_tty function takes care of the details of clearing |
1788 | * the slots and preserving the termios structure. The tty_unlock_pair | 1854 | * the slots and preserving the termios structure. The tty_unlock_pair |