tty: never hold BTM while getting tty_mutex
tty_mutex is never taken with the BTM held, except for two corner cases that are worked around here. We give up the BTM before calling tty_release() in the error path of tty_open(). Similarly, we reorder the locking in ptmx_open() to get tty_mutex before the BTM. 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:
parent
ec79d6056d
commit
64ba3dc314
2 changed files with 17 additions and 19 deletions
|
@ -647,7 +647,7 @@ static const struct tty_operations pty_unix98_ops = {
|
||||||
* allocated_ptys_lock handles the list of free pty numbers
|
* allocated_ptys_lock handles the list of free pty numbers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int __ptmx_open(struct inode *inode, struct file *filp)
|
static int ptmx_open(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -656,11 +656,14 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
|
||||||
nonseekable_open(inode, filp);
|
nonseekable_open(inode, filp);
|
||||||
|
|
||||||
/* find a device that is not in use. */
|
/* find a device that is not in use. */
|
||||||
|
tty_lock();
|
||||||
index = devpts_new_index(inode);
|
index = devpts_new_index(inode);
|
||||||
|
tty_unlock();
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
return index;
|
return index;
|
||||||
|
|
||||||
mutex_lock(&tty_mutex);
|
mutex_lock(&tty_mutex);
|
||||||
|
tty_lock();
|
||||||
tty = tty_init_dev(ptm_driver, index, 1);
|
tty = tty_init_dev(ptm_driver, index, 1);
|
||||||
mutex_unlock(&tty_mutex);
|
mutex_unlock(&tty_mutex);
|
||||||
|
|
||||||
|
@ -678,24 +681,19 @@ static int __ptmx_open(struct inode *inode, struct file *filp)
|
||||||
goto out1;
|
goto out1;
|
||||||
|
|
||||||
retval = ptm_driver->ops->open(tty, filp);
|
retval = ptm_driver->ops->open(tty, filp);
|
||||||
if (!retval)
|
if (retval)
|
||||||
return 0;
|
goto out2;
|
||||||
out1:
|
out1:
|
||||||
|
tty_unlock();
|
||||||
|
return retval;
|
||||||
|
out2:
|
||||||
|
tty_unlock();
|
||||||
tty_release(inode, filp);
|
tty_release(inode, filp);
|
||||||
return retval;
|
return retval;
|
||||||
out:
|
out:
|
||||||
devpts_kill_index(inode, index);
|
devpts_kill_index(inode, index);
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ptmx_open(struct inode *inode, struct file *filp)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
tty_lock();
|
|
||||||
ret = __ptmx_open(inode, filp);
|
|
||||||
tty_unlock();
|
tty_unlock();
|
||||||
return ret;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct file_operations ptmx_fops;
|
static struct file_operations ptmx_fops;
|
||||||
|
|
|
@ -1866,19 +1866,19 @@ 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_unlock(); /* need to call tty_release without BTM */
|
||||||
tty_release(inode, filp);
|
tty_release(inode, filp);
|
||||||
if (retval != -ERESTARTSYS) {
|
if (retval != -ERESTARTSYS)
|
||||||
tty_unlock();
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
if (signal_pending(current)) {
|
if (signal_pending(current))
|
||||||
tty_unlock();
|
|
||||||
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.
|
||||||
*/
|
*/
|
||||||
|
tty_lock();
|
||||||
if (filp->f_op == &hung_up_tty_fops)
|
if (filp->f_op == &hung_up_tty_fops)
|
||||||
filp->f_op = &tty_fops;
|
filp->f_op = &tty_fops;
|
||||||
tty_unlock();
|
tty_unlock();
|
||||||
|
|
Loading…
Add table
Reference in a new issue