diff options
Diffstat (limited to 'drivers/tty/pty.c')
| -rw-r--r-- | drivers/tty/pty.c | 79 | 
1 files changed, 37 insertions, 42 deletions
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index e16a49b507ef..cf0dc51a2690 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -626,7 +626,7 @@ static int pty_unix98_ioctl(struct tty_struct *tty,   */  static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, -		struct inode *ptm_inode, int idx) +		struct file *file, int idx)  {  	/* Master must be open via /dev/ptmx */  	return ERR_PTR(-EIO); @@ -642,12 +642,12 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,   */  static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, -		struct inode *pts_inode, int idx) +		struct file *file, int idx)  {  	struct tty_struct *tty;  	mutex_lock(&devpts_mutex); -	tty = devpts_get_priv(pts_inode); +	tty = devpts_get_priv(file->f_path.dentry);  	mutex_unlock(&devpts_mutex);  	/* Master must be open before slave */  	if (!tty) @@ -663,14 +663,14 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)  /* this is called once with whichever end is closed last */  static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)  { -	struct inode *ptmx_inode; +	struct pts_fs_info *fsi;  	if (tty->driver->subtype == PTY_TYPE_MASTER) -		ptmx_inode = tty->driver_data; +		fsi = tty->driver_data;  	else -		ptmx_inode = tty->link->driver_data; -	devpts_kill_index(ptmx_inode, tty->index); -	devpts_del_ref(ptmx_inode); +		fsi = tty->link->driver_data; +	devpts_kill_index(fsi, tty->index); +	devpts_put_ref(fsi);  }  static const struct tty_operations ptm_unix98_ops = { @@ -720,8 +720,9 @@ static const struct tty_operations pty_unix98_ops = {  static int ptmx_open(struct inode *inode, struct file *filp)  { +	struct pts_fs_info *fsi;  	struct tty_struct *tty; -	struct inode *slave_inode; +	struct dentry *dentry;  	int retval;  	int index; @@ -734,54 +735,46 @@ static int ptmx_open(struct inode *inode, struct file *filp)  	if (retval)  		return retval; +	fsi = devpts_get_ref(inode, filp); +	retval = -ENODEV; +	if (!fsi) +		goto out_free_file; +  	/* find a device that is not in use. */  	mutex_lock(&devpts_mutex); -	index = devpts_new_index(inode); -	if (index < 0) { -		retval = index; -		mutex_unlock(&devpts_mutex); -		goto err_file; -	} - +	index = devpts_new_index(fsi);  	mutex_unlock(&devpts_mutex); -	mutex_lock(&tty_mutex); -	tty = tty_init_dev(ptm_driver, index); +	retval = index; +	if (index < 0) +		goto out_put_ref; -	if (IS_ERR(tty)) { -		retval = PTR_ERR(tty); -		goto out; -	} +	mutex_lock(&tty_mutex); +	tty = tty_init_dev(ptm_driver, index);  	/* The tty returned here is locked so we can safely  	   drop the mutex */  	mutex_unlock(&tty_mutex); -	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ -	tty->driver_data = inode; +	retval = PTR_ERR(tty); +	if (IS_ERR(tty)) +		goto out;  	/* -	 * In the case where all references to ptmx inode are dropped and we -	 * still have /dev/tty opened pointing to the master/slave pair (ptmx -	 * is closed/released before /dev/tty), we must make sure that the inode -	 * is still valid when we call the final pty_unix98_shutdown, thus we -	 * hold an additional reference to the ptmx inode. For the same /dev/tty -	 * last close case, we also need to make sure the super_block isn't -	 * destroyed (devpts instance unmounted), before /dev/tty is closed and -	 * on its release devpts_kill_index is called. +	 * From here on out, the tty is "live", and the index and +	 * fsi will be killed/put by the tty_release()  	 */ -	devpts_add_ref(inode); +	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ +	tty->driver_data = fsi;  	tty_add_file(tty, filp); -	slave_inode = devpts_pty_new(inode, -			MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index, -			tty->link); -	if (IS_ERR(slave_inode)) { -		retval = PTR_ERR(slave_inode); +	dentry = devpts_pty_new(fsi, index, tty->link); +	if (IS_ERR(dentry)) { +		retval = PTR_ERR(dentry);  		goto err_release;  	} -	tty->link->driver_data = slave_inode; +	tty->link->driver_data = dentry;  	retval = ptm_driver->ops->open(tty, filp);  	if (retval) @@ -793,12 +786,14 @@ static int ptmx_open(struct inode *inode, struct file *filp)  	return 0;  err_release:  	tty_unlock(tty); +	// This will also put-ref the fsi  	tty_release(inode, filp);  	return retval;  out: -	mutex_unlock(&tty_mutex); -	devpts_kill_index(inode, index); -err_file: +	devpts_kill_index(fsi, index); +out_put_ref: +	devpts_put_ref(fsi); +out_free_file:  	tty_free_file(filp);  	return retval;  }  | 
