--- zzzz-none-000/linux-2.6.39.4/drivers/tty/tty_ldisc.c 2011-08-03 19:43:28.000000000 +0000 +++ puma6-arm-6490-729/linux-2.6.39.4/drivers/tty/tty_ldisc.c 2021-11-10 13:23:10.000000000 +0000 @@ -37,6 +37,7 @@ #include #include +#include /* * This guards the refcounted line discipline lists. The lock * must be taken with irqs off because there are hangup path @@ -45,7 +46,6 @@ static DEFINE_SPINLOCK(tty_ldisc_lock); static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); -static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle); /* Line disc dispatch table */ static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; @@ -82,7 +82,7 @@ return; } local_irq_restore(flags); - wake_up(&tty_ldisc_idle); + wake_up(&ld->wq_idle); } /** @@ -217,6 +217,7 @@ ld->ops = ldops; atomic_set(&ld->users, 1); + init_waitqueue_head(&ld->wq_idle); return ld; } @@ -552,13 +553,11 @@ * Wait for the line discipline to become idle. The discipline must * have been halted for this to guarantee it remains idle. */ -static int tty_ldisc_wait_idle(struct tty_struct *tty) +static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) { int ret; - ret = wait_event_timeout(tty_ldisc_idle, - atomic_read(&tty->ldisc->users) == 1, 5 * HZ); - if (ret < 0) - return ret; + ret = wait_event_timeout(tty->ldisc->wq_idle, + atomic_read(&tty->ldisc->users) == 1, timeout); return ret > 0 ? 0 : -EBUSY; } @@ -666,7 +665,7 @@ tty_ldisc_flush_works(tty); - retval = tty_ldisc_wait_idle(tty); + retval = tty_ldisc_wait_idle(tty, 5 * HZ); tty_lock(); mutex_lock(&tty->ldisc_mutex); @@ -677,7 +676,7 @@ goto enable; } - if (test_bit(TTY_HUPPED, &tty->flags)) { + if (test_bit(TTY_HUPPING, &tty->flags)) { /* We were raced by the hangup method. It will have stomped the ldisc data and closed the ldisc down */ clear_bit(TTY_LDISC_CHANGING, &tty->flags); @@ -763,7 +762,7 @@ if (IS_ERR(ld)) return -1; - WARN_ON_ONCE(tty_ldisc_wait_idle(tty)); + WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ)); tty_ldisc_close(tty, tty->ldisc); tty_ldisc_put(tty->ldisc); @@ -840,6 +839,7 @@ cancel_work_sync(&tty->buf.work); mutex_unlock(&tty->ldisc_mutex); +retry: tty_lock(); mutex_lock(&tty->ldisc_mutex); @@ -848,6 +848,21 @@ 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(); + 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))