Two kinds of objects there - ptmx and everything else (pty).  The former is
created on mount and kept until the fs shutdown; the latter get created
and removed by tty layer (the references are borrowed into tty->driver_data).
The reference to ptmx dentry is also kept, but we only ever use it to
find ptmx inode on remount.

* turn d_add() into d_make_persistent() + dput()  both in mknod_ptmx() and
in devpts_pty_new().

* turn dput() to d_make_discardable() in devpts_pty_kill().

* switch mknod_ptmx() to simple_{start,done}_creating().

* instead of storing a reference to ptmx dentry pts_fs_info, store a reference
to its inode, seeing that this is what we use it for.

Signed-off-by: Al Viro <v...@zeniv.linux.org.uk>
---
 fs/devpts/inode.c | 57 +++++++++++++++++------------------------------
 1 file changed, 21 insertions(+), 36 deletions(-)

diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index fdf22264a8e9..9f3de528c358 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -102,7 +102,7 @@ struct pts_fs_info {
        struct ida allocated_ptys;
        struct pts_mount_opts mount_opts;
        struct super_block *sb;
-       struct dentry *ptmx_dentry;
+       struct inode *ptmx_inode; // borrowed
 };
 
 static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb)
@@ -259,7 +259,6 @@ static int devpts_parse_param(struct fs_context *fc, struct 
fs_parameter *param)
 static int mknod_ptmx(struct super_block *sb, struct fs_context *fc)
 {
        int mode;
-       int rc = -ENOMEM;
        struct dentry *dentry;
        struct inode *inode;
        struct dentry *root = sb->s_root;
@@ -268,18 +267,10 @@ static int mknod_ptmx(struct super_block *sb, struct 
fs_context *fc)
        kuid_t ptmx_uid = current_fsuid();
        kgid_t ptmx_gid = current_fsgid();
 
-       inode_lock(d_inode(root));
-
-       /* If we have already created ptmx node, return */
-       if (fsi->ptmx_dentry) {
-               rc = 0;
-               goto out;
-       }
-
-       dentry = d_alloc_name(root, "ptmx");
-       if (!dentry) {
+       dentry = simple_start_creating(root, "ptmx");
+       if (IS_ERR(dentry)) {
                pr_err("Unable to alloc dentry for ptmx node\n");
-               goto out;
+               return PTR_ERR(dentry);
        }
 
        /*
@@ -287,9 +278,9 @@ static int mknod_ptmx(struct super_block *sb, struct 
fs_context *fc)
         */
        inode = new_inode(sb);
        if (!inode) {
+               simple_done_creating(dentry);
                pr_err("Unable to alloc inode for ptmx node\n");
-               dput(dentry);
-               goto out;
+               return -ENOMEM;
        }
 
        inode->i_ino = 2;
@@ -299,23 +290,18 @@ static int mknod_ptmx(struct super_block *sb, struct 
fs_context *fc)
        init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2));
        inode->i_uid = ptmx_uid;
        inode->i_gid = ptmx_gid;
+       fsi->ptmx_inode = inode;
 
-       d_add(dentry, inode);
+       d_make_persistent(dentry, inode);
 
-       fsi->ptmx_dentry = dentry;
-       rc = 0;
-out:
-       inode_unlock(d_inode(root));
-       return rc;
+       simple_done_creating(dentry);
+
+       return 0;
 }
 
 static void update_ptmx_mode(struct pts_fs_info *fsi)
 {
-       struct inode *inode;
-       if (fsi->ptmx_dentry) {
-               inode = d_inode(fsi->ptmx_dentry);
-               inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode;
-       }
+       fsi->ptmx_inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode;
 }
 
 static int devpts_reconfigure(struct fs_context *fc)
@@ -461,7 +447,7 @@ static void devpts_kill_sb(struct super_block *sb)
        if (fsi)
                ida_destroy(&fsi->allocated_ptys);
        kfree(fsi);
-       kill_litter_super(sb);
+       kill_anon_super(sb);
 }
 
 static struct file_system_type devpts_fs_type = {
@@ -534,16 +520,15 @@ struct dentry *devpts_pty_new(struct pts_fs_info *fsi, 
int index, void *priv)
        sprintf(s, "%d", index);
 
        dentry = d_alloc_name(root, s);
-       if (dentry) {
-               dentry->d_fsdata = priv;
-               d_add(dentry, inode);
-               fsnotify_create(d_inode(root), dentry);
-       } else {
+       if (!dentry) {
                iput(inode);
-               dentry = ERR_PTR(-ENOMEM);
+               return ERR_PTR(-ENOMEM);
        }
-
-       return dentry;
+       dentry->d_fsdata = priv;
+       d_make_persistent(dentry, inode);
+       fsnotify_create(d_inode(root), dentry);
+       dput(dentry);
+       return dentry; // borrowed
 }
 
 /**
@@ -573,7 +558,7 @@ void devpts_pty_kill(struct dentry *dentry)
        drop_nlink(dentry->d_inode);
        d_drop(dentry);
        fsnotify_unlink(d_inode(dentry->d_parent), dentry);
-       dput(dentry);   /* d_alloc_name() in devpts_pty_new() */
+       d_make_discardable(dentry);
 }
 
 static int __init init_devpts_fs(void)
-- 
2.47.3


Reply via email to