diff options
Diffstat (limited to 'drivers/tty/tty_io.c')
-rw-r--r-- | drivers/tty/tty_io.c | 81 |
1 files changed, 50 insertions, 31 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 05400acbc456..706c23b9cb95 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c | |||
@@ -533,6 +533,51 @@ 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 | * | ||
538 | * Send SIGHUP and SIGCONT to the session leader and its | ||
539 | * process group. | ||
540 | * | ||
541 | * Returns the number of processes in the session with this tty | ||
542 | * as their controlling terminal. This value is used to drop | ||
543 | * tty references for those processes. | ||
544 | */ | ||
545 | static int tty_signal_session_leader(struct tty_struct *tty) | ||
546 | { | ||
547 | struct task_struct *p; | ||
548 | unsigned long flags; | ||
549 | int refs = 0; | ||
550 | |||
551 | read_lock(&tasklist_lock); | ||
552 | if (tty->session) { | ||
553 | do_each_pid_task(tty->session, PIDTYPE_SID, p) { | ||
554 | spin_lock_irq(&p->sighand->siglock); | ||
555 | if (p->signal->tty == tty) { | ||
556 | p->signal->tty = NULL; | ||
557 | /* We defer the dereferences outside fo | ||
558 | the tasklist lock */ | ||
559 | refs++; | ||
560 | } | ||
561 | if (!p->signal->leader) { | ||
562 | spin_unlock_irq(&p->sighand->siglock); | ||
563 | continue; | ||
564 | } | ||
565 | __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); | ||
566 | __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); | ||
567 | put_pid(p->signal->tty_old_pgrp); /* A noop */ | ||
568 | spin_lock_irqsave(&tty->ctrl_lock, flags); | ||
569 | if (tty->pgrp) | ||
570 | p->signal->tty_old_pgrp = get_pid(tty->pgrp); | ||
571 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | ||
572 | spin_unlock_irq(&p->sighand->siglock); | ||
573 | } while_each_pid_task(tty->session, PIDTYPE_SID, p); | ||
574 | } | ||
575 | read_unlock(&tasklist_lock); | ||
576 | |||
577 | return refs; | ||
578 | } | ||
579 | |||
580 | /** | ||
536 | * __tty_hangup - actual handler for hangup events | 581 | * __tty_hangup - actual handler for hangup events |
537 | * @work: tty device | 582 | * @work: tty device |
538 | * | 583 | * |
@@ -558,11 +603,10 @@ static void __tty_hangup(struct tty_struct *tty) | |||
558 | { | 603 | { |
559 | struct file *cons_filp = NULL; | 604 | struct file *cons_filp = NULL; |
560 | struct file *filp, *f = NULL; | 605 | struct file *filp, *f = NULL; |
561 | struct task_struct *p; | ||
562 | struct tty_file_private *priv; | 606 | struct tty_file_private *priv; |
563 | int closecount = 0, n; | 607 | int closecount = 0, n; |
564 | unsigned long flags; | 608 | unsigned long flags; |
565 | int refs = 0; | 609 | int refs; |
566 | 610 | ||
567 | if (!tty) | 611 | if (!tty) |
568 | return; | 612 | return; |
@@ -605,31 +649,10 @@ static void __tty_hangup(struct tty_struct *tty) | |||
605 | */ | 649 | */ |
606 | tty_ldisc_hangup(tty); | 650 | tty_ldisc_hangup(tty); |
607 | 651 | ||
608 | read_lock(&tasklist_lock); | 652 | refs = tty_signal_session_leader(tty); |
609 | if (tty->session) { | 653 | /* Account for the p->signal references we killed */ |
610 | do_each_pid_task(tty->session, PIDTYPE_SID, p) { | 654 | while (refs--) |
611 | spin_lock_irq(&p->sighand->siglock); | 655 | tty_kref_put(tty); |
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 | 656 | ||
634 | spin_lock_irqsave(&tty->ctrl_lock, flags); | 657 | spin_lock_irqsave(&tty->ctrl_lock, flags); |
635 | clear_bit(TTY_THROTTLED, &tty->flags); | 658 | clear_bit(TTY_THROTTLED, &tty->flags); |
@@ -642,10 +665,6 @@ static void __tty_hangup(struct tty_struct *tty) | |||
642 | tty->ctrl_status = 0; | 665 | tty->ctrl_status = 0; |
643 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); | 666 | spin_unlock_irqrestore(&tty->ctrl_lock, flags); |
644 | 667 | ||
645 | /* Account for the p->signal references we killed */ | ||
646 | while (refs--) | ||
647 | tty_kref_put(tty); | ||
648 | |||
649 | /* | 668 | /* |
650 | * If one of the devices matches a console pointer, we | 669 | * If one of the devices matches a console pointer, we |
651 | * cannot just call hangup() because that will cause | 670 | * cannot just call hangup() because that will cause |