Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 64ba3dc3 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Greg Kroah-Hartman
Browse files

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: default avatarArnd Bergmann <arnd@arndb.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent ec79d605
Loading
Loading
Loading
Loading
+11 −13
Original line number Original line Diff line number Diff line
@@ -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;
+6 −6
Original line number Original line Diff line number Diff line
@@ -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();