void tty_ldisc_hangup(struct tty_struct *tty) { struct tty_ldisc *ld; int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS; int err = 0; /* * FIXME! What are the locking issues here? This may me overdoing * things... This question is especially important now that we've * removed the irqlock. */ ld = tty_ldisc_ref(tty); if (ld != NULL) { /* We may have no line discipline at this point */ if (ld->ops->flush_buffer) ld->ops->flush_buffer(tty); tty_driver_flush_buffer(tty); if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && ld->ops->write_wakeup) ld->ops->write_wakeup(tty); if (ld->ops->hangup) ld->ops->hangup(tty); tty_ldisc_deref(ld); } /* * FIXME: Once we trust the LDISC code better we can wait here for * ldisc completion and fix the driver call race */ wake_up_interruptible_poll(&tty->write_wait, POLLOUT); wake_up_interruptible_poll(&tty->read_wait, POLLIN); /* * Shutdown the current line discipline, and reset it to * N_TTY if need be. * * Avoid racing set_ldisc or tty_ldisc_release */ mutex_lock(&tty->ldisc_mutex); tty_ldisc_halt(tty); /* At this point we have a closed ldisc and we want to reopen it. We could defer this to the next open but it means auditing a lot of other paths so this is a FIXME */ if (tty->ldisc) { /* Not yet closed */ if (reset == 0) { tty_ldisc_reinit(tty, tty->termios->c_line); err = tty_ldisc_open(tty, tty->ldisc); } /* If the re-open fails or we reset then go to N_TTY. The N_TTY open cannot fail */ if (reset || err) { tty_ldisc_reinit(tty, N_TTY); WARN_ON(tty_ldisc_open(tty, tty->ldisc)); } tty_ldisc_enable(tty); } mutex_unlock(&tty->ldisc_mutex); if (reset) tty_reset_termios(tty); }
void tty_ldisc_hangup(struct tty_struct *tty) { struct tty_ldisc *ld; int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS; int err = 0; tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc); ld = tty_ldisc_ref(tty); if (ld != NULL) { if (ld->ops->flush_buffer) ld->ops->flush_buffer(tty); tty_driver_flush_buffer(tty); if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && ld->ops->write_wakeup) ld->ops->write_wakeup(tty); if (ld->ops->hangup) ld->ops->hangup(tty); tty_ldisc_deref(ld); } wake_up_interruptible_poll(&tty->write_wait, POLLOUT); wake_up_interruptible_poll(&tty->read_wait, POLLIN); tty_unlock(tty); /* * Shutdown the current line discipline, and reset it to * N_TTY if need be. * * Avoid racing set_ldisc or tty_ldisc_release */ tty_ldisc_lock_pair(tty, tty->link); tty_lock(tty); if (tty->ldisc) { /* At this point we have a halted ldisc; we want to close it and reopen a new ldisc. We could defer the reopen to the next open but it means auditing a lot of other paths so this is a FIXME */ if (reset == 0) { if (!tty_ldisc_reinit(tty, tty->termios.c_line)) err = tty_ldisc_open(tty, tty->ldisc); else err = 1; } /* If the re-open fails or we reset then go to N_TTY. The N_TTY open cannot fail */ if (reset || err) { BUG_ON(tty_ldisc_reinit(tty, N_TTY)); WARN_ON(tty_ldisc_open(tty, tty->ldisc)); } } tty_ldisc_enable_pair(tty, tty->link); if (reset) tty_reset_termios(tty); tty_ldisc_debug(tty, "re-opened ldisc: %p\n", tty->ldisc); }
void tty_ldisc_hangup(struct tty_struct *tty) { struct tty_ldisc *ld; int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS; int err = 0; /* * FIXME! What are the locking issues here? This may me overdoing * things... This question is especially important now that we've * removed the irqlock. */ ld = tty_ldisc_ref(tty); if (ld != NULL) { /* We may have no line discipline at this point */ if (ld->ops->flush_buffer) ld->ops->flush_buffer(tty); tty_driver_flush_buffer(tty); if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && ld->ops->write_wakeup) ld->ops->write_wakeup(tty); if (ld->ops->hangup) ld->ops->hangup(tty); tty_ldisc_deref(ld); } /* * FIXME: Once we trust the LDISC code better we can wait here for * ldisc completion and fix the driver call race */ wake_up_interruptible_poll(&tty->write_wait, POLLOUT); wake_up_interruptible_poll(&tty->read_wait, POLLIN); /* * Shutdown the current line discipline, and reset it to * N_TTY if need be. * * Avoid racing set_ldisc or tty_ldisc_release */ mutex_lock(&tty->ldisc_mutex); /* * this is like tty_ldisc_halt, but we need to give up * the BTM before calling cancel_work_sync, which may * need to wait for another function taking the BTM */ clear_bit(TTY_LDISC, &tty->flags); tty_unlock(tty); cancel_work_sync(&tty->port->buf.work); mutex_unlock(&tty->ldisc_mutex); retry: tty_lock(tty); mutex_lock(&tty->ldisc_mutex); /* At this point we have a closed ldisc and we want to reopen it. We could defer this to the next open but it means auditing a lot of other paths so this is a FIXME */ if (tty->ldisc) { /* Not yet closed */ if (atomic_read(&tty->ldisc->users) != 1) { char cur_n[TASK_COMM_LEN], tty_n[64]; long timeout = 3 * HZ; tty_unlock(tty); while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { timeout = MAX_SCHEDULE_TIMEOUT; printk_ratelimited(KERN_WARNING "%s: waiting (%s) for %s took too long, but we keep waiting...\n", __func__, get_task_comm(cur_n, current), tty_name(tty, tty_n)); } mutex_unlock(&tty->ldisc_mutex); goto retry; } if (reset == 0) { if (!tty_ldisc_reinit(tty, tty->termios.c_line)) err = tty_ldisc_open(tty, tty->ldisc); else err = 1; } /* If the re-open fails or we reset then go to N_TTY. The N_TTY open cannot fail */ if (reset || err) { BUG_ON(tty_ldisc_reinit(tty, N_TTY)); WARN_ON(tty_ldisc_open(tty, tty->ldisc)); } tty_ldisc_enable(tty); } mutex_unlock(&tty->ldisc_mutex); if (reset) tty_reset_termios(tty); }
void tty_ldisc_hangup(struct tty_struct *tty) { struct tty_ldisc *ld; int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS; int err = 0; ld = tty_ldisc_ref(tty); if (ld != NULL) { /* We may have no line discipline at this point */ if (ld->ops->flush_buffer) ld->ops->flush_buffer(tty); tty_driver_flush_buffer(tty); if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && ld->ops->write_wakeup) ld->ops->write_wakeup(tty); if (ld->ops->hangup) ld->ops->hangup(tty); tty_ldisc_deref(ld); } wake_up_interruptible_poll(&tty->write_wait, POLLOUT); wake_up_interruptible_poll(&tty->read_wait, POLLIN); /* * Shutdown the current line discipline, and reset it to * N_TTY if need be. * * Avoid racing set_ldisc or tty_ldisc_release */ mutex_lock(&tty->ldisc_mutex); /* * this is like tty_ldisc_halt, but we need to give up * the BTM before calling cancel_delayed_work_sync, * which may need to wait for another function taking the BTM */ clear_bit(TTY_LDISC, &tty->flags); tty_unlock(); cancel_delayed_work_sync(&tty->buf.work); mutex_unlock(&tty->ldisc_mutex); tty_lock(); mutex_lock(&tty->ldisc_mutex); if (tty->ldisc) { /* Not yet closed */ if (reset == 0) { if (!tty_ldisc_reinit(tty, tty->termios->c_line)) err = tty_ldisc_open(tty, tty->ldisc); else err = 1; } /* If the re-open fails or we reset then go to N_TTY. The N_TTY open cannot fail */ if (reset || err) { BUG_ON(tty_ldisc_reinit(tty, N_TTY)); WARN_ON(tty_ldisc_open(tty, tty->ldisc)); } tty_ldisc_enable(tty); } mutex_unlock(&tty->ldisc_mutex); if (reset) tty_reset_termios(tty); }