aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2011-11-16 10:27:09 -0500
committerHerton Ronaldo Krzesinski <herton.krzesinski@canonical.com>2011-12-12 08:06:57 -0500
commitbeba0995dce90daef987271a6289b8a2762625c1 (patch)
tree20c7941ab7e3d62cf7c15570c9fb73f08e1ab57e /drivers/tty
parent51c5a5485d7ee8606a5210a10ad65b1ee6a0db1e (diff)
TTY: ldisc, wait for ldisc infinitely in hangup
BugLink: http://bugs.launchpad.net/bugs/897514 commit 0c73c08ec73dbe080b9ec56696ee21d32754d918 upstream. For /dev/console case, we do not kill all ldisc users. It's due to redirected_tty_write test in __tty_hangup. In that case there still might be a process waiting e.g. in n_tty_read for input. We wait for such processes to disappear. The problem is that we use a timeout. After this timeout, we continue closing the ldisc and start freeing tty resources. It obviously leads to crashes when the other process is woken. So to fix this, we wait infinitely before reiniting the ldisc. (The tiocsetd remains untouched -- times out after 5s.) This is nicely reproducible with this run from shell: exec 0<>/dev/console 1<>/dev/console 2<>/dev/console and stopping a getty like: systemctl stop serial-getty@ttyS0.service The crash proper may be produced only under load or with constified timing the same as for 92f6fa09b. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Cc: Dave Young <hidave.darkstar@gmail.com> Cc: Dave Jones <davej@redhat.com> Cc: Ben Hutchings <ben@decadent.org.uk> Cc: Dmitriy Matrosov <sgf.dma@gmail.com> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/tty_ldisc.c19
1 files changed, 17 insertions, 2 deletions
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index ba59b0a1fe4..a76c808afad 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -36,6 +36,7 @@
36 36
37#include <linux/kmod.h> 37#include <linux/kmod.h>
38#include <linux/nsproxy.h> 38#include <linux/nsproxy.h>
39#include <linux/ratelimit.h>
39 40
40/* 41/*
41 * This guards the refcounted line discipline lists. The lock 42 * This guards the refcounted line discipline lists. The lock
@@ -838,7 +839,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
838 tty_unlock(); 839 tty_unlock();
839 cancel_work_sync(&tty->buf.work); 840 cancel_work_sync(&tty->buf.work);
840 mutex_unlock(&tty->ldisc_mutex); 841 mutex_unlock(&tty->ldisc_mutex);
841 842retry:
842 tty_lock(); 843 tty_lock();
843 mutex_lock(&tty->ldisc_mutex); 844 mutex_lock(&tty->ldisc_mutex);
844 845
@@ -847,7 +848,21 @@ void tty_ldisc_hangup(struct tty_struct *tty)
847 it means auditing a lot of other paths so this is 848 it means auditing a lot of other paths so this is
848 a FIXME */ 849 a FIXME */
849 if (tty->ldisc) { /* Not yet closed */ 850 if (tty->ldisc) { /* Not yet closed */
850 WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ)); 851 if (atomic_read(&tty->ldisc->users) != 1) {
852 char cur_n[TASK_COMM_LEN], tty_n[64];
853 long timeout = 3 * HZ;
854 tty_unlock();
855
856 while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
857 timeout = MAX_SCHEDULE_TIMEOUT;
858 printk_ratelimited(KERN_WARNING
859 "%s: waiting (%s) for %s took too long, but we keep waiting...\n",
860 __func__, get_task_comm(cur_n, current),
861 tty_name(tty, tty_n));
862 }
863 mutex_unlock(&tty->ldisc_mutex);
864 goto retry;
865 }
851 866
852 if (reset == 0) { 867 if (reset == 0) {
853 868