Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiri Slaby <jslaby@suse.cz>2018-11-01 12:04:30 +0100
committerJiri Slaby <jslaby@suse.cz>2018-11-01 12:04:30 +0100
commitb10485a40e62cc02e498f2d8afd3c7fa6dab90ea (patch)
treee7bcab4339afec7a92a85582489ca9cd0e64f495
parentad55b3696a576584e3b87e5a22c8f5678d0617ec (diff)
- tty: Don't block on IO when ldisc change is pending
(bnc#1105428). - Refresh patches.suse/tty-Hold-tty_ldisc_lock-during-tty_reopen.patch. - Refresh patches.suse/tty-Simplify-tty-count-math-in-tty_reopen.patch. - Refresh patches.suse/tty-ldsem-Add-lockdep-asserts-for-ldisc_sem.patch. - Refresh patches.suse/tty-ldsem-Convert-to-regular-lockdep-annotations.patch. - Refresh patches.suse/tty-ldsem-Decrement-wait_readers-on-timeouted-down_r.patch. - Refresh patches.suse/tty-ldsem-Wake-up-readers-after-timed-out-down_write.patch. Update to v6 of the patchset. It should fix the potential deadlocks.
-rw-r--r--patches.suse/tty-Don-t-block-on-IO-when-ldisc-change-is-pending.patch145
-rw-r--r--patches.suse/tty-Hold-tty_ldisc_lock-during-tty_reopen.patch9
-rw-r--r--patches.suse/tty-Simplify-tty-count-math-in-tty_reopen.patch4
-rw-r--r--patches.suse/tty-ldsem-Add-lockdep-asserts-for-ldisc_sem.patch16
-rw-r--r--patches.suse/tty-ldsem-Convert-to-regular-lockdep-annotations.patch6
-rw-r--r--patches.suse/tty-ldsem-Decrement-wait_readers-on-timeouted-down_r.patch4
-rw-r--r--patches.suse/tty-ldsem-Wake-up-readers-after-timed-out-down_write.patch9
-rw-r--r--series.conf1
8 files changed, 170 insertions, 24 deletions
diff --git a/patches.suse/tty-Don-t-block-on-IO-when-ldisc-change-is-pending.patch b/patches.suse/tty-Don-t-block-on-IO-when-ldisc-change-is-pending.patch
new file mode 100644
index 0000000000..b1f79dcb3e
--- /dev/null
+++ b/patches.suse/tty-Don-t-block-on-IO-when-ldisc-change-is-pending.patch
@@ -0,0 +1,145 @@
+From: Dmitry Safonov <dima@arista.com>
+Date: Thu, 1 Nov 2018 00:24:48 +0000
+Subject: tty: Don't block on IO when ldisc change is pending
+Patch-mainline: Submitted on 2018/11/1
+References: bnc#1105428
+
+There might be situations where tty_ldisc_lock() has blocked, but there
+is already IO on tty and it prevents line discipline changes.
+It might theoretically turn into dead-lock.
+
+Basically, provide more priority to pending tty_ldisc_lock() than to
+servicing reads/writes over tty.
+
+User-visible issue was reported by Mikulas where on pa-risc with
+Debian 5 reboot took either 80 seconds, 3 minutes or 3:25 after proper
+locking in tty_reopen().
+
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Jiri Slaby <jslaby@suse.com>
+Reported-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Dmitry Safonov <dima@arista.com>
+Signed-off-by: Jiri Slaby <jslaby@suse.cz>
+---
+ drivers/tty/n_hdlc.c | 4 ++--
+ drivers/tty/n_r3964.c | 2 +-
+ drivers/tty/n_tty.c | 8 ++++----
+ drivers/tty/tty_ldisc.c | 7 +++++++
+ include/linux/tty.h | 7 +++++++
+ 5 files changed, 21 insertions(+), 7 deletions(-)
+
+--- a/drivers/tty/n_hdlc.c
++++ b/drivers/tty/n_hdlc.c
+@@ -613,7 +613,7 @@ static ssize_t n_hdlc_tty_read(struct tt
+ }
+
+ /* no data */
+- if (file->f_flags & O_NONBLOCK) {
++ if (tty_io_nonblock(tty, file)) {
+ ret = -EAGAIN;
+ break;
+ }
+@@ -680,7 +680,7 @@ static ssize_t n_hdlc_tty_write(struct t
+ if (tbuf)
+ break;
+
+- if (file->f_flags & O_NONBLOCK) {
++ if (tty_io_nonblock(tty, file)) {
+ error = -EAGAIN;
+ break;
+ }
+--- a/drivers/tty/n_r3964.c
++++ b/drivers/tty/n_r3964.c
+@@ -1080,7 +1080,7 @@ static ssize_t r3964_read(struct tty_str
+ pMsg = remove_msg(pInfo, pClient);
+ if (pMsg == NULL) {
+ /* no messages available. */
+- if (file->f_flags & O_NONBLOCK) {
++ if (tty_io_nonblock(tty, file)) {
+ ret = -EAGAIN;
+ goto unlock;
+ }
+--- a/drivers/tty/n_tty.c
++++ b/drivers/tty/n_tty.c
+@@ -1691,7 +1691,7 @@ n_tty_receive_buf_common(struct tty_stru
+
+ down_read(&tty->termios_rwsem);
+
+- while (1) {
++ do {
+ /*
+ * When PARMRK is set, each input char may take up to 3 chars
+ * in the read buf; reduce the buffer space avail by 3x
+@@ -1733,7 +1733,7 @@ n_tty_receive_buf_common(struct tty_stru
+ fp += n;
+ count -= n;
+ rcvd += n;
+- }
++ } while (!test_bit(TTY_LDISC_CHANGING, &tty->flags));
+
+ tty->receive_room = room;
+
+@@ -2199,7 +2199,7 @@ static ssize_t n_tty_read(struct tty_str
+ break;
+ if (!timeout)
+ break;
+- if (file->f_flags & O_NONBLOCK) {
++ if (tty_io_nonblock(tty, file)) {
+ retval = -EAGAIN;
+ break;
+ }
+@@ -2353,7 +2353,7 @@ static ssize_t n_tty_write(struct tty_st
+ }
+ if (!nr)
+ break;
+- if (file->f_flags & O_NONBLOCK) {
++ if (tty_io_nonblock(tty, file)) {
+ retval = -EAGAIN;
+ break;
+ }
+--- a/drivers/tty/tty_ldisc.c
++++ b/drivers/tty/tty_ldisc.c
+@@ -339,6 +339,11 @@ int tty_ldisc_lock(struct tty_struct *tt
+ {
+ int ret;
+
++ /* Kindly asking blocked readers to release the read side */
++ set_bit(TTY_LDISC_CHANGING, &tty->flags);
++ wake_up_interruptible_all(&tty->read_wait);
++ wake_up_interruptible_all(&tty->write_wait);
++
+ ret = __tty_ldisc_lock(tty, timeout);
+ if (!ret)
+ return -EBUSY;
+@@ -349,6 +354,8 @@ int tty_ldisc_lock(struct tty_struct *tt
+ void tty_ldisc_unlock(struct tty_struct *tty)
+ {
+ clear_bit(TTY_LDISC_HALTED, &tty->flags);
++ /* Can be cleared here - ldisc_unlock will wake up writers firstly */
++ clear_bit(TTY_LDISC_CHANGING, &tty->flags);
+ __tty_ldisc_unlock(tty);
+ }
+
+--- a/include/linux/tty.h
++++ b/include/linux/tty.h
+@@ -363,6 +363,7 @@ struct tty_file_private {
+ #define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
+ #define TTY_HUPPED 18 /* Post driver->hangup() */
+ #define TTY_HUPPING 19 /* Hangup in progress */
++#define TTY_LDISC_CHANGING 20 /* Change pending - non-block IO */
+ #define TTY_LDISC_HALTED 22 /* Line discipline is halted */
+
+ /* Values for tty->flow_change */
+@@ -380,6 +381,12 @@ static inline void tty_set_flow_change(s
+ smp_mb();
+ }
+
++static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file)
++{
++ return file->f_flags & O_NONBLOCK ||
++ test_bit(TTY_LDISC_CHANGING, &tty->flags);
++}
++
+ static inline bool tty_io_error(struct tty_struct *tty)
+ {
+ return test_bit(TTY_IO_ERROR, &tty->flags);
diff --git a/patches.suse/tty-Hold-tty_ldisc_lock-during-tty_reopen.patch b/patches.suse/tty-Hold-tty_ldisc_lock-during-tty_reopen.patch
index 56a77e0543..ac0f33d9da 100644
--- a/patches.suse/tty-Hold-tty_ldisc_lock-during-tty_reopen.patch
+++ b/patches.suse/tty-Hold-tty_ldisc_lock-during-tty_reopen.patch
@@ -1,7 +1,7 @@
From: Dmitry Safonov <dima@arista.com>
-Date: Tue, 18 Sep 2018 00:52:54 +0100
+Date: Thu, 1 Nov 2018 00:24:47 +0000
Subject: tty: Hold tty_ldisc_lock() during tty_reopen()
-Patch-mainline: Submitted on 2018/09/18
+Patch-mainline: Submitted on 2018/11/1
References: bnc#1105428
tty_ldisc_reinit() doesn't race with neither tty_ldisc_hangup()
@@ -26,12 +26,9 @@ Call Trace:
tty_ldisc_reinit() should be called with ldisc_sem hold for writing,
which will protect any reader against line discipline changes.
-Backport-first: b027e2298bd5 ("tty: fix data race between tty_init_dev
-and flush of buf")
-Cc: stable@vger.kernel.org
-
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.com>
+Cc: stable@vger.kernel.org # b027e2298bd5 ("tty: fix data race between tty_init_dev and flush of buf")
Reviewed-by: Jiri Slaby <jslaby@suse.cz>
Reported-by: syzbot+3aa9784721dfb90e984d@syzkaller.appspotmail.com
Tested-by: Mark Rutland <mark.rutland@arm.com>
diff --git a/patches.suse/tty-Simplify-tty-count-math-in-tty_reopen.patch b/patches.suse/tty-Simplify-tty-count-math-in-tty_reopen.patch
index 10455330f1..b7f96cf5f2 100644
--- a/patches.suse/tty-Simplify-tty-count-math-in-tty_reopen.patch
+++ b/patches.suse/tty-Simplify-tty-count-math-in-tty_reopen.patch
@@ -1,7 +1,7 @@
From: Dmitry Safonov <dima@arista.com>
-Date: Tue, 18 Sep 2018 00:52:55 +0100
+Date: Thu, 1 Nov 2018 00:24:49 +0000
Subject: tty: Simplify tty->count math in tty_reopen()
-Patch-mainline: Submitted on 2018/09/18
+Patch-mainline: Submitted on 2018/11/1
References: bnc#1105428
As notted by Jiri, tty_ldisc_reinit() shouldn't rely on tty counter.
diff --git a/patches.suse/tty-ldsem-Add-lockdep-asserts-for-ldisc_sem.patch b/patches.suse/tty-ldsem-Add-lockdep-asserts-for-ldisc_sem.patch
index 535995a6d9..fd8e3ba344 100644
--- a/patches.suse/tty-ldsem-Add-lockdep-asserts-for-ldisc_sem.patch
+++ b/patches.suse/tty-ldsem-Add-lockdep-asserts-for-ldisc_sem.patch
@@ -1,7 +1,7 @@
From: Dmitry Safonov <dima@arista.com>
-Date: Tue, 18 Sep 2018 00:52:57 +0100
+Date: Thu, 1 Nov 2018 00:24:51 +0000
Subject: tty/ldsem: Add lockdep asserts for ldisc_sem
-Patch-mainline: Submitted on 2018/09/18
+Patch-mainline: Submitted on 2018/11/1
References: bnc#1105428
Make sure under CONFIG_LOCKDEP that each change to line discipline
@@ -28,7 +28,7 @@ Signed-off-by: Jiri Slaby <jslaby@suse.cz>
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
-@@ -483,6 +483,7 @@ static int tty_ldisc_open(struct tty_str
+@@ -490,6 +490,7 @@ static int tty_ldisc_open(struct tty_str
static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
{
@@ -36,7 +36,7 @@ Signed-off-by: Jiri Slaby <jslaby@suse.cz>
WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
clear_bit(TTY_LDISC_OPEN, &tty->flags);
if (ld->ops->close)
-@@ -504,6 +505,7 @@ static int tty_ldisc_failto(struct tty_s
+@@ -511,6 +512,7 @@ static int tty_ldisc_failto(struct tty_s
struct tty_ldisc *disc = tty_ldisc_get(tty, ld);
int r;
@@ -44,7 +44,7 @@ Signed-off-by: Jiri Slaby <jslaby@suse.cz>
if (IS_ERR(disc))
return PTR_ERR(disc);
tty->ldisc = disc;
-@@ -626,6 +628,7 @@ err:
+@@ -633,6 +635,7 @@ err:
*/
static void tty_ldisc_kill(struct tty_struct *tty)
{
@@ -52,7 +52,7 @@ Signed-off-by: Jiri Slaby <jslaby@suse.cz>
if (!tty->ldisc)
return;
/*
-@@ -673,6 +676,7 @@ int tty_ldisc_reinit(struct tty_struct *
+@@ -680,6 +683,7 @@ int tty_ldisc_reinit(struct tty_struct *
struct tty_ldisc *ld;
int retval;
@@ -60,7 +60,7 @@ Signed-off-by: Jiri Slaby <jslaby@suse.cz>
ld = tty_ldisc_get(tty, disc);
if (IS_ERR(ld)) {
BUG_ON(disc == N_TTY);
-@@ -772,6 +776,10 @@ int tty_ldisc_setup(struct tty_struct *t
+@@ -779,6 +783,10 @@ int tty_ldisc_setup(struct tty_struct *t
return retval;
if (o_tty) {
@@ -71,7 +71,7 @@ Signed-off-by: Jiri Slaby <jslaby@suse.cz>
retval = tty_ldisc_open(o_tty, o_tty->ldisc);
if (retval) {
tty_ldisc_close(tty, tty->ldisc);
-@@ -836,6 +844,7 @@ int tty_ldisc_init(struct tty_struct *tt
+@@ -843,6 +851,7 @@ int tty_ldisc_init(struct tty_struct *tt
*/
void tty_ldisc_deinit(struct tty_struct *tty)
{
diff --git a/patches.suse/tty-ldsem-Convert-to-regular-lockdep-annotations.patch b/patches.suse/tty-ldsem-Convert-to-regular-lockdep-annotations.patch
index ed5f75c2bf..6221c2c46f 100644
--- a/patches.suse/tty-ldsem-Convert-to-regular-lockdep-annotations.patch
+++ b/patches.suse/tty-ldsem-Convert-to-regular-lockdep-annotations.patch
@@ -1,11 +1,13 @@
From: Peter Zijlstra <peterz@infradead.org>
-Date: Tue, 18 Sep 2018 00:52:56 +0100
+Date: Thu, 1 Nov 2018 00:24:50 +0000
Subject: tty/ldsem: Convert to regular lockdep annotations
-Patch-mainline: Submitted on 2018/09/18
+Patch-mainline: Submitted on 2018/11/1
References: bnc#1105428
For some reason ldsem has its own lockdep wrappers, make them go away.
+Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: Jiri Slaby <jslaby@suse.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Dmitry Safonov <dima@arista.com>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
diff --git a/patches.suse/tty-ldsem-Decrement-wait_readers-on-timeouted-down_r.patch b/patches.suse/tty-ldsem-Decrement-wait_readers-on-timeouted-down_r.patch
index 1e3fa456c8..886d0a9fa8 100644
--- a/patches.suse/tty-ldsem-Decrement-wait_readers-on-timeouted-down_r.patch
+++ b/patches.suse/tty-ldsem-Decrement-wait_readers-on-timeouted-down_r.patch
@@ -1,7 +1,7 @@
From: Dmitry Safonov <dima@arista.com>
-Date: Tue, 18 Sep 2018 00:52:58 +0100
+Date: Thu, 1 Nov 2018 00:24:52 +0000
Subject: tty/ldsem: Decrement wait_readers on timeouted down_read()
-Patch-mainline: Submitted on 2018/09/18
+Patch-mainline: Submitted on 2018/11/1
References: bnc#1105428
It seems like when ldsem_down_read() fails with timeout, it misses
diff --git a/patches.suse/tty-ldsem-Wake-up-readers-after-timed-out-down_write.patch b/patches.suse/tty-ldsem-Wake-up-readers-after-timed-out-down_write.patch
index 50ea5f03b2..6d272541a5 100644
--- a/patches.suse/tty-ldsem-Wake-up-readers-after-timed-out-down_write.patch
+++ b/patches.suse/tty-ldsem-Wake-up-readers-after-timed-out-down_write.patch
@@ -1,7 +1,7 @@
From: Dmitry Safonov <dima@arista.com>
-Date: Tue, 18 Sep 2018 00:52:53 +0100
+Date: Thu, 1 Nov 2018 00:24:46 +0000
Subject: tty/ldsem: Wake up readers after timed out down_write()
-Patch-mainline: Submitted on 2018/09/18
+Patch-mainline: Submitted on 2018/11/1
References: bnc#1105428
ldsem_down_read() will sleep if there is pending writer in the queue.
@@ -21,11 +21,12 @@ other readers soft locked up:
Prevent readers wait for active readers to release ldisc semaphore.
-Link: lkml.kernel.org/r/<20171121132855.ajdv4k6swzhvktl6@wfg-t540p.sh.intel.com>
-Link: lkml.kernel.org/r/<20180907045041.GF1110@shao2-debian>
+Link: lkml.kernel.org/r/20171121132855.ajdv4k6swzhvktl6@wfg-t540p.sh.intel.com
+Link: lkml.kernel.org/r/20180907045041.GF1110@shao2-debian
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.com>
Cc: Peter Zijlstra <peterz@infradead.org>
+Cc: stable@vger.kernel.org
Reported-by: kernel test robot <rong.a.chen@intel.com>
Signed-off-by: Dmitry Safonov <dima@arista.com>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
diff --git a/series.conf b/series.conf
index 57375b760a..9b1e487e44 100644
--- a/series.conf
+++ b/series.conf
@@ -18366,6 +18366,7 @@
########################################################
patches.suse/tty-ldsem-Wake-up-readers-after-timed-out-down_write.patch
patches.suse/tty-Hold-tty_ldisc_lock-during-tty_reopen.patch
+ patches.suse/tty-Don-t-block-on-IO-when-ldisc-change-is-pending.patch
patches.suse/tty-Simplify-tty-count-math-in-tty_reopen.patch
patches.suse/tty-ldsem-Convert-to-regular-lockdep-annotations.patch
patches.suse/tty-ldsem-Add-lockdep-asserts-for-ldisc_sem.patch