Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2011-06-29 14:46:33 +0200
committerJiri Slaby <jslaby@suse.cz>2011-06-29 14:46:33 +0200
commitb3afb1ad56890b9f60fa978b01e79eda6bc82c97 (patch)
treeea238b5ae5c736d68f5c111b81e1a2ae0b6ffcdd
parent997e757a61750b160343ebee5cc277a0fe5e1596 (diff)
TTY: ldisc, do not close until there are readers (bnc#698247
-rw-r--r--patches.fixes/tty-ldisc-do-not-close-until-there-are-readers.patch104
-rw-r--r--series.conf5
2 files changed, 109 insertions, 0 deletions
diff --git a/patches.fixes/tty-ldisc-do-not-close-until-there-are-readers.patch b/patches.fixes/tty-ldisc-do-not-close-until-there-are-readers.patch
new file mode 100644
index 0000000000..d6b2d1fb79
--- /dev/null
+++ b/patches.fixes/tty-ldisc-do-not-close-until-there-are-readers.patch
@@ -0,0 +1,104 @@
+From 92f6fa09bd453ffe3351fa1f1377a1b7cfa911e6 Mon Sep 17 00:00:00 2001
+From: Jiri Slaby <jslaby@suse.cz>
+Date: Sun, 5 Jun 2011 14:16:16 +0200
+Subject: TTY: ldisc, do not close until there are readers
+Git-commit: 92f6fa09bd453ffe3351fa1f1377a1b7cfa911e6
+Patch-mainline: 3.0-rc6
+References: bnc#698247 bnc#693374
+
+We restored tty_ldisc_wait_idle in 100eeae2c5c (TTY: restore
+tty_ldisc_wait_idle). We used it in the ldisc changing path to fix the
+case where there are tasks in n_tty_read waiting for data and somebody
+tries to change ldisc.
+
+Similar to the case above, there may be also tasks waiting in
+n_tty_read while hangup is performed. As 65b770468e98 (tty-ldisc: turn
+ldisc user count into a proper refcount) removed the wait-until-idle
+from all paths, hangup path won't wait for them to disappear either
+now. So add it back even to the hangup path.
+
+There is a difference, we need uninterruptible sleep as there is
+obviously HUP signal pending. So tty_ldisc_wait_idle now sleeps
+without possibility to be interrupted. This is what original
+tty_ldisc_wait_idle did. After the wait idle reintroduction
+(100eeae2c5c), we have had interruptible sleeps for the ldisc changing
+path. But as there is a 5s timeout anyway, we don't allow it to be
+interrupted from now on. It's not worth the added complexity of
+deciding what kind of sleep we want.
+
+Before 65b770468e98 tty_ldisc_release was called also from
+tty_ldisc_release. It is called from tty_release, so I don't think we
+need to restore that one.
+
+This is nicely reproducible after constifying the timing when
+drivers/tty/n_tty.c is patched as follows ("TTY: ntty, add one more
+sanity check" patch is needed to actually see it explode):
+%% -1548,6 +1549,7 @@ static int n_tty_open(struct tty_struct *tty)
+
+ /* These are ugly. Currently a malloc failure here can panic */
+ if (!tty->read_buf) {
++ msleep(100);
+ tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+ if (!tty->read_buf)
+ return -ENOMEM;
+%% -1785,6 +1788,7 @@ do_it_again:
+ break;
+ }
+ timeout = schedule_timeout(timeout);
++ msleep(20);
+ continue;
+ }
+ __set_current_state(TASK_RUNNING);
+===== With a process: =====
+ while (1) {
+ int fd = open(argv[1], O_RDWR);
+ read(fd, buf, sizeof(buf));
+ close(fd);
+ }
+===== and its child: =====
+ setsid();
+ while (1) {
+ int fd = open(tty, O_RDWR|O_NOCTTY);
+ ioctl(fd, TIOCSCTTY, 1);
+ vhangup();
+ close(fd);
+ usleep(100 * (10 + random() % 1000));
+ }
+===== EOF =====
+
+References: https://bugzilla.novell.com/show_bug.cgi?id=693374
+References: https://bugzilla.novell.com/show_bug.cgi?id=694509
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Cc: stable <stable@kernel.org> [32, 33, 34, 39]
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/tty/tty_ldisc.c | 4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
+index 5d01d32..ef925d5 100644
+--- a/drivers/tty/tty_ldisc.c
++++ b/drivers/tty/tty_ldisc.c
+@@ -555,7 +555,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
+ static int tty_ldisc_wait_idle(struct tty_struct *tty)
+ {
+ int ret;
+- ret = wait_event_interruptible_timeout(tty_ldisc_idle,
++ ret = wait_event_timeout(tty_ldisc_idle,
+ atomic_read(&tty->ldisc->users) == 1, 5 * HZ);
+ if (ret < 0)
+ return ret;
+@@ -763,6 +763,8 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
+ if (IS_ERR(ld))
+ return -1;
+
++ WARN_ON_ONCE(tty_ldisc_wait_idle(tty));
++
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ tty->ldisc = NULL;
+--
+1.7.6
+
diff --git a/series.conf b/series.conf
index 9f0de59b44..20fc0ac988 100644
--- a/series.conf
+++ b/series.conf
@@ -428,6 +428,11 @@
patches.drivers/alsa-hda-0019-Increase-default-buffer-size
########################################################
+ # Char / serial
+ ########################################################
+ patches.fixes/tty-ldisc-do-not-close-until-there-are-readers.patch
+
+ ########################################################
# Other driver fixes
########################################################
patches.fixes/parport-mutex