From: Dmitry Safonov <dima@arista.com>
To: linux-kernel@vger.kernel.org
Cc: "Dmitry Safonov" <0x7f454c46@gmail.com>,
"Dmitry Safonov" <dima@arista.com>,
"Daniel Axtens" <dja@axtens.net>,
"Dmitry Vyukov" <dvyukov@google.com>,
"Mark Rutland" <mark.rutland@arm.com>,
"Michael Neuling" <mikey@neuling.org>,
"Mikulas Patocka" <mpatocka@redhat.com>,
"Nathan March" <nathan@gt.net>, "Pasi Kärkkäinen" <pasik@iki.fi>,
"Peter Hurley" <peter@hurleysoftware.com>,
"Peter Zijlstra" <peterz@infradead.org>,
"Rong, Chen" <rong.a.chen@intel.com>,
"Sergey Senozhatsky" <sergey.senozhatsky.work@gmail.com>,
"Tan Xiaojun" <tanxiaojun@huawei.com>,
"Tetsuo Handa" <penguin-kernel@I-love.SAKURA.ne.jp>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Jiri Slaby" <jslaby@suse.com>
Subject: [PATCHv6 3/7] tty: Don't block on IO when ldisc change is pending
Date: Thu, 1 Nov 2018 00:24:48 +0000 [thread overview]
Message-ID: <20181101002452.5483-4-dima@arista.com> (raw)
In-Reply-To: <20181101002452.5483-1-dima@arista.com>
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>
---
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(-)
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index dabb391909aa..99460af61b77 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -612,7 +612,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
}
/* no data */
- if (file->f_flags & O_NONBLOCK) {
+ if (tty_io_nonblock(tty, file)) {
ret = -EAGAIN;
break;
}
@@ -679,7 +679,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
if (tbuf)
break;
- if (file->f_flags & O_NONBLOCK) {
+ if (tty_io_nonblock(tty, file)) {
error = -EAGAIN;
break;
}
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
index 749a608c40b0..f75696f0ee2d 100644
--- a/drivers/tty/n_r3964.c
+++ b/drivers/tty/n_r3964.c
@@ -1085,7 +1085,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
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;
}
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 3ad460219fd6..5dc9686697cf 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1702,7 +1702,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
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
@@ -1744,7 +1744,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
fp += n;
count -= n;
rcvd += n;
- }
+ } while (!test_bit(TTY_LDISC_CHANGING, &tty->flags));
tty->receive_room = room;
@@ -2211,7 +2211,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
break;
if (!timeout)
break;
- if (file->f_flags & O_NONBLOCK) {
+ if (tty_io_nonblock(tty, file)) {
retval = -EAGAIN;
break;
}
@@ -2365,7 +2365,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
}
if (!nr)
break;
- if (file->f_flags & O_NONBLOCK) {
+ if (tty_io_nonblock(tty, file)) {
retval = -EAGAIN;
break;
}
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index fc4c97cae01e..9434d20cf3ca 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -327,6 +327,11 @@ int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
{
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;
@@ -337,6 +342,8 @@ int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
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);
}
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 414db2bce715..80ae5528ef8e 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -366,6 +366,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 */
@@ -383,6 +384,12 @@ static inline void tty_set_flow_change(struct tty_struct *tty, int val)
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);
--
2.19.1
next prev parent reply other threads:[~2018-11-01 0:25 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-11-01 0:24 [PATCHv6 0/7] tty: Hold write ldisc sem in tty_reopen() Dmitry Safonov
2018-11-01 0:24 ` [PATCHv6 1/7] tty/ldsem: Wake up readers after timed out down_write() Dmitry Safonov
2018-11-01 0:24 ` [PATCHv6 2/7] tty: Hold tty_ldisc_lock() during tty_reopen() Dmitry Safonov
2018-11-09 20:44 ` Tycho Andersen
2018-11-01 0:24 ` Dmitry Safonov [this message]
2018-11-01 0:24 ` [PATCHv6 4/7] tty: Simplify tty->count math in tty_reopen() Dmitry Safonov
2018-11-01 0:24 ` [PATCHv6 5/7] tty/ldsem: Convert to regular lockdep annotations Dmitry Safonov
2018-11-01 0:24 ` [PATCHv6 6/7] tty/ldsem: Add lockdep asserts for ldisc_sem Dmitry Safonov
2018-11-01 0:24 ` [PATCHv6 7/7] tty/ldsem: Decrement wait_readers on timeouted down_read() Dmitry Safonov
2018-11-19 12:52 ` [PATCHv6 0/7] tty: Hold write ldisc sem in tty_reopen() Pasi Kärkkäinen
2018-11-19 12:52 ` Pasi Kärkkäinen
2018-12-07 14:24 ` Guilherme G. Piccoli
2018-12-07 15:23 ` Tycho Andersen
[not found] ` <CAHD1Q_yPbhTYcKwk2PUkoabD+dTqegkVEab7nAvcrgAN10otSQ@mail.gmail.com>
2018-12-07 15:37 ` Dmitry Safonov
2018-12-07 18:09 ` Guilherme G. Piccoli
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20181101002452.5483-4-dima@arista.com \
--to=dima@arista.com \
--cc=0x7f454c46@gmail.com \
--cc=dja@axtens.net \
--cc=dvyukov@google.com \
--cc=gregkh@linuxfoundation.org \
--cc=jslaby@suse.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mikey@neuling.org \
--cc=mpatocka@redhat.com \
--cc=nathan@gt.net \
--cc=pasik@iki.fi \
--cc=penguin-kernel@I-love.SAKURA.ne.jp \
--cc=peter@hurleysoftware.com \
--cc=peterz@infradead.org \
--cc=rong.a.chen@intel.com \
--cc=sergey.senozhatsky.work@gmail.com \
--cc=tanxiaojun@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.