From 978e595f88a1fba5869aa42a4af4fba36f33ecac Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Wed, 30 Apr 2008 00:53:59 -0700 Subject: tty/serial: lay the foundations for the next set of reworks - Stop drivers calling their own flush method indirectly, it obfuscates code and it will change soon anyway - A few more lock_kernel paths temporarily needed in some driver internal waiting code - Remove private put_char method that does a write call for one char - we have that anyway - Most but not yet all of the termios copy under lock fixing (some has other dependencies to follow) - Note a few locking bugs in drivers found in the process - Kill remaining [ab]users of TIOCG/SSOFTCAR in the driver, these must go to fix the termios locking Signed-off-by: Alan Cox Cc: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tty_ioctl.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/char/tty_ioctl.c') diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index d769e43f73fb..8c4bf3e48d5b 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -396,7 +396,7 @@ EXPORT_SYMBOL(tty_termios_hw_change); static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) { int canon_change; - struct ktermios old_termios = *tty->termios; + struct ktermios old_termios; struct tty_ldisc *ld; unsigned long flags; @@ -408,7 +408,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) /* FIXME: we need to decide on some locking/ordering semantics for the set_termios notification eventually */ mutex_lock(&tty->termios_mutex); - + old_termios = *tty->termios; *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; @@ -480,7 +480,9 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) if (retval) return retval; + mutex_lock(&tty->termios_mutex); memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios)); + mutex_unlock(&tty->termios_mutex); if (opt & TERMIOS_TERMIO) { if (user_termio_to_kernel_termios(&tmp_termios, @@ -666,12 +668,14 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars) { struct tchars tmp; + mutex_lock(&tty->termios_mutex); tmp.t_intrc = tty->termios->c_cc[VINTR]; tmp.t_quitc = tty->termios->c_cc[VQUIT]; tmp.t_startc = tty->termios->c_cc[VSTART]; tmp.t_stopc = tty->termios->c_cc[VSTOP]; tmp.t_eofc = tty->termios->c_cc[VEOF]; tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */ + mutex_unlock(&tty->termios_mutex); return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -681,12 +685,14 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars) if (copy_from_user(&tmp, tchars, sizeof(tmp))) return -EFAULT; + mutex_lock(&tty->termios_mutex); tty->termios->c_cc[VINTR] = tmp.t_intrc; tty->termios->c_cc[VQUIT] = tmp.t_quitc; tty->termios->c_cc[VSTART] = tmp.t_startc; tty->termios->c_cc[VSTOP] = tmp.t_stopc; tty->termios->c_cc[VEOF] = tmp.t_eofc; tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */ + mutex_unlock(&tty->termios_mutex); return 0; } #endif @@ -696,6 +702,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) { struct ltchars tmp; + mutex_lock(&tty->termios_mutex); tmp.t_suspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */ tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; @@ -704,6 +711,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) tmp.t_flushc = tty->termios->c_cc[VEOL2]; tmp.t_werasc = tty->termios->c_cc[VWERASE]; tmp.t_lnextc = tty->termios->c_cc[VLNEXT]; + mutex_unlock(&tty->termios_mutex); return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -714,6 +722,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) if (copy_from_user(&tmp, ltchars, sizeof(tmp))) return -EFAULT; + mutex_lock(&tty->termios_mutex); tty->termios->c_cc[VSUSP] = tmp.t_suspc; /* what is dsuspc anyway? */ tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; @@ -722,6 +731,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) tty->termios->c_cc[VEOL2] = tmp.t_flushc; tty->termios->c_cc[VWERASE] = tmp.t_werasc; tty->termios->c_cc[VLNEXT] = tmp.t_lnextc; + mutex_unlock(&tty->termios_mutex); return 0; } #endif -- cgit v1.2.3