⬢ DragonFlyBSD Kernel Audit
DF-5794 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -1447,47 +1447,29 @@
 		tp->t_rocol = 0;
 		CLR(tp->t_state, TS_LOCAL);
 		ttwakeup(tp);
-		if (ISSET(tp->t_state, TS_TBLOCK)) {
-			if (rw & FWRITE)
-				FLUSHQ(&tp->t_outq);
-			ttyunblock(tp);
-
-			/*
-			 * Don't let leave any state that might clobber the
-			 * next line discipline (although we should do more
-			 * to send the START char).  Not clearing the state
-			 * may have caused the "putc to a clist with no
-			 * reserved cblocks" panic/kprintf.
-			 */
-			CLR(tp->t_state, TS_TBLOCK);
-
-#if 0 /* forget it, sleeping isn't always safe and we don't know when it is */
-			if (ISSET(tp->t_iflag, IXOFF)) {
-				/*
-				 * XXX wait a bit in the hope that the stop
-				 * character (if any) will go out.  Waiting
-				 * isn't good since it allows races.  This
-				 * will be fixed when the stop character is
-				 * put in a special queue.  Don't bother with
-				 * the checks in ttywait() since the timeout
-				 * will save us.
-				 */
-				SET(tp->t_state, TS_SO_OCOMPLETE);
-				ttysleep(tp, TSA_OCOMPLETE(tp), 0,
-					 "ttyfls", hz / 10);
-				/*
-				 * Don't try sending the stop character again.
-				 */
-				CLR(tp->t_state, TS_TBLOCK);
-				goto again;
-			}
-#endif
-		}
 	}
 	if (rw & FWRITE) {
 		FLUSHQ(&tp->t_outq);
 		ttwwakeup(tp);
 	}
+	/*
+	 * Unblock input flow control only after the final output flush so
+	 * the START character queued by ttyunblock() is not discarded by
+	 * the FLUSHQ above.  The old ordering stranded IXOFF peers forever:
+	 * the resume char was queued and then thrown away, while TS_TBLOCK
+	 * was already cleared so no later path re-sent it.
+	 */
+	if ((rw & FREAD) && ISSET(tp->t_state, TS_TBLOCK)) {
+		ttyunblock(tp);
+
+		/*
+		 * Don't leave any state that might clobber the next line
+		 * discipline (although we should do more to send the START
+		 * char).  Not clearing the state may have caused the
+		 * "putc to a clist with no reserved cblocks" panic/kprintf.
+		 */
+		CLR(tp->t_state, TS_TBLOCK);
+	}
 	lwkt_reltoken(&tp->t_token);
 }