aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2006-09-29 02:01:40 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-29 09:18:24 -0700
commit5f412b24240d92212e50ebbaff2dff20c9e6f3d0 (patch)
tree4929d68d6949c887fbd3fb0594b0c1ec5a7e765d
parent67cc0161ecc9ebee6eba4af6cbfdba028090b1b9 (diff)
[PATCH] Fix locking for tty drivers when doing urgent characters
If you send a priority character (as is done for flow control) then the tty driver can either have its own method for "jumping the queue" or the characrer can be queued normally. In the latter case we call the write method but without the atomic_write_lock taken elsewhere. Make this consistent. Note that the send_xchar method if implemented remains outside of the lock as it can jump ahead of a current write so must not be locked out by it. Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/char/tty_ioctl.c18
1 files changed, 11 insertions, 7 deletions
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 4d540619ac8..3b6fa7b0be8 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -423,24 +423,28 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
*
* Send a high priority character to the tty even if stopped
*
- * Locking: none
- *
- * FIXME: overlapping calls with start/stop tty lose state of tty
+ * Locking: none for xchar method, write ordering for write method.
*/
-static void send_prio_char(struct tty_struct *tty, char ch)
+static int send_prio_char(struct tty_struct *tty, char ch)
{
int was_stopped = tty->stopped;
if (tty->driver->send_xchar) {
tty->driver->send_xchar(tty, ch);
- return;
+ return 0;
}
+
+ if (mutex_lock_interruptible(&tty->atomic_write_lock))
+ return -ERESTARTSYS;
+
if (was_stopped)
start_tty(tty);
tty->driver->write(tty, &ch, 1);
if (was_stopped)
stop_tty(tty);
+ mutex_unlock(&tty->atomic_write_lock);
+ return 0;
}
int n_tty_ioctl(struct tty_struct * tty, struct file * file,
@@ -514,11 +518,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
break;
case TCIOFF:
if (STOP_CHAR(tty) != __DISABLED_CHAR)
- send_prio_char(tty, STOP_CHAR(tty));
+ return send_prio_char(tty, STOP_CHAR(tty));
break;
case TCION:
if (START_CHAR(tty) != __DISABLED_CHAR)
- send_prio_char(tty, START_CHAR(tty));
+ return send_prio_char(tty, START_CHAR(tty));
break;
default:
return -EINVAL;