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>
This commit is contained in:
+25
-7
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user