[kernel/f20] Fix atomic sched BUG in tty low_latency (rhbz 1065087)

Josh Boyer jwboyer at fedoraproject.org
Mon Mar 3 14:20:53 UTC 2014


commit bf0bd9037be739d6b8a400a8dd22d4b79a66dc91
Author: Josh Boyer <jwboyer at redhat.com>
Date:   Mon Mar 3 09:20:54 2014 -0500

    Fix atomic sched BUG in tty low_latency (rhbz 1065087)

 kernel.spec                   |    7 ++
 tty-Fix-low_latency-BUG.patch |  158 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 165 insertions(+), 0 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index 9e502c3..5bbdc8f 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -770,6 +770,9 @@ Patch25026: keyring-fix.patch
 #CVE-2014-0049 rhbz 1062368 1071837
 Patch25027: kvm-x86-fix-emulator-buffer-overflow.patch
 
+#rhbz 1065087
+Patch25028: tty-Fix-low_latency-BUG.patch
+
 # END OF PATCH DEFINITIONS
 
 %endif
@@ -1496,6 +1499,9 @@ ApplyPatch keyring-fix.patch
 #CVE-2014-0049 rhbz 1062368 1071837
 ApplyPatch kvm-x86-fix-emulator-buffer-overflow.patch
 
+#rhbz 1065087
+ApplyPatch tty-Fix-low_latency-BUG.patch
+
 # END OF PATCH APPLICATIONS
 
 %endif
@@ -2309,6 +2315,7 @@ fi
 %changelog
 * Mon Mar 03 2014 Josh Boyer <jwboyer at fedoraproject.org>
 - CVE-2014-0049 kvm: mmio_fragments out-of-bounds access (rhbz 1062368 1071837)
+- Fix atomic sched BUG in tty low_latency (rhbz 1065087)
 
 * Fri Feb 28 2014 Josh Boyer <jwboyer at fedoraproject.org>
 - CVE-2014-0102 keyctl_link can be used to cause an oops (rhbz 1071396)
diff --git a/tty-Fix-low_latency-BUG.patch b/tty-Fix-low_latency-BUG.patch
new file mode 100644
index 0000000..60b3958
--- /dev/null
+++ b/tty-Fix-low_latency-BUG.patch
@@ -0,0 +1,158 @@
+Bugzilla: 1065087
+Upstream-status: 3.14
+
+From a9c3f68f3cd8d55f809fbdb0c138ed061ea1bd25 Mon Sep 17 00:00:00 2001
+From: Peter Hurley <peter at hurleysoftware.com>
+Date: Sat, 22 Feb 2014 12:31:21 +0000
+Subject: tty: Fix low_latency BUG
+
+The user-settable knob, low_latency, has been the source of
+several BUG reports which stem from flush_to_ldisc() running
+in interrupt context. Since 3.12, which added several sleeping
+locks (termios_rwsem and buf->lock) to the input processing path,
+the frequency of these BUG reports has increased.
+
+Note that changes in 3.12 did not introduce this regression;
+sleeping locks were first added to the input processing path
+with the removal of the BKL from N_TTY in commit
+a88a69c91256418c5907c2f1f8a0ec0a36f9e6cc,
+'n_tty: Fix loss of echoed characters and remove bkl from n_tty'
+and later in commit 38db89799bdf11625a831c5af33938dcb11908b6,
+'tty: throttling race fix'. Since those changes, executing
+flush_to_ldisc() in interrupt_context (ie, low_latency set), is unsafe.
+
+However, since most devices do not validate if the low_latency
+setting is appropriate for the context (process or interrupt) in
+which they receive data, some reports are due to misconfiguration.
+Further, serial dma devices for which dma fails, resort to
+interrupt receiving as a backup without resetting low_latency.
+
+Historically, low_latency was used to force wake-up the reading
+process rather than wait for the next scheduler tick. The
+effect was to trim multiple milliseconds of latency from
+when the process would receive new data.
+
+Recent tests [1] have shown that the reading process now receives
+data with only 10's of microseconds latency without low_latency set.
+
+Remove the low_latency rx steering from tty_flip_buffer_push();
+however, leave the knob as an optional hint to drivers that can
+tune their rx fifos and such like. Cleanup stale code comments
+regarding low_latency.
+
+[1] https://lkml.org/lkml/2014/2/20/434
+
+"Yay.. thats an annoying historical pain in the butt gone."
+	-- Alan Cox
+
+Reported-by: Beat Bolli <bbolli at ewanet.ch>
+Reported-by: Pavel Roskin <proski at gnu.org>
+Acked-by: David Sterba <dsterba at suse.cz>
+Cc: Grant Edwards <grant.b.edwards at gmail.com>
+Cc: Stanislaw Gruszka <sgruszka at redhat.com>
+Cc: Hal Murray <murray+fedora at ip-64-139-1-69.sjc.megapath.net>
+Cc: <stable at vger.kernel.org> # 3.12.x+
+Signed-off-by: Peter Hurley <peter at hurleysoftware.com>
+Signed-off-by: Alan Cox <alan at linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
+---
+diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
+index ebd5bff..17ee3bf 100644
+--- a/drivers/tty/ipwireless/tty.c
++++ b/drivers/tty/ipwireless/tty.c
+@@ -176,9 +176,6 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
+ 				": %d chars not inserted to flip buffer!\n",
+ 				length - work);
+ 
+-	/*
+-	 * This may sleep if ->low_latency is set
+-	 */
+ 	if (work)
+ 		tty_flip_buffer_push(&tty->port);
+ }
+diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
+index 765125d..8ebd9f8 100644
+--- a/drivers/tty/tty_buffer.c
++++ b/drivers/tty/tty_buffer.c
+@@ -351,14 +351,11 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags);
+  *	Takes any pending buffers and transfers their ownership to the
+  *	ldisc side of the queue. It then schedules those characters for
+  *	processing by the line discipline.
+- *	Note that this function can only be used when the low_latency flag
+- *	is unset. Otherwise the workqueue won't be flushed.
+  */
+ 
+ void tty_schedule_flip(struct tty_port *port)
+ {
+ 	struct tty_bufhead *buf = &port->buf;
+-	WARN_ON(port->low_latency);
+ 
+ 	buf->tail->commit = buf->tail->used;
+ 	schedule_work(&buf->work);
+@@ -482,17 +479,15 @@ static void flush_to_ldisc(struct work_struct *work)
+  */
+ void tty_flush_to_ldisc(struct tty_struct *tty)
+ {
+-	if (!tty->port->low_latency)
+-		flush_work(&tty->port->buf.work);
++	flush_work(&tty->port->buf.work);
+ }
+ 
+ /**
+  *	tty_flip_buffer_push	-	terminal
+  *	@port: tty port to push
+  *
+- *	Queue a push of the terminal flip buffers to the line discipline. This
+- *	function must not be called from IRQ context if port->low_latency is
+- *	set.
++ *	Queue a push of the terminal flip buffers to the line discipline.
++ *	Can be called from IRQ/atomic context.
+  *
+  *	In the event of the queue being busy for flipping the work will be
+  *	held off and retried later.
+@@ -500,14 +495,7 @@ void tty_flush_to_ldisc(struct tty_struct *tty)
+ 
+ void tty_flip_buffer_push(struct tty_port *port)
+ {
+-	struct tty_bufhead *buf = &port->buf;
+-
+-	buf->tail->commit = buf->tail->used;
+-
+-	if (port->low_latency)
+-		flush_to_ldisc(&buf->work);
+-	else
+-		schedule_work(&buf->work);
++	tty_schedule_flip(port);
+ }
+ EXPORT_SYMBOL(tty_flip_buffer_push);
+ 
+diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
+index b369292..ad0aca8 100644
+--- a/drivers/usb/gadget/u_serial.c
++++ b/drivers/usb/gadget/u_serial.c
+@@ -549,8 +549,8 @@ static void gs_rx_push(unsigned long _port)
+ 		port->read_started--;
+ 	}
+ 
+-	/* Push from tty to ldisc; without low_latency set this is handled by
+-	 * a workqueue, so we won't get callbacks and can hold port_lock
++	/* Push from tty to ldisc; this is handled by a workqueue,
++	 * so we won't get callbacks and can hold port_lock
+ 	 */
+ 	if (do_push)
+ 		tty_flip_buffer_push(&port->port);
+diff --git a/include/linux/tty.h b/include/linux/tty.h
+index 90b4fdc..b90b5c2 100644
+--- a/include/linux/tty.h
++++ b/include/linux/tty.h
+@@ -208,7 +208,7 @@ struct tty_port {
+ 	wait_queue_head_t	delta_msr_wait;	/* Modem status change */
+ 	unsigned long		flags;		/* TTY flags ASY_*/
+ 	unsigned char		console:1,	/* port is a console */
+-				low_latency:1;	/* direct buffer flush */
++				low_latency:1;	/* optional: tune for latency */
+ 	struct mutex		mutex;		/* Locking */
+ 	struct mutex		buf_mutex;	/* Buffer alloc lock */
+ 	unsigned char		*xmit_buf;	/* Optional buffer */
+--
+cgit v0.9.2


More information about the scm-commits mailing list