From cf872776fc84128bb779ce2b83a37c884c3203ae Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 11 Dec 2013 21:11:58 -0500 Subject: tty: Fix hang at ldsem_down_read() When a controlling tty is being hung up and the hang up is waiting for a just-signalled tty reader or writer to exit, and a new tty reader/writer tries to acquire an ldisc reference concurrently with the ldisc reference release from the signalled reader/writer, the hangup can hang. The new reader/writer is sleeping in ldsem_down_read() and the hangup is sleeping in ldsem_down_write() [1]. The new reader/writer fails to wakeup the waiting hangup because the wrong lock count value is checked (the old lock count rather than the new lock count) to see if the lock is unowned. Change helper function to return the new lock count if the cmpxchg was successful; document this behavior. [1] edited dmesg log from reporter SysRq : Show Blocked State task PC stack pid father systemd D ffff88040c4f0000 0 1 0 0x00000000 ffff88040c49fbe0 0000000000000046 ffff88040c4a0000 ffff88040c49ffd8 00000000001d3980 00000000001d3980 ffff88040c4a0000 ffff88040593d840 ffff88040c49fb40 ffffffff810a4cc0 0000000000000006 0000000000000023 Call Trace: [] ? sched_clock_cpu+0x9f/0xe4 [] ? sched_clock_cpu+0x9f/0xe4 [] ? sched_clock_cpu+0x9f/0xe4 [] ? sched_clock_cpu+0x9f/0xe4 [] schedule+0x24/0x5e [] schedule_timeout+0x15b/0x1ec [] ? sched_clock_cpu+0x9f/0xe4 [] ? _raw_spin_unlock_irq+0x24/0x26 [] down_read_failed+0xe3/0x1b9 [] ldsem_down_read+0x8b/0xa5 [] ? tty_ldisc_ref_wait+0x1b/0x44 [] tty_ldisc_ref_wait+0x1b/0x44 [] tty_write+0x7d/0x28a [] redirected_tty_write+0x8d/0x98 [] ? tty_write+0x28a/0x28a [] do_loop_readv_writev+0x56/0x79 [] do_readv_writev+0x1b0/0x1ff [] ? do_vfs_ioctl+0x32a/0x489 [] ? final_putname+0x1d/0x3a [] vfs_writev+0x2e/0x49 [] SyS_writev+0x47/0xaa [] system_call_fastpath+0x16/0x1b bash D ffffffff81c104c0 0 5469 5302 0x00000082 ffff8800cf817ac0 0000000000000046 ffff8804086b22a0 ffff8800cf817fd8 00000000001d3980 00000000001d3980 ffff8804086b22a0 ffff8800cf817a48 000000000000b9a0 ffff8800cf817a78 ffffffff81004675 ffff8800cf817a44 Call Trace: [] ? dump_trace+0x165/0x29c [] ? sched_clock_cpu+0x9f/0xe4 [] ? save_stack_trace+0x26/0x41 [] schedule+0x24/0x5e [] schedule_timeout+0x15b/0x1ec [] ? sched_clock_cpu+0x9f/0xe4 [] ? down_write_failed+0xa3/0x1c9 [] ? _raw_spin_unlock_irq+0x24/0x26 [] down_write_failed+0xab/0x1c9 [] ldsem_down_write+0x79/0xb1 [] ? tty_ldisc_lock_pair_timeout+0xa5/0xd9 [] tty_ldisc_lock_pair_timeout+0xa5/0xd9 [] tty_ldisc_hangup+0xc4/0x218 [] __tty_hangup+0x2e2/0x3ed [] disassociate_ctty+0x63/0x226 [] do_exit+0x79f/0xa11 [] ? get_signal_to_deliver+0x206/0x62f [] ? lock_release_holdtime.part.8+0xf/0x16e [] do_group_exit+0x47/0xb5 [] get_signal_to_deliver+0x241/0x62f [] do_signal+0x43/0x59d [] ? __audit_syscall_exit+0x21a/0x2a8 [] ? lock_release_holdtime.part.8+0xf/0x16e [] do_notify_resume+0x54/0x6c [] int_signal+0x12/0x17 Reported-by: Sami Farin Cc: # 3.12.x Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldsem.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c index 22fad8ad5ac2..d8a55e87877f 100644 --- a/drivers/tty/tty_ldsem.c +++ b/drivers/tty/tty_ldsem.c @@ -86,11 +86,21 @@ static inline long ldsem_atomic_update(long delta, struct ld_semaphore *sem) return atomic_long_add_return(delta, (atomic_long_t *)&sem->count); } +/* + * ldsem_cmpxchg() updates @*old with the last-known sem->count value. + * Returns 1 if count was successfully changed; @*old will have @new value. + * Returns 0 if count was not changed; @*old will have most recent sem->count + */ static inline int ldsem_cmpxchg(long *old, long new, struct ld_semaphore *sem) { - long tmp = *old; - *old = atomic_long_cmpxchg(&sem->count, *old, new); - return *old == tmp; + long tmp = atomic_long_cmpxchg(&sem->count, *old, new); + if (tmp == *old) { + *old = new; + return 1; + } else { + *old = tmp; + return 0; + } } /* -- cgit v1.2.3 From 6979f8d28049879e6147767d93ba6732c8bd94f4 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 10 Dec 2013 22:28:04 +0000 Subject: serial: 8250_dw: Fix LCR workaround regression Commit c49436b657d0 (serial: 8250_dw: Improve unwritable LCR workaround) caused a regression. It added a check that the LCR was written properly to detect and workaround the busy quirk, but the behaviour of bit 5 (UART_LCR_SPAR) differs between IP versions 3.00a and 3.14c per the docs. On older versions this caused the check to fail and it would repeatedly force idle and rewrite the LCR register, causing delays and preventing any input from serial being received. This is fixed by masking out UART_LCR_SPAR before making the comparison. Signed-off-by: James Hogan Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: Tim Kryger Cc: Ezequiel Garcia Cc: Matt Porter Cc: Markus Mayer Tested-by: Tim Kryger Tested-by: Ezequiel Garcia Tested-by: Heikki Krogerus Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 4658e3e0ec42..5f096c74da7e 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -96,7 +96,8 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value) if (offset == UART_LCR) { int tries = 1000; while (tries--) { - if (value == p->serial_in(p, UART_LCR)) + unsigned int lcr = p->serial_in(p, UART_LCR); + if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) return; dw8250_force_idle(p); writeb(value, p->membase + (UART_LCR << p->regshift)); @@ -132,7 +133,8 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value) if (offset == UART_LCR) { int tries = 1000; while (tries--) { - if (value == p->serial_in(p, UART_LCR)) + unsigned int lcr = p->serial_in(p, UART_LCR); + if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR)) return; dw8250_force_idle(p); writel(value, p->membase + (UART_LCR << p->regshift)); -- cgit v1.2.3 From d24c195f90cb1adb178d26d84c722d4b9e551e05 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 10 Dec 2013 12:56:59 +0200 Subject: serial: 8250_dw: add new ACPI IDs Newer Intel PCHs with LPSS have the same Designware controllers than Haswell but ACPI IDs are different. Add these IDs to the driver list. Signed-off-by: Mika Westerberg Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 5f096c74da7e..06525f10e364 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -457,6 +457,8 @@ MODULE_DEVICE_TABLE(of, dw8250_of_match); static const struct acpi_device_id dw8250_acpi_match[] = { { "INT33C4", 0 }, { "INT33C5", 0 }, + { "INT3434", 0 }, + { "INT3435", 0 }, { "80860F0A", 0 }, { }, }; -- cgit v1.2.3 From 1075a6e2dc7e2a96efc417b98dd98f57fdae985d Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 9 Dec 2013 18:06:07 -0500 Subject: n_tty: Fix apparent order of echoed output With block processing of echoed output, observed output order is still required. Push completed echoes and echo commands prior to output. Introduce echo_mark echo buffer index, which tracks completed echo commands; ie., those submitted via commit_echoes but which may not have been committed. Ensure that completed echoes are output prior to subsequent terminal writes in process_echoes(). Fixes newline/prompt output order in cooked mode shell. Cc: # 3.12.x : 39434ab n_tty: Fix missing newline echo Reported-by: Karl Dahlke Reported-by: Mikulas Patocka Signed-off-by: Peter Hurley Tested-by: Karl Dahlke Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 268b62768f2b..34aacaaae14a 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -93,6 +93,7 @@ struct n_tty_data { size_t canon_head; size_t echo_head; size_t echo_commit; + size_t echo_mark; DECLARE_BITMAP(char_map, 256); /* private to n_tty_receive_overrun (single-threaded) */ @@ -336,6 +337,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata) { ldata->read_head = ldata->canon_head = ldata->read_tail = 0; ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; + ldata->echo_mark = 0; ldata->line_start = 0; ldata->erasing = 0; @@ -787,6 +789,7 @@ static void commit_echoes(struct tty_struct *tty) size_t head; head = ldata->echo_head; + ldata->echo_mark = head; old = ldata->echo_commit - ldata->echo_tail; /* Process committed echoes if the accumulated # of bytes @@ -811,10 +814,11 @@ static void process_echoes(struct tty_struct *tty) size_t echoed; if ((!L_ECHO(tty) && !L_ECHONL(tty)) || - ldata->echo_commit == ldata->echo_tail) + ldata->echo_mark == ldata->echo_tail) return; mutex_lock(&ldata->output_lock); + ldata->echo_commit = ldata->echo_mark; echoed = __process_echoes(tty); mutex_unlock(&ldata->output_lock); @@ -822,6 +826,7 @@ static void process_echoes(struct tty_struct *tty) tty->ops->flush_chars(tty); } +/* NB: echo_mark and echo_head should be equivalent here */ static void flush_echoes(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; -- cgit v1.2.3 From c2db11eca089b60148ded7467b956a547e8a2ae0 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Mon, 2 Dec 2013 11:38:38 -0800 Subject: tty: xuartps: Properly guard sysrq specific code Commit 'tty: xuartps: Implement BREAK detection, add SYSRQ support' (0c0c47bc40a2e358d593b2d7fb93b50027fbfc0c) introduced sysrq support without properly guarding sysrq specific code which results in build errors when sysrq is disabled: DNAME=KBUILD_STR(xilinx_uartps)" -c -o drivers/tty/serial/.tmp_xilinx_uartps.o drivers/tty/serial/xilinx_uartps.c drivers/tty/serial/xilinx_uartps.c: In function 'xuartps_isr': drivers/tty/serial/xilinx_uartps.c:247:5: error: 'struct uart_port' has no member named 'sysrq' drivers/tty/serial/xilinx_uartps.c:247:5: error: 'struct uart_port' has no member named 'sysrq' drivers/tty/serial/xilinx_uartps.c:247:5: error: 'struct uart_port' has no member named 'sysrq' make[3]: *** [drivers/tty/serial/xilinx_uartps.o] Error 1 Reported-by: Masanari Iida Cc: Vlad Lungu Signed-off-by: Soren Brinkmann Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index e46e9f3f19b9..f619ad5b5eae 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -240,6 +240,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) continue; } +#ifdef SUPPORT_SYSRQ /* * uart_handle_sysrq_char() doesn't work if * spinlocked, for some reason @@ -253,6 +254,7 @@ static irqreturn_t xuartps_isr(int irq, void *dev_id) } spin_lock(&port->lock); } +#endif port->icount.rx++; -- cgit v1.2.3