@@ -2309,22 +2309,15 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
* lock themselves)
*/
-static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
- const unsigned char *buf, size_t nr)
+static ssize_t do_n_tty_write(struct tty_struct *tty, struct file *file,
+ const unsigned char *buf, size_t nr)
{
const unsigned char *b = buf;
DEFINE_WAIT_FUNC(wait, woken_wake_function);
int c;
ssize_t retval = 0;
- /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
- if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- }
-
- down_read(&tty->termios_rwsem);
+ lockdep_assert_held_read(&tty->termios_rwsem);
/* Write out any echoed characters that are still pending */
process_echoes(tty);
@@ -2392,10 +2385,28 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
remove_wait_queue(&tty->write_wait, &wait);
if (nr && tty->fasync)
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- up_read(&tty->termios_rwsem);
return (b - buf) ? b - buf : retval;
}
+static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
+ const unsigned char *buf, size_t nr)
+{
+ ssize_t retval = 0;
+
+ /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
+ if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) {
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+ }
+
+ down_read(&tty->termios_rwsem);
+ retval = do_n_tty_write(tty, file, buf, nr);
+ up_read(&tty->termios_rwsem);
+
+ return retval;
+}
+
/**
* n_tty_poll - poll method for N_TTY
* @tty: terminal device
@@ -390,7 +390,7 @@ static inline void tty_set_flow_change(struct tty_struct *tty, int val)
static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file)
{
- return file->f_flags & O_NONBLOCK ||
+ return (file && file->f_flags & O_NONBLOCK) ||
test_bit(TTY_LDISC_CHANGING, &tty->flags);
}
To simplify internal re-use of the line discipline's write method, we isolate the work it does to its own function. Since in-kernel callers might not refer to the tty through a file, the struct file* argument might make no sense, so we also stop tty_io_nonblock() from dereferencing file too early, allowing to pass NULL as the referring file here. Signed-off-by: Arseny Maslennikov <ar@cs.msu.ru> --- drivers/tty/n_tty.c | 33 ++++++++++++++++++++++----------- include/linux/tty.h | 2 +- 2 files changed, 23 insertions(+), 12 deletions(-)