tty: replace BKL with a new tty_lock
As a preparation for replacing the big kernel lock in the TTY layer, wrap all the callers in new macros tty_lock, tty_lock_nested and tty_unlock. Signed-off-by: Arnd Bergmann <arnd@arndb.de> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
3f582b8c11
commit
ec79d6056d
@@ -149,6 +149,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
|
||||
#else
|
||||
#define tty_compat_ioctl NULL
|
||||
#endif
|
||||
static int __tty_fasync(int fd, struct file *filp, int on);
|
||||
static int tty_fasync(int fd, struct file *filp, int on);
|
||||
static void release_tty(struct tty_struct *tty, int idx);
|
||||
static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
|
||||
@@ -483,7 +484,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
|
||||
* remains intact.
|
||||
*
|
||||
* Locking:
|
||||
* BKL
|
||||
* BTM
|
||||
* redirect lock for undoing redirection
|
||||
* file list lock for manipulating list of ttys
|
||||
* tty_ldisc_lock from called functions
|
||||
@@ -513,8 +514,11 @@ static void do_tty_hangup(struct work_struct *work)
|
||||
}
|
||||
spin_unlock(&redirect_lock);
|
||||
|
||||
/* inuse_filps is protected by the single kernel lock */
|
||||
lock_kernel();
|
||||
/* inuse_filps is protected by the single tty lock,
|
||||
this really needs to change if we want to flush the
|
||||
workqueue with the lock held */
|
||||
tty_lock_nested(); /* called with BTM held from pty_close and
|
||||
others */
|
||||
check_tty_count(tty, "do_tty_hangup");
|
||||
|
||||
file_list_lock();
|
||||
@@ -525,7 +529,7 @@ static void do_tty_hangup(struct work_struct *work)
|
||||
if (filp->f_op->write != tty_write)
|
||||
continue;
|
||||
closecount++;
|
||||
tty_fasync(-1, filp, 0); /* can't block */
|
||||
__tty_fasync(-1, filp, 0); /* can't block */
|
||||
filp->f_op = &hung_up_tty_fops;
|
||||
}
|
||||
file_list_unlock();
|
||||
@@ -594,7 +598,7 @@ static void do_tty_hangup(struct work_struct *work)
|
||||
*/
|
||||
set_bit(TTY_HUPPED, &tty->flags);
|
||||
tty_ldisc_enable(tty);
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
if (f)
|
||||
fput(f);
|
||||
}
|
||||
@@ -696,7 +700,8 @@ static void session_clear_tty(struct pid *session)
|
||||
* exiting; it is 0 if called by the ioctl TIOCNOTTY.
|
||||
*
|
||||
* Locking:
|
||||
* BKL is taken for hysterical raisins
|
||||
* BTM is taken for hysterical raisins, and held when
|
||||
* called from no_tty().
|
||||
* tty_mutex is taken to protect tty
|
||||
* ->siglock is taken to protect ->signal/->sighand
|
||||
* tasklist_lock is taken to walk process list for sessions
|
||||
@@ -714,10 +719,10 @@ void disassociate_ctty(int on_exit)
|
||||
tty = get_current_tty();
|
||||
if (tty) {
|
||||
tty_pgrp = get_pid(tty->pgrp);
|
||||
lock_kernel();
|
||||
tty_lock_nested(); /* see above */
|
||||
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
|
||||
tty_vhangup(tty);
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
tty_kref_put(tty);
|
||||
} else if (on_exit) {
|
||||
struct pid *old_pgrp;
|
||||
@@ -774,9 +779,9 @@ void disassociate_ctty(int on_exit)
|
||||
void no_tty(void)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
lock_kernel();
|
||||
tty_lock();
|
||||
disassociate_ctty(0);
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
proc_clear_tty(tsk);
|
||||
}
|
||||
|
||||
@@ -1013,19 +1018,19 @@ out:
|
||||
* We don't put it into the syslog queue right now maybe in the future if
|
||||
* really needed.
|
||||
*
|
||||
* We must still hold the BKL and test the CLOSING flag for the moment.
|
||||
* We must still hold the BTM and test the CLOSING flag for the moment.
|
||||
*/
|
||||
|
||||
void tty_write_message(struct tty_struct *tty, char *msg)
|
||||
{
|
||||
if (tty) {
|
||||
mutex_lock(&tty->atomic_write_lock);
|
||||
lock_kernel();
|
||||
tty_lock();
|
||||
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
tty->ops->write(tty, msg, strlen(msg));
|
||||
} else
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
tty_write_unlock(tty);
|
||||
}
|
||||
return;
|
||||
@@ -1208,18 +1213,18 @@ static int tty_driver_install_tty(struct tty_driver *driver,
|
||||
int ret;
|
||||
|
||||
if (driver->ops->install) {
|
||||
lock_kernel();
|
||||
tty_lock_nested(); /* already called with BTM held */
|
||||
ret = driver->ops->install(driver, tty);
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tty_init_termios(tty) == 0) {
|
||||
lock_kernel();
|
||||
tty_lock_nested();
|
||||
tty_driver_kref_get(driver);
|
||||
tty->count++;
|
||||
driver->ttys[idx] = tty;
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
return 0;
|
||||
}
|
||||
return -ENOMEM;
|
||||
@@ -1312,14 +1317,15 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
||||
struct tty_struct *tty;
|
||||
int retval;
|
||||
|
||||
lock_kernel();
|
||||
tty_lock_nested(); /* always called with tty lock held already */
|
||||
|
||||
/* Check if pty master is being opened multiple times */
|
||||
if (driver->subtype == PTY_TYPE_MASTER &&
|
||||
(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
|
||||
/*
|
||||
* First time open is complex, especially for PTY devices.
|
||||
@@ -1363,9 +1369,9 @@ release_mem_out:
|
||||
if (printk_ratelimit())
|
||||
printk(KERN_INFO "tty_init_dev: ldisc open failed, "
|
||||
"clearing slot %d\n", idx);
|
||||
lock_kernel();
|
||||
tty_lock_nested();
|
||||
release_tty(tty, idx);
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
return ERR_PTR(retval);
|
||||
}
|
||||
|
||||
@@ -1512,10 +1518,10 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
if (tty_paranoia_check(tty, inode, "tty_release_dev"))
|
||||
return 0;
|
||||
|
||||
lock_kernel();
|
||||
tty_lock();
|
||||
check_tty_count(tty, "tty_release_dev");
|
||||
|
||||
tty_fasync(-1, filp, 0);
|
||||
__tty_fasync(-1, filp, 0);
|
||||
|
||||
idx = tty->index;
|
||||
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
@@ -1527,18 +1533,18 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
if (idx < 0 || idx >= tty->driver->num) {
|
||||
printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
|
||||
"free (%s)\n", tty->name);
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
return 0;
|
||||
}
|
||||
if (!devpts) {
|
||||
if (tty != tty->driver->ttys[idx]) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
|
||||
"for (%s)\n", idx, tty->name);
|
||||
return 0;
|
||||
}
|
||||
if (tty->termios != tty->driver->termios[idx]) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
|
||||
"for (%s)\n",
|
||||
idx, tty->name);
|
||||
@@ -1556,21 +1562,21 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
if (tty->driver->other &&
|
||||
!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
|
||||
if (o_tty != tty->driver->other->ttys[idx]) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
|
||||
"not o_tty for (%s)\n",
|
||||
idx, tty->name);
|
||||
return 0 ;
|
||||
}
|
||||
if (o_tty->termios != tty->driver->other->termios[idx]) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
|
||||
"not o_termios for (%s)\n",
|
||||
idx, tty->name);
|
||||
return 0;
|
||||
}
|
||||
if (o_tty->link != tty) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1579,7 +1585,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
if (tty->ops->close)
|
||||
tty->ops->close(tty, filp);
|
||||
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
/*
|
||||
* Sanity check: if tty->count is going to zero, there shouldn't be
|
||||
* any waiters on tty->read_wait or tty->write_wait. We test the
|
||||
@@ -1602,7 +1608,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
opens on /dev/tty */
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
lock_kernel();
|
||||
tty_lock();
|
||||
tty_closing = tty->count <= 1;
|
||||
o_tty_closing = o_tty &&
|
||||
(o_tty->count <= (pty_master ? 1 : 0));
|
||||
@@ -1633,7 +1639,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
|
||||
printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
|
||||
"active!\n", tty_name(tty, buf));
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
schedule();
|
||||
}
|
||||
@@ -1698,7 +1704,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
|
||||
/* check whether both sides are closing ... */
|
||||
if (!tty_closing || (o_tty && !o_tty_closing)) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1718,7 +1724,7 @@ int tty_release(struct inode *inode, struct file *filp)
|
||||
/* Make this pty number available for reallocation */
|
||||
if (devpts)
|
||||
devpts_kill_index(inode, idx);
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1760,12 +1766,12 @@ retry_open:
|
||||
retval = 0;
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
lock_kernel();
|
||||
tty_lock();
|
||||
|
||||
if (device == MKDEV(TTYAUX_MAJOR, 0)) {
|
||||
tty = get_current_tty();
|
||||
if (!tty) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
return -ENXIO;
|
||||
}
|
||||
@@ -1797,14 +1803,14 @@ retry_open:
|
||||
goto got_driver;
|
||||
}
|
||||
}
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
driver = get_tty_driver(device, &index);
|
||||
if (!driver) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1814,7 +1820,7 @@ got_driver:
|
||||
tty = tty_driver_lookup_tty(driver, inode, index);
|
||||
|
||||
if (IS_ERR(tty)) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
return PTR_ERR(tty);
|
||||
}
|
||||
@@ -1830,7 +1836,7 @@ got_driver:
|
||||
mutex_unlock(&tty_mutex);
|
||||
tty_driver_kref_put(driver);
|
||||
if (IS_ERR(tty)) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
return PTR_ERR(tty);
|
||||
}
|
||||
|
||||
@@ -1862,11 +1868,11 @@ got_driver:
|
||||
#endif
|
||||
tty_release(inode, filp);
|
||||
if (retval != -ERESTARTSYS) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
return retval;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
return retval;
|
||||
}
|
||||
schedule();
|
||||
@@ -1875,14 +1881,14 @@ got_driver:
|
||||
*/
|
||||
if (filp->f_op == &hung_up_tty_fops)
|
||||
filp->f_op = &tty_fops;
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
goto retry_open;
|
||||
}
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
|
||||
|
||||
mutex_lock(&tty_mutex);
|
||||
lock_kernel();
|
||||
tty_lock();
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
if (!noctty &&
|
||||
current->signal->leader &&
|
||||
@@ -1890,7 +1896,7 @@ got_driver:
|
||||
tty->session == NULL)
|
||||
__proc_set_tty(current, tty);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
unlock_kernel();
|
||||
tty_unlock();
|
||||
mutex_unlock(&tty_mutex);
|
||||
return 0;
|
||||
}
|
||||
@@ -1926,13 +1932,12 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tty_fasync(int fd, struct file *filp, int on)
|
||||
static int __tty_fasync(int fd, struct file *filp, int on)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
int retval = 0;
|
||||
|
||||
lock_kernel();
|
||||
tty = (struct tty_struct *)filp->private_data;
|
||||
if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync"))
|
||||
goto out;
|
||||
@@ -1966,7 +1971,15 @@ static int tty_fasync(int fd, struct file *filp, int on)
|
||||
}
|
||||
retval = 0;
|
||||
out:
|
||||
unlock_kernel();
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int tty_fasync(int fd, struct file *filp, int on)
|
||||
{
|
||||
int retval;
|
||||
tty_lock();
|
||||
retval = __tty_fasync(fd, filp, on);
|
||||
tty_unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user