aboutsummaryrefslogtreecommitdiff
path: root/drivers/char/n_tty.c
diff options
context:
space:
mode:
authorAlan Cox <alan@lxorguk.ukuu.org.uk>2008-04-30 00:53:29 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-30 08:29:40 -0700
commit04f378b198da233ca0aca341b113dc6579d46123 (patch)
tree696e7bd401125cee71ecaa2047c4273f38732554 /drivers/char/n_tty.c
parente52384426064bca0669a954736206adca7595d48 (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.c32
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;
}