Properly drain the TTY when both revoke(2) and close(2) end up closing

the TTY. In such a case, ttydev_close() is called multiple times and
each time, t_revokecnt is incremented and cv_broadcast() is called for
both the t_outwait and t_inwait condition variables.
Let's say revoke(2) comes in first and gets to call tty_drain() from
ttydev_leave(). Let's say that the revoke comes from init(8) as the
result of running "shutdown -r now". Since shutdown prints various
messages to the console before announing that the machine will reboot
immediately, let's also say that the output queue is not empty and
that tty_drain() has something to do. Let's assume this all happens
on a 9600 baud serial console, so it takes a time to drain.
The shutdown command will exit(2) and as such will end up closing
stdout. Let's say this close will come in second, bump t_revokecnt
and call tty_wakeup(). This has tty_wait() return prematurely and
the next thing that will happen is that the thread doing revoke(2)
will flush the TTY. Since the drain wasn't complete, the flush will
effectively drop whatever is left in t_outq.

This change takes into account that tty_drain() will return ERESTART
due to the fact that t_revokecnt was bumped and in that case simply
call tty_drain() again. The thread in question is already performing
the close so it can safely finish draining the TTY before destroying
the TTY structure.

Now all messages from shutdown will be printed on the serial console.

Obtained from:	Juniper Networks, Inc.
This commit is contained in:
Marcel Moolenaar 2013-12-16 00:50:14 +00:00
parent 68cfe72642
commit 15773775f7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=259441

View File

@ -191,8 +191,10 @@ ttydev_leave(struct tty *tp)
/* Drain any output. */
MPASS((tp->t_flags & TF_STOPPED) == 0);
if (!tty_gone(tp))
tty_drain(tp);
if (!tty_gone(tp)) {
while (tty_drain(tp) == ERESTART)
;
}
ttydisc_close(tp);