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 @@ -532,6 +532,51 @@ void tty_wakeup(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_wakeup); +/** + * tty_signal_session_leader - sends SIGHUP to session leader + * + * Send SIGHUP and SIGCONT to the session leader and its + * process group. + * + * Returns the number of processes in the session with this tty + * as their controlling terminal. This value is used to drop + * tty references for those processes. + */ +static int tty_signal_session_leader(struct tty_struct *tty) +{ + struct task_struct *p; + unsigned long flags; + int refs = 0; + + read_lock(&tasklist_lock); + if (tty->session) { + do_each_pid_task(tty->session, PIDTYPE_SID, p) { + spin_lock_irq(&p->sighand->siglock); + if (p->signal->tty == tty) { + p->signal->tty = NULL; + /* We defer the dereferences outside fo + the tasklist lock */ + refs++; + } + if (!p->signal->leader) { + spin_unlock_irq(&p->sighand->siglock); + continue; + } + __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); + __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); + put_pid(p->signal->tty_old_pgrp); /* A noop */ + spin_lock_irqsave(&tty->ctrl_lock, flags); + if (tty->pgrp) + p->signal->tty_old_pgrp = get_pid(tty->pgrp); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + spin_unlock_irq(&p->sighand->siglock); + } while_each_pid_task(tty->session, PIDTYPE_SID, p); + } + read_unlock(&tasklist_lock); + + return refs; +} + /** * __tty_hangup - actual handler for hangup events * @work: tty device @@ -558,11 +603,10 @@ static void __tty_hangup(struct tty_struct *tty) { struct file *cons_filp = NULL; struct file *filp, *f = NULL; - struct task_struct *p; struct tty_file_private *priv; int closecount = 0, n; unsigned long flags; - int refs = 0; + int refs; if (!tty) return; @@ -605,31 +649,10 @@ static void __tty_hangup(struct tty_struct *tty) */ tty_ldisc_hangup(tty); - read_lock(&tasklist_lock); - if (tty->session) { - do_each_pid_task(tty->session, PIDTYPE_SID, p) { - spin_lock_irq(&p->sighand->siglock); - if (p->signal->tty == tty) { - p->signal->tty = NULL; - /* We defer the dereferences outside fo - the tasklist lock */ - refs++; - } - if (!p->signal->leader) { - spin_unlock_irq(&p->sighand->siglock); - continue; - } - __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); - __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); - put_pid(p->signal->tty_old_pgrp); /* A noop */ - spin_lock_irqsave(&tty->ctrl_lock, flags); - if (tty->pgrp) - p->signal->tty_old_pgrp = get_pid(tty->pgrp); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - spin_unlock_irq(&p->sighand->siglock); - } while_each_pid_task(tty->session, PIDTYPE_SID, p); - } - read_unlock(&tasklist_lock); + refs = tty_signal_session_leader(tty); + /* Account for the p->signal references we killed */ + while (refs--) + tty_kref_put(tty); spin_lock_irqsave(&tty->ctrl_lock, flags); clear_bit(TTY_THROTTLED, &tty->flags); @@ -642,10 +665,6 @@ static void __tty_hangup(struct tty_struct *tty) tty->ctrl_status = 0; spin_unlock_irqrestore(&tty->ctrl_lock, flags); - /* Account for the p->signal references we killed */ - while (refs--) - tty_kref_put(tty); - /* * If one of the devices matches a console pointer, we * cannot just call hangup() because that will cause