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
This commit is contained in:
Коммит
9a0e3eea25
|
@ -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 */
|
/* this is called once with whichever end is closed last */
|
||||||
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
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)
|
if (tty->driver->subtype == PTY_TYPE_MASTER)
|
||||||
ptmx_inode = tty->driver_data;
|
fsi = tty->driver_data;
|
||||||
else
|
else
|
||||||
ptmx_inode = tty->link->driver_data;
|
fsi = tty->link->driver_data;
|
||||||
devpts_kill_index(ptmx_inode, tty->index);
|
devpts_kill_index(fsi, tty->index);
|
||||||
devpts_del_ref(ptmx_inode);
|
devpts_put_ref(fsi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct tty_operations ptm_unix98_ops = {
|
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)
|
static int ptmx_open(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
|
struct pts_fs_info *fsi;
|
||||||
struct tty_struct *tty;
|
struct tty_struct *tty;
|
||||||
struct inode *slave_inode;
|
struct inode *slave_inode;
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -734,47 +735,41 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
||||||
if (retval)
|
if (retval)
|
||||||
return 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. */
|
/* find a device that is not in use. */
|
||||||
mutex_lock(&devpts_mutex);
|
mutex_lock(&devpts_mutex);
|
||||||
index = devpts_new_index(inode);
|
index = devpts_new_index(fsi);
|
||||||
if (index < 0) {
|
|
||||||
retval = index;
|
|
||||||
mutex_unlock(&devpts_mutex);
|
|
||||||
goto err_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&devpts_mutex);
|
mutex_unlock(&devpts_mutex);
|
||||||
|
|
||||||
|
retval = index;
|
||||||
|
if (index < 0)
|
||||||
|
goto out_put_ref;
|
||||||
|
|
||||||
|
|
||||||
mutex_lock(&tty_mutex);
|
mutex_lock(&tty_mutex);
|
||||||
tty = tty_init_dev(ptm_driver, index);
|
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
|
/* The tty returned here is locked so we can safely
|
||||||
drop the mutex */
|
drop the mutex */
|
||||||
mutex_unlock(&tty_mutex);
|
mutex_unlock(&tty_mutex);
|
||||||
|
|
||||||
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
|
retval = PTR_ERR(tty);
|
||||||
tty->driver_data = inode;
|
if (IS_ERR(tty))
|
||||||
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the case where all references to ptmx inode are dropped and we
|
* From here on out, the tty is "live", and the index and
|
||||||
* still have /dev/tty opened pointing to the master/slave pair (ptmx
|
* fsi will be killed/put by the tty_release()
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
devpts_add_ref(inode);
|
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
|
||||||
|
tty->driver_data = fsi;
|
||||||
|
|
||||||
tty_add_file(tty, filp);
|
tty_add_file(tty, filp);
|
||||||
|
|
||||||
slave_inode = devpts_pty_new(inode,
|
slave_inode = devpts_pty_new(fsi,
|
||||||
MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
|
MKDEV(UNIX98_PTY_SLAVE_MAJOR, index), index,
|
||||||
tty->link);
|
tty->link);
|
||||||
if (IS_ERR(slave_inode)) {
|
if (IS_ERR(slave_inode)) {
|
||||||
|
@ -793,12 +788,14 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
||||||
return 0;
|
return 0;
|
||||||
err_release:
|
err_release:
|
||||||
tty_unlock(tty);
|
tty_unlock(tty);
|
||||||
|
// This will also put-ref the fsi
|
||||||
tty_release(inode, filp);
|
tty_release(inode, filp);
|
||||||
return retval;
|
return retval;
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&tty_mutex);
|
devpts_kill_index(fsi, index);
|
||||||
devpts_kill_index(inode, index);
|
out_put_ref:
|
||||||
err_file:
|
devpts_put_ref(fsi);
|
||||||
|
out_free_file:
|
||||||
tty_free_file(filp);
|
tty_free_file(filp);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,6 +128,7 @@ static const match_table_t tokens = {
|
||||||
struct pts_fs_info {
|
struct pts_fs_info {
|
||||||
struct ida allocated_ptys;
|
struct ida allocated_ptys;
|
||||||
struct pts_mount_opts mount_opts;
|
struct pts_mount_opts mount_opts;
|
||||||
|
struct super_block *sb;
|
||||||
struct dentry *ptmx_dentry;
|
struct dentry *ptmx_dentry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -358,7 +359,7 @@ static const struct super_operations devpts_sops = {
|
||||||
.show_options = devpts_show_options,
|
.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;
|
struct pts_fs_info *fsi;
|
||||||
|
|
||||||
|
@ -369,6 +370,7 @@ static void *new_pts_fs_info(void)
|
||||||
ida_init(&fsi->allocated_ptys);
|
ida_init(&fsi->allocated_ptys);
|
||||||
fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
|
fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
|
||||||
fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
|
fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
|
||||||
|
fsi->sb = sb;
|
||||||
|
|
||||||
return fsi;
|
return fsi;
|
||||||
}
|
}
|
||||||
|
@ -384,7 +386,7 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
|
||||||
s->s_op = &devpts_sops;
|
s->s_op = &devpts_sops;
|
||||||
s->s_time_gran = 1;
|
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)
|
if (!s->s_fs_info)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
@ -524,17 +526,14 @@ static struct file_system_type devpts_fs_type = {
|
||||||
* to the System V naming convention
|
* 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 index;
|
||||||
int ida_ret;
|
int ida_ret;
|
||||||
|
|
||||||
if (!sb)
|
if (!fsi)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
fsi = DEVPTS_SB(sb);
|
|
||||||
retry:
|
retry:
|
||||||
if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
|
if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -564,11 +563,8 @@ retry:
|
||||||
return index;
|
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);
|
mutex_lock(&allocated_ptys_lock);
|
||||||
ida_remove(&fsi->allocated_ptys, idx);
|
ida_remove(&fsi->allocated_ptys, idx);
|
||||||
pty_count--;
|
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
|
* pty code needs to hold extra references in case of last /dev/tty close
|
||||||
*/
|
*/
|
||||||
|
struct pts_fs_info *devpts_get_ref(struct inode *ptmx_inode, struct file *file)
|
||||||
void devpts_add_ref(struct inode *ptmx_inode)
|
|
||||||
{
|
{
|
||||||
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);
|
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);
|
deactivate_super(fsi->sb);
|
||||||
|
|
||||||
iput(ptmx_inode);
|
|
||||||
deactivate_super(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.
|
* 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)
|
void *priv)
|
||||||
{
|
{
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct super_block *sb = pts_sb_from_inode(ptmx_inode);
|
struct super_block *sb;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct dentry *root;
|
struct dentry *root;
|
||||||
struct pts_fs_info *fsi;
|
|
||||||
struct pts_mount_opts *opts;
|
struct pts_mount_opts *opts;
|
||||||
char s[12];
|
char s[12];
|
||||||
|
|
||||||
if (!sb)
|
if (!fsi)
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
|
sb = fsi->sb;
|
||||||
root = sb->s_root;
|
root = sb->s_root;
|
||||||
fsi = DEVPTS_SB(sb);
|
|
||||||
opts = &fsi->mount_opts;
|
opts = &fsi->mount_opts;
|
||||||
|
|
||||||
inode = new_inode(sb);
|
inode = new_inode(sb);
|
||||||
|
|
|
@ -15,38 +15,24 @@
|
||||||
|
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
|
||||||
|
struct pts_fs_info;
|
||||||
|
|
||||||
#ifdef CONFIG_UNIX98_PTYS
|
#ifdef CONFIG_UNIX98_PTYS
|
||||||
|
|
||||||
int devpts_new_index(struct inode *ptmx_inode);
|
/* Look up a pts fs info and get a ref to it */
|
||||||
void devpts_kill_index(struct inode *ptmx_inode, int idx);
|
struct pts_fs_info *devpts_get_ref(struct inode *, struct file *);
|
||||||
void devpts_add_ref(struct inode *ptmx_inode);
|
void devpts_put_ref(struct pts_fs_info *);
|
||||||
void devpts_del_ref(struct inode *ptmx_inode);
|
|
||||||
|
int devpts_new_index(struct pts_fs_info *);
|
||||||
|
void devpts_kill_index(struct pts_fs_info *, int);
|
||||||
|
|
||||||
/* mknod in devpts */
|
/* mknod in devpts */
|
||||||
struct inode *devpts_pty_new(struct inode *ptmx_inode, dev_t device, int index,
|
struct inode *devpts_pty_new(struct pts_fs_info *, dev_t, int, void *);
|
||||||
void *priv);
|
|
||||||
/* get private structure */
|
/* get private structure */
|
||||||
void *devpts_get_priv(struct inode *pts_inode);
|
void *devpts_get_priv(struct inode *pts_inode);
|
||||||
/* unlink */
|
/* unlink */
|
||||||
void devpts_pty_kill(struct inode *inode);
|
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
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче