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

Commit 9a0e3eea authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'ptmx-cleanup'

Merge the ptmx internal interface cleanup branch.

This doesn't change semantics, but it should be a sane basis for
eventually getting the multi-instance devpts code into some sane shape
where we can get rid of the kernel config option.  Which we can
hopefully get done next merge window..

* ptmx-cleanup:
  devpts: clean up interface to pty drivers
parents 12566cc3 67245ff3
Loading
Loading
Loading
Loading
+30 −33
Original line number Diff line number Diff line
@@ -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,6 +720,7 @@ 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;
	int retval;
@@ -734,47 +735,41 @@ 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;
	index = devpts_new_index(fsi);
	mutex_unlock(&devpts_mutex);
		goto err_file;
	}

	mutex_unlock(&devpts_mutex);
	retval = index;
	if (index < 0)
		goto out_put_ref;


	mutex_lock(&tty_mutex);
	tty = tty_init_dev(ptm_driver, index);

	if (IS_ERR(tty)) {
		retval = PTR_ERR(tty);
		goto out;
	}

	/* 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,
	slave_inode = devpts_pty_new(fsi,
			MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
			tty->link);
	if (IS_ERR(slave_inode)) {
@@ -793,12 +788,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;
}
+24 −25
Original line number Diff line number Diff line
@@ -128,6 +128,7 @@ static const match_table_t tokens = {
struct pts_fs_info {
	struct ida allocated_ptys;
	struct pts_mount_opts mount_opts;
	struct super_block *sb;
	struct dentry *ptmx_dentry;
};

@@ -358,7 +359,7 @@ static const struct super_operations devpts_sops = {
	.show_options	= devpts_show_options,
};

static void *new_pts_fs_info(void)
static void *new_pts_fs_info(struct super_block *sb)
{
	struct pts_fs_info *fsi;

@@ -369,6 +370,7 @@ static void *new_pts_fs_info(void)
	ida_init(&fsi->allocated_ptys);
	fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
	fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
	fsi->sb = sb;

	return fsi;
}
@@ -384,7 +386,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
	s->s_op = &devpts_sops;
	s->s_time_gran = 1;

	s->s_fs_info = new_pts_fs_info();
	s->s_fs_info = new_pts_fs_info(s);
	if (!s->s_fs_info)
		goto fail;

@@ -524,17 +526,14 @@ static struct file_system_type devpts_fs_type = {
 * to the System V naming convention
 */

int devpts_new_index(struct inode *ptmx_inode)
int devpts_new_index(struct pts_fs_info *fsi)
{
	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
	struct pts_fs_info *fsi;
	int index;
	int ida_ret;

	if (!sb)
	if (!fsi)
		return -ENODEV;

	fsi = DEVPTS_SB(sb);
retry:
	if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
		return -ENOMEM;
@@ -564,11 +563,8 @@ int devpts_new_index(struct inode *ptmx_inode)
	return index;
}

void devpts_kill_index(struct inode *ptmx_inode, int idx)
void devpts_kill_index(struct pts_fs_info *fsi, int idx)
{
	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
	struct pts_fs_info *fsi = DEVPTS_SB(sb);

	mutex_lock(&allocated_ptys_lock);
	ida_remove(&fsi->allocated_ptys, idx);
	pty_count--;
@@ -578,21 +574,25 @@ void devpts_kill_index(struct inode *ptmx_inode, int idx)
/*
 * pty code needs to hold extra references in case of last /dev/tty close
 */

void devpts_add_ref(struct inode *ptmx_inode)
struct pts_fs_info *devpts_get_ref(struct inode *ptmx_inode, struct file *file)
{
	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
	struct super_block *sb;
	struct pts_fs_info *fsi;

	sb = pts_sb_from_inode(ptmx_inode);
	if (!sb)
		return NULL;
	fsi = DEVPTS_SB(sb);
	if (!fsi)
		return NULL;

	atomic_inc(&sb->s_active);
	ihold(ptmx_inode);
	return fsi;
}

void devpts_del_ref(struct inode *ptmx_inode)
void devpts_put_ref(struct pts_fs_info *fsi)
{
	struct super_block *sb = pts_sb_from_inode(ptmx_inode);

	iput(ptmx_inode);
	deactivate_super(sb);
	deactivate_super(fsi->sb);
}

/**
@@ -604,22 +604,21 @@ void devpts_del_ref(struct inode *ptmx_inode)
 *
 * The created inode is returned. Remove it from /dev/pts/ by devpts_pty_kill.
 */
struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index,
struct inode *devpts_pty_new(struct pts_fs_info *fsi, dev_t device, int index,
		void *priv)
{
	struct dentry *dentry;
	struct super_block *sb = pts_sb_from_inode(ptmx_inode);
	struct super_block *sb;
	struct inode *inode;
	struct dentry *root;
	struct pts_fs_info *fsi;
	struct pts_mount_opts *opts;
	char s[12];

	if (!sb)
	if (!fsi)
		return ERR_PTR(-ENODEV);

	sb = fsi->sb;
	root = sb->s_root;
	fsi = DEVPTS_SB(sb);
	opts = &fsi->mount_opts;

	inode = new_inode(sb);
+10 −24
Original line number Diff line number Diff line
@@ -15,38 +15,24 @@

#include <linux/errno.h>

struct pts_fs_info;

#ifdef CONFIG_UNIX98_PTYS

int devpts_new_index(struct inode *ptmx_inode);
void devpts_kill_index(struct inode *ptmx_inode, int idx);
void devpts_add_ref(struct inode *ptmx_inode);
void devpts_del_ref(struct inode *ptmx_inode);
/* Look up a pts fs info and get a ref to it */
struct pts_fs_info *devpts_get_ref(struct inode *, struct file *);
void devpts_put_ref(struct pts_fs_info *);

int devpts_new_index(struct pts_fs_info *);
void devpts_kill_index(struct pts_fs_info *, int);

/* mknod in devpts */
struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index,
		void *priv);
struct inode *devpts_pty_new(struct pts_fs_info *, dev_t, int, void *);
/* get private structure */
void *devpts_get_priv(struct inode *pts_inode);
/* unlink */
void devpts_pty_kill(struct inode *inode);

#else

/* Dummy stubs in the no-pty case */
static inline int devpts_new_index(struct inode *ptmx_inode) { return -EINVAL; }
static inline void devpts_kill_index(struct inode *ptmx_inode, int idx) { }
static inline void devpts_add_ref(struct inode *ptmx_inode) { }
static inline void devpts_del_ref(struct inode *ptmx_inode) { }
static inline struct inode *devpts_pty_new(struct inode *ptmx_inode,
		dev_t device, int index, void *priv)
{
	return ERR_PTR(-EINVAL);
}
static inline void *devpts_get_priv(struct inode *pts_inode)
{
	return NULL;
}
static inline void devpts_pty_kill(struct inode *inode) { }

#endif