aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_ldisc.c
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2011-11-16 10:27:09 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-11-17 14:36:12 -0500
commit0c73c08ec73dbe080b9ec56696ee21d32754d918 (patch)
tree1ea6d927a4766dfa0f24ad4ec482eeb6187c3c98 /drivers/tty/tty_ldisc.c
parent300420722e0734a4254f3b634e0f82664495d210 (diff)
TTY: ldisc, wait for ldisc infinitely in hangup
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> Cc: stable <stable@vger.kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/tty/tty_ldisc.c')
-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 a69a755035b6..8e0924f55446 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
@@ -837,7 +838,7 @@ void tty_ldisc_hangup(struct tty_struct *tty)
837 tty_unlock(); 838 tty_unlock();
838 cancel_work_sync(&tty->buf.work); 839 cancel_work_sync(&tty->buf.work);
839 mutex_unlock(&tty->ldisc_mutex); 840 mutex_unlock(&tty->ldisc_mutex);
840 841retry:
841 tty_lock(); 842 tty_lock();
842 mutex_lock(&tty->ldisc_mutex); 843 mutex_lock(&tty->ldisc_mutex);
843 844
@@ -846,7 +847,21 @@ void tty_ldisc_hangup(struct tty_struct *tty)
846 it means auditing a lot of other paths so this is 847 it means auditing a lot of other paths so this is
847 a FIXME */ 848 a FIXME */
848 if (tty->ldisc) { /* Not yet closed */ 849 if (tty->ldisc) { /* Not yet closed */
849 WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ)); 850 if (atomic_read(&tty->ldisc->users) != 1) {
851 char cur_n[TASK_COMM_LEN], tty_n[64];
852 long timeout = 3 * HZ;
853 tty_unlock();
854
855 while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
856 timeout = MAX_SCHEDULE_TIMEOUT;
857 printk_ratelimited(KERN_WARNING
858 "%s: waiting (%s) for %s took too long, but we keep waiting...\n",
859 __func__, get_task_comm(cur_n, current),
860 tty_name(tty, tty_n));
861 }
862 mutex_unlock(&tty->ldisc_mutex);
863 goto retry;
864 }
850 865
851 if (reset == 0) { 866 if (reset == 0) {
852 867