[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