Commit eeb89d91 authored by Alan Cox's avatar Alan Cox Committed by Greg Kroah-Hartman
Browse files

tty: push the BKL down into the handlers a bit



Start trying to untangle the remaining BKL mess

Updated to fix missing unlock_kernel noted by Dan Carpenter
Signed-off-by: default avatarAlan "I must be out of my tree" Cox <alan@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent e8c62103
...@@ -659,7 +659,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp) ...@@ -659,7 +659,7 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
if (!retval) if (!retval)
return 0; return 0;
out1: out1:
tty_release_dev(filp); tty_release(inode, filp);
return retval; return retval;
out: out:
devpts_kill_index(inode, index); devpts_kill_index(inode, index);
......
...@@ -142,7 +142,6 @@ ssize_t redirected_tty_write(struct file *, const char __user *, ...@@ -142,7 +142,6 @@ ssize_t redirected_tty_write(struct file *, const char __user *,
size_t, loff_t *); size_t, loff_t *);
static unsigned int tty_poll(struct file *, poll_table *); static unsigned int tty_poll(struct file *, poll_table *);
static int tty_open(struct inode *, struct file *); static int tty_open(struct inode *, struct file *);
static int tty_release(struct inode *, struct file *);
long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
static long tty_compat_ioctl(struct file *file, unsigned int cmd, static long tty_compat_ioctl(struct file *file, unsigned int cmd,
...@@ -1017,14 +1016,16 @@ out: ...@@ -1017,14 +1016,16 @@ out:
void tty_write_message(struct tty_struct *tty, char *msg) void tty_write_message(struct tty_struct *tty, char *msg)
{ {
lock_kernel();
if (tty) { if (tty) {
mutex_lock(&tty->atomic_write_lock); mutex_lock(&tty->atomic_write_lock);
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) lock_kernel();
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
unlock_kernel();
tty->ops->write(tty, msg, strlen(msg)); tty->ops->write(tty, msg, strlen(msg));
} else
unlock_kernel();
tty_write_unlock(tty); tty_write_unlock(tty);
} }
unlock_kernel();
return; return;
} }
...@@ -1202,14 +1203,21 @@ static int tty_driver_install_tty(struct tty_driver *driver, ...@@ -1202,14 +1203,21 @@ static int tty_driver_install_tty(struct tty_driver *driver,
struct tty_struct *tty) struct tty_struct *tty)
{ {
int idx = tty->index; int idx = tty->index;
int ret;
if (driver->ops->install) if (driver->ops->install) {
return driver->ops->install(driver, tty); lock_kernel();
ret = driver->ops->install(driver, tty);
unlock_kernel();
return ret;
}
if (tty_init_termios(tty) == 0) { if (tty_init_termios(tty) == 0) {
lock_kernel();
tty_driver_kref_get(driver); tty_driver_kref_get(driver);
tty->count++; tty->count++;
driver->ttys[idx] = tty; driver->ttys[idx] = tty;
unlock_kernel();
return 0; return 0;
} }
return -ENOMEM; return -ENOMEM;
...@@ -1302,10 +1310,14 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, ...@@ -1302,10 +1310,14 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
struct tty_struct *tty; struct tty_struct *tty;
int retval; int retval;
lock_kernel();
/* Check if pty master is being opened multiple times */ /* Check if pty master is being opened multiple times */
if (driver->subtype == PTY_TYPE_MASTER && if (driver->subtype == PTY_TYPE_MASTER &&
(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
unlock_kernel();
return ERR_PTR(-EIO); return ERR_PTR(-EIO);
}
unlock_kernel();
/* /*
* First time open is complex, especially for PTY devices. * First time open is complex, especially for PTY devices.
...@@ -1335,8 +1347,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, ...@@ -1335,8 +1347,9 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
* If we fail here just call release_tty to clean up. No need * If we fail here just call release_tty to clean up. No need
* to decrement the use counts, as release_tty doesn't care. * to decrement the use counts, as release_tty doesn't care.
*/ */
lock_kernel();
retval = tty_ldisc_setup(tty, tty->link); retval = tty_ldisc_setup(tty, tty->link);
unlock_kernel();
if (retval) if (retval)
goto release_mem_out; goto release_mem_out;
return tty; return tty;
...@@ -1350,7 +1363,9 @@ release_mem_out: ...@@ -1350,7 +1363,9 @@ release_mem_out:
if (printk_ratelimit()) if (printk_ratelimit())
printk(KERN_INFO "tty_init_dev: ldisc open failed, " printk(KERN_INFO "tty_init_dev: ldisc open failed, "
"clearing slot %d\n", idx); "clearing slot %d\n", idx);
lock_kernel();
release_tty(tty, idx); release_tty(tty, idx);
unlock_kernel();
return ERR_PTR(retval); return ERR_PTR(retval);
} }
...@@ -1464,7 +1479,17 @@ static void release_tty(struct tty_struct *tty, int idx) ...@@ -1464,7 +1479,17 @@ static void release_tty(struct tty_struct *tty, int idx)
tty_kref_put(tty); tty_kref_put(tty);
} }
/* /**
* tty_release - vfs callback for close
* @inode: inode of tty
* @filp: file pointer for handle to tty
*
* Called the last time each file handle is closed that references
* this tty. There may however be several such references.
*
* Locking:
* Takes bkl. See tty_release_dev
*
* Even releasing the tty structures is a tricky business.. We have * Even releasing the tty structures is a tricky business.. We have
* to be very careful that the structures are all released at the * to be very careful that the structures are all released at the
* same time, as interrupts might otherwise get the wrong pointers. * same time, as interrupts might otherwise get the wrong pointers.
...@@ -1472,20 +1497,20 @@ static void release_tty(struct tty_struct *tty, int idx) ...@@ -1472,20 +1497,20 @@ static void release_tty(struct tty_struct *tty, int idx)
* WSH 09/09/97: rewritten to avoid some nasty race conditions that could * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
* lead to double frees or releasing memory still in use. * lead to double frees or releasing memory still in use.
*/ */
void tty_release_dev(struct file *filp)
int tty_release(struct inode *inode, struct file *filp)
{ {
struct tty_struct *tty, *o_tty; struct tty_struct *tty, *o_tty;
int pty_master, tty_closing, o_tty_closing, do_sleep; int pty_master, tty_closing, o_tty_closing, do_sleep;
int devpts; int devpts;
int idx; int idx;
char buf[64]; char buf[64];
struct inode *inode;
inode = filp->f_path.dentry->d_inode;
tty = (struct tty_struct *)filp->private_data; tty = (struct tty_struct *)filp->private_data;
if (tty_paranoia_check(tty, inode, "tty_release_dev")) if (tty_paranoia_check(tty, inode, "tty_release_dev"))
return; return 0;
lock_kernel();
check_tty_count(tty, "tty_release_dev"); check_tty_count(tty, "tty_release_dev");
tty_fasync(-1, filp, 0); tty_fasync(-1, filp, 0);
...@@ -1500,19 +1525,22 @@ void tty_release_dev(struct file *filp) ...@@ -1500,19 +1525,22 @@ void tty_release_dev(struct file *filp)
if (idx < 0 || idx >= tty->driver->num) { if (idx < 0 || idx >= tty->driver->num) {
printk(KERN_DEBUG "tty_release_dev: bad idx when trying to " printk(KERN_DEBUG "tty_release_dev: bad idx when trying to "
"free (%s)\n", tty->name); "free (%s)\n", tty->name);
return; unlock_kernel();
return 0;
} }
if (!devpts) { if (!devpts) {
if (tty != tty->driver->ttys[idx]) { if (tty != tty->driver->ttys[idx]) {
unlock_kernel();
printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty " printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty "
"for (%s)\n", idx, tty->name); "for (%s)\n", idx, tty->name);
return; return 0;
} }
if (tty->termios != tty->driver->termios[idx]) { if (tty->termios != tty->driver->termios[idx]) {
unlock_kernel();
printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios " printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios "
"for (%s)\n", "for (%s)\n",
idx, tty->name); idx, tty->name);
return; return 0;
} }
} }
#endif #endif
...@@ -1526,26 +1554,30 @@ void tty_release_dev(struct file *filp) ...@@ -1526,26 +1554,30 @@ void tty_release_dev(struct file *filp)
if (tty->driver->other && if (tty->driver->other &&
!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
if (o_tty != tty->driver->other->ttys[idx]) { if (o_tty != tty->driver->other->ttys[idx]) {
unlock_kernel();
printk(KERN_DEBUG "tty_release_dev: other->table[%d] " printk(KERN_DEBUG "tty_release_dev: other->table[%d] "
"not o_tty for (%s)\n", "not o_tty for (%s)\n",
idx, tty->name); idx, tty->name);
return; return 0 ;
} }
if (o_tty->termios != tty->driver->other->termios[idx]) { if (o_tty->termios != tty->driver->other->termios[idx]) {
unlock_kernel();
printk(KERN_DEBUG "tty_release_dev: other->termios[%d] " printk(KERN_DEBUG "tty_release_dev: other->termios[%d] "
"not o_termios for (%s)\n", "not o_termios for (%s)\n",
idx, tty->name); idx, tty->name);
return; return 0;
} }
if (o_tty->link != tty) { if (o_tty->link != tty) {
unlock_kernel();
printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n"); printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n");
return; return 0;
} }
} }
#endif #endif
if (tty->ops->close) if (tty->ops->close)
tty->ops->close(tty, filp); tty->ops->close(tty, filp);
unlock_kernel();
/* /*
* Sanity check: if tty->count is going to zero, there shouldn't be * 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 * any waiters on tty->read_wait or tty->write_wait. We test the
...@@ -1568,6 +1600,7 @@ void tty_release_dev(struct file *filp) ...@@ -1568,6 +1600,7 @@ void tty_release_dev(struct file *filp)
opens on /dev/tty */ opens on /dev/tty */
mutex_lock(&tty_mutex); mutex_lock(&tty_mutex);
lock_kernel();
tty_closing = tty->count <= 1; tty_closing = tty->count <= 1;
o_tty_closing = o_tty && o_tty_closing = o_tty &&
(o_tty->count <= (pty_master ? 1 : 0)); (o_tty->count <= (pty_master ? 1 : 0));
...@@ -1598,6 +1631,7 @@ void tty_release_dev(struct file *filp) ...@@ -1598,6 +1631,7 @@ void tty_release_dev(struct file *filp)
printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue " printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue "
"active!\n", tty_name(tty, buf)); "active!\n", tty_name(tty, buf));
unlock_kernel();
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
schedule(); schedule();
} }
...@@ -1661,8 +1695,10 @@ void tty_release_dev(struct file *filp) ...@@ -1661,8 +1695,10 @@ void tty_release_dev(struct file *filp)
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
/* check whether both sides are closing ... */ /* check whether both sides are closing ... */
if (!tty_closing || (o_tty && !o_tty_closing)) if (!tty_closing || (o_tty && !o_tty_closing)) {
return; unlock_kernel();
return 0;
}
#ifdef TTY_DEBUG_HANGUP #ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "freeing tty structure..."); printk(KERN_DEBUG "freeing tty structure...");
...@@ -1680,10 +1716,12 @@ void tty_release_dev(struct file *filp) ...@@ -1680,10 +1716,12 @@ void tty_release_dev(struct file *filp)
/* Make this pty number available for reallocation */ /* Make this pty number available for reallocation */
if (devpts) if (devpts)
devpts_kill_index(inode, idx); devpts_kill_index(inode, idx);
unlock_kernel();
return 0;
} }
/** /**
* __tty_open - open a tty device * tty_open - open a tty device
* @inode: inode of device file * @inode: inode of device file
* @filp: file pointer to tty * @filp: file pointer to tty
* *
...@@ -1703,7 +1741,7 @@ void tty_release_dev(struct file *filp) ...@@ -1703,7 +1741,7 @@ void tty_release_dev(struct file *filp)
* ->siglock protects ->signal/->sighand * ->siglock protects ->signal/->sighand
*/ */
static int __tty_open(struct inode *inode, struct file *filp) static int tty_open(struct inode *inode, struct file *filp)
{ {
struct tty_struct *tty = NULL; struct tty_struct *tty = NULL;
int noctty, retval; int noctty, retval;
...@@ -1720,10 +1758,12 @@ retry_open: ...@@ -1720,10 +1758,12 @@ retry_open:
retval = 0; retval = 0;
mutex_lock(&tty_mutex); mutex_lock(&tty_mutex);
lock_kernel();
if (device == MKDEV(TTYAUX_MAJOR, 0)) { if (device == MKDEV(TTYAUX_MAJOR, 0)) {
tty = get_current_tty(); tty = get_current_tty();
if (!tty) { if (!tty) {
unlock_kernel();
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
return -ENXIO; return -ENXIO;
} }
...@@ -1755,12 +1795,14 @@ retry_open: ...@@ -1755,12 +1795,14 @@ retry_open:
goto got_driver; goto got_driver;
} }
} }
unlock_kernel();
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
return -ENODEV; return -ENODEV;
} }
driver = get_tty_driver(device, &index); driver = get_tty_driver(device, &index);
if (!driver) { if (!driver) {
unlock_kernel();
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
return -ENODEV; return -ENODEV;
} }
...@@ -1770,6 +1812,7 @@ got_driver: ...@@ -1770,6 +1812,7 @@ got_driver:
tty = tty_driver_lookup_tty(driver, inode, index); tty = tty_driver_lookup_tty(driver, inode, index);
if (IS_ERR(tty)) { if (IS_ERR(tty)) {
unlock_kernel();
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
return PTR_ERR(tty); return PTR_ERR(tty);
} }
...@@ -1784,8 +1827,10 @@ got_driver: ...@@ -1784,8 +1827,10 @@ got_driver:
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
tty_driver_kref_put(driver); tty_driver_kref_put(driver);
if (IS_ERR(tty)) if (IS_ERR(tty)) {
unlock_kernel();
return PTR_ERR(tty); return PTR_ERR(tty);
}
filp->private_data = tty; filp->private_data = tty;
file_move(filp, &tty->tty_files); file_move(filp, &tty->tty_files);
...@@ -1813,11 +1858,15 @@ got_driver: ...@@ -1813,11 +1858,15 @@ got_driver:
printk(KERN_DEBUG "error %d in opening %s...", retval, printk(KERN_DEBUG "error %d in opening %s...", retval,
tty->name); tty->name);
#endif #endif
tty_release_dev(filp); tty_release(inode, filp);
if (retval != -ERESTARTSYS) if (retval != -ERESTARTSYS) {
unlock_kernel();
return retval; return retval;
if (signal_pending(current)) }
if (signal_pending(current)) {
unlock_kernel();
return retval; return retval;
}
schedule(); schedule();
/* /*
* Need to reset f_op in case a hangup happened. * Need to reset f_op in case a hangup happened.
...@@ -1826,8 +1875,11 @@ got_driver: ...@@ -1826,8 +1875,11 @@ got_driver:
filp->f_op = &tty_fops; filp->f_op = &tty_fops;
goto retry_open; goto retry_open;
} }
unlock_kernel();
mutex_lock(&tty_mutex); mutex_lock(&tty_mutex);
lock_kernel();
spin_lock_irq(&current->sighand->siglock); spin_lock_irq(&current->sighand->siglock);
if (!noctty && if (!noctty &&
current->signal->leader && current->signal->leader &&
...@@ -1835,44 +1887,13 @@ got_driver: ...@@ -1835,44 +1887,13 @@ got_driver:
tty->session == NULL) tty->session == NULL)
__proc_set_tty(current, tty); __proc_set_tty(current, tty);
spin_unlock_irq(&current->sighand->siglock); spin_unlock_irq(&current->sighand->siglock);
unlock_kernel();
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
return 0; return 0;
} }
/* BKL pushdown: scary code avoidance wrapper */
static int tty_open(struct inode *inode, struct file *filp)
{
int ret;
lock_kernel();
ret = __tty_open(inode, filp);
unlock_kernel();
return ret;
}
/**
* tty_release - vfs callback for close
* @inode: inode of tty
* @filp: file pointer for handle to tty
*
* Called the last time each file handle is closed that references
* this tty. There may however be several such references.
*
* Locking:
* Takes bkl. See tty_release_dev
*/
static int tty_release(struct inode *inode, struct file *filp)
{
lock_kernel();
tty_release_dev(filp);
unlock_kernel();
return 0;
}
/** /**
* tty_poll - check tty status * tty_poll - check tty status
* @filp: file being polled * @filp: file being polled
...@@ -2317,9 +2338,7 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) ...@@ -2317,9 +2338,7 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
if (get_user(ldisc, p)) if (get_user(ldisc, p))
return -EFAULT; return -EFAULT;
lock_kernel();
ret = tty_set_ldisc(tty, ldisc); ret = tty_set_ldisc(tty, ldisc);
unlock_kernel();
return ret; return ret;
} }
......
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include <linux/vt_kern.h> #include <linux/vt_kern.h>
#include <linux/selection.h> #include <linux/selection.h>
#include <linux/smp_lock.h> /* For the moment */
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
...@@ -545,6 +547,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) ...@@ -545,6 +547,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
if (IS_ERR(new_ldisc)) if (IS_ERR(new_ldisc))
return PTR_ERR(new_ldisc); return PTR_ERR(new_ldisc);
lock_kernel();
/* /*
* We need to look at the tty locking here for pty/tty pairs * We need to look at the tty locking here for pty/tty pairs
* when both sides try to change in parallel. * when both sides try to change in parallel.
...@@ -558,6 +561,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) ...@@ -558,6 +561,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
*/ */
if (tty->ldisc->ops->num == ldisc) { if (tty->ldisc->ops->num == ldisc) {
unlock_kernel();
tty_ldisc_put(new_ldisc); tty_ldisc_put(new_ldisc);
return 0; return 0;
} }
...@@ -569,6 +573,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) ...@@ -569,6 +573,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty_wait_until_sent(tty, 0); tty_wait_until_sent(tty, 0);
unlock_kernel();
mutex_lock(&tty->ldisc_mutex); mutex_lock(&tty->ldisc_mutex);
/* /*
...@@ -582,6 +587,9 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) ...@@ -582,6 +587,9 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
mutex_lock(&tty->ldisc_mutex); mutex_lock(&tty->ldisc_mutex);
} }
lock_kernel();
set_bit(TTY_LDISC_CHANGING, &tty->flags); set_bit(TTY_LDISC_CHANGING, &tty->flags);
/* /*
...@@ -592,6 +600,8 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) ...@@ -592,6 +600,8 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty->receive_room = 0; tty->receive_room = 0;
o_ldisc = tty->ldisc; o_ldisc = tty->ldisc;
unlock_kernel();
/* /*
* Make sure we don't change while someone holds a * Make sure we don't change while someone holds a
* reference to the line discipline. The TTY_LDISC bit * reference to the line discipline. The TTY_LDISC bit
...@@ -617,12 +627,14 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) ...@@ -617,12 +627,14 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
flush_scheduled_work(); flush_scheduled_work();