diff options
author | Alan Cox <alan@lxorguk.ukuu.org.uk> | 2008-04-30 00:53:29 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-30 08:29:40 -0700 |
commit | 04f378b198da233ca0aca341b113dc6579d46123 (patch) | |
tree | 696e7bd401125cee71ecaa2047c4273f38732554 /drivers/char/n_tty.c | |
parent | e52384426064bca0669a954736206adca7595d48 (diff) |
tty: BKL pushdown
- Push the BKL down into the line disciplines
- Switch the tty layer to unlocked_ioctl
- Introduce a new ctrl_lock spin lock for the control bits
- Eliminate much of the lock_kernel use in n_tty
- Prepare to (but don't yet) call the drivers with the lock dropped
on the paths that historically held the lock
BKL now primarily protects open/close/ldisc change in the tty layer
[jirislaby@gmail.com: a couple of fixes]
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/n_tty.c')
-rw-r--r-- | drivers/char/n_tty.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 0c09409fa45..001d9d87538 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -183,22 +183,24 @@ static void reset_buffer_flags(struct tty_struct *tty) * at hangup) or when the N_TTY line discipline internally has to * clean the pending queue (for example some signals). * - * FIXME: tty->ctrl_status is not spinlocked and relies on - * lock_kernel() still. + * Locking: ctrl_lock */ static void n_tty_flush_buffer(struct tty_struct *tty) { + unsigned long flags; /* clear everything and unthrottle the driver */ reset_buffer_flags(tty); if (!tty->link) return; + spin_lock_irqsave(&tty->ctrl_lock, flags); if (tty->link->packet) { tty->ctrl_status |= TIOCPKT_FLUSHREAD; wake_up_interruptible(&tty->link->read_wait); } + spin_unlock_irqrestore(&tty->ctrl_lock, flags); } /** @@ -264,7 +266,7 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty) * relevant in the world today. If you ever need them, add them here. * * Called from both the receive and transmit sides and can be called - * re-entrantly. Relies on lock_kernel() still. + * re-entrantly. Relies on lock_kernel() for tty->column state. */ static int opost(unsigned char c, struct tty_struct *tty) @@ -275,6 +277,7 @@ static int opost(unsigned char c, struct tty_struct *tty) if (!space) return -1; + lock_kernel(); if (O_OPOST(tty)) { switch (c) { case '\n': @@ -323,6 +326,7 @@ static int opost(unsigned char c, struct tty_struct *tty) } } tty->driver->put_char(tty, c); + unlock_kernel(); return 0; } @@ -337,7 +341,8 @@ static int opost(unsigned char c, struct tty_struct *tty) * the simple cases normally found and helps to generate blocks of * symbols for the console driver and thus improve performance. * - * Called from write_chan under the tty layer write lock. + * Called from write_chan under the tty layer write lock. Relies + * on lock_kernel for the tty->column state. */ static ssize_t opost_block(struct tty_struct *tty, @@ -353,6 +358,7 @@ static ssize_t opost_block(struct tty_struct *tty, if (nr > space) nr = space; + lock_kernel(); for (i = 0, cp = buf; i < nr; i++, cp++) { switch (*cp) { case '\n': @@ -387,6 +393,7 @@ break_out: if (tty->driver->flush_chars) tty->driver->flush_chars(tty); i = tty->driver->write(tty, buf, i); + unlock_kernel(); return i; } @@ -1194,6 +1201,11 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *, * Perform job control management checks on this file/tty descriptor * and if appropriate send any needed signals and return a negative * error code if action should be taken. + * + * FIXME: + * Locking: None - redirected write test is safe, testing + * current->signal should possibly lock current->sighand + * pgrp locking ? */ static int job_control(struct tty_struct *tty, struct file *file) @@ -1246,6 +1258,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, ssize_t size; long timeout; unsigned long flags; + int packet; do_it_again: @@ -1289,16 +1302,19 @@ do_it_again: if (mutex_lock_interruptible(&tty->atomic_read_lock)) return -ERESTARTSYS; } + packet = tty->packet; add_wait_queue(&tty->read_wait, &wait); while (nr) { /* First test for status change. */ - if (tty->packet && tty->link->ctrl_status) { + if (packet && tty->link->ctrl_status) { unsigned char cs; if (b != buf) break; + spin_lock_irqsave(&tty->link->ctrl_lock, flags); cs = tty->link->ctrl_status; tty->link->ctrl_status = 0; + spin_unlock_irqrestore(&tty->link->ctrl_lock, flags); if (tty_put_user(tty, cs, b++)) { retval = -EFAULT; b--; @@ -1333,6 +1349,7 @@ do_it_again: retval = -ERESTARTSYS; break; } + /* FIXME: does n_tty_set_room need locking ? */ n_tty_set_room(tty); timeout = schedule_timeout(timeout); continue; @@ -1340,7 +1357,7 @@ do_it_again: __set_current_state(TASK_RUNNING); /* Deal with packet mode. */ - if (tty->packet && b == buf) { + if (packet && b == buf) { if (tty_put_user(tty, TIOCPKT_DATA, b++)) { retval = -EFAULT; b--; @@ -1388,6 +1405,8 @@ do_it_again: break; } else { int uncopied; + /* The copy function takes the read lock and handles + locking internally for this case */ uncopied = copy_from_read_buf(tty, &b, &nr); uncopied += copy_from_read_buf(tty, &b, &nr); if (uncopied) { @@ -1429,7 +1448,6 @@ do_it_again: goto do_it_again; n_tty_set_room(tty); - return retval; } |