kernfs: don't set dentry->d_fsdata
authorShaohua Li <shli@fb.com>
Wed, 12 Jul 2017 18:49:49 +0000 (11:49 -0700)
committerJens Axboe <axboe@kernel.dk>
Sat, 29 Jul 2017 15:00:03 +0000 (09:00 -0600)
When working on adding exportfs operations in kernfs, I found it's hard
to initialize dentry->d_fsdata in the exportfs operations. Looks there
is no way to do it without race condition. Look at the kernfs code
closely, there is no point to set dentry->d_fsdata. inode->i_private
already points to kernfs_node, and we can get inode from a dentry. So
this patch just delete the d_fsdata usage.

Acked-by: Tejun Heo <tj@kernel.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Shaohua Li <shli@fb.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/kernfs/dir.c
fs/kernfs/file.c
fs/kernfs/inode.c
fs/kernfs/kernfs-internal.h
fs/kernfs/mount.c
fs/kernfs/symlink.c

index 7be37c8380079368420e6710adf3c8b096a4f066..b61a7efceb7aeddb38cb7faa0f4ae0c97af7b79f 100644 (file)
@@ -566,7 +566,7 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
        if (d_really_is_negative(dentry))
                goto out_bad_unlocked;
 
-       kn = dentry->d_fsdata;
+       kn = kernfs_dentry_node(dentry);
        mutex_lock(&kernfs_mutex);
 
        /* The kernfs node has been deactivated */
@@ -574,7 +574,7 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
                goto out_bad;
 
        /* The kernfs node has been moved? */
-       if (dentry->d_parent->d_fsdata != kn->parent)
+       if (kernfs_dentry_node(dentry->d_parent) != kn->parent)
                goto out_bad;
 
        /* The kernfs node has been renamed */
@@ -594,14 +594,8 @@ out_bad_unlocked:
        return 0;
 }
 
-static void kernfs_dop_release(struct dentry *dentry)
-{
-       kernfs_put(dentry->d_fsdata);
-}
-
 const struct dentry_operations kernfs_dops = {
        .d_revalidate   = kernfs_dop_revalidate,
-       .d_release      = kernfs_dop_release,
 };
 
 /**
@@ -617,8 +611,9 @@ const struct dentry_operations kernfs_dops = {
  */
 struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry)
 {
-       if (dentry->d_sb->s_op == &kernfs_sops)
-               return dentry->d_fsdata;
+       if (dentry->d_sb->s_op == &kernfs_sops &&
+           !d_really_is_negative(dentry))
+               return kernfs_dentry_node(dentry);
        return NULL;
 }
 
@@ -1056,7 +1051,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
                                        unsigned int flags)
 {
        struct dentry *ret;
-       struct kernfs_node *parent = dentry->d_parent->d_fsdata;
+       struct kernfs_node *parent = dir->i_private;
        struct kernfs_node *kn;
        struct inode *inode;
        const void *ns = NULL;
@@ -1073,8 +1068,6 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
                ret = NULL;
                goto out_unlock;
        }
-       kernfs_get(kn);
-       dentry->d_fsdata = kn;
 
        /* attach dentry and inode */
        inode = kernfs_get_inode(dir->i_sb, kn);
@@ -1111,7 +1104,7 @@ static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry,
 
 static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       struct kernfs_node *kn  = dentry->d_fsdata;
+       struct kernfs_node *kn  = kernfs_dentry_node(dentry);
        struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops;
        int ret;
 
@@ -1131,7 +1124,7 @@ static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
                             struct inode *new_dir, struct dentry *new_dentry,
                             unsigned int flags)
 {
-       struct kernfs_node *kn  = old_dentry->d_fsdata;
+       struct kernfs_node *kn = kernfs_dentry_node(old_dentry);
        struct kernfs_node *new_parent = new_dir->i_private;
        struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops;
        int ret;
@@ -1644,7 +1637,7 @@ static struct kernfs_node *kernfs_dir_next_pos(const void *ns,
 static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
 {
        struct dentry *dentry = file->f_path.dentry;
-       struct kernfs_node *parent = dentry->d_fsdata;
+       struct kernfs_node *parent = kernfs_dentry_node(dentry);
        struct kernfs_node *pos = file->private_data;
        const void *ns = NULL;
 
index ac2dfe0c5a9c8520aa8b40c4bab97b710799cc78..7f90d4de86b628ac15736330c1548a94ce488435 100644 (file)
@@ -616,7 +616,7 @@ static void kernfs_put_open_node(struct kernfs_node *kn,
 
 static int kernfs_fop_open(struct inode *inode, struct file *file)
 {
-       struct kernfs_node *kn = file->f_path.dentry->d_fsdata;
+       struct kernfs_node *kn = inode->i_private;
        struct kernfs_root *root = kernfs_root(kn);
        const struct kernfs_ops *ops;
        struct kernfs_open_file *of;
@@ -768,7 +768,7 @@ static void kernfs_release_file(struct kernfs_node *kn,
 
 static int kernfs_fop_release(struct inode *inode, struct file *filp)
 {
-       struct kernfs_node *kn = filp->f_path.dentry->d_fsdata;
+       struct kernfs_node *kn = inode->i_private;
        struct kernfs_open_file *of = kernfs_of(filp);
 
        if (kn->flags & KERNFS_HAS_RELEASE) {
@@ -835,7 +835,7 @@ void kernfs_drain_open_files(struct kernfs_node *kn)
 static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait)
 {
        struct kernfs_open_file *of = kernfs_of(filp);
-       struct kernfs_node *kn = filp->f_path.dentry->d_fsdata;
+       struct kernfs_node *kn = kernfs_dentry_node(filp->f_path.dentry);
        struct kernfs_open_node *on = kn->attr.open;
 
        if (!kernfs_get_active(kn))
index 79cdae4758fb357bd933e7043b8480a0c5aa0740..4c8b51085a865727521b634e71171266b769e47e 100644 (file)
@@ -112,7 +112,7 @@ int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
 int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr)
 {
        struct inode *inode = d_inode(dentry);
-       struct kernfs_node *kn = dentry->d_fsdata;
+       struct kernfs_node *kn = inode->i_private;
        int error;
 
        if (!kn)
@@ -154,7 +154,7 @@ static int kernfs_node_setsecdata(struct kernfs_iattrs *attrs, void **secdata,
 
 ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
 {
-       struct kernfs_node *kn = dentry->d_fsdata;
+       struct kernfs_node *kn = kernfs_dentry_node(dentry);
        struct kernfs_iattrs *attrs;
 
        attrs = kernfs_iattrs(kn);
@@ -203,8 +203,8 @@ static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode)
 int kernfs_iop_getattr(const struct path *path, struct kstat *stat,
                       u32 request_mask, unsigned int query_flags)
 {
-       struct kernfs_node *kn = path->dentry->d_fsdata;
        struct inode *inode = d_inode(path->dentry);
+       struct kernfs_node *kn = inode->i_private;
 
        mutex_lock(&kernfs_mutex);
        kernfs_refresh_inode(kn, inode);
index e9c226f29828e8bb1e1469a55f080f11ab851feb..0f260dcca1770427e7f292fe8ac1d2abc410e029 100644 (file)
@@ -70,6 +70,13 @@ struct kernfs_super_info {
 };
 #define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info))
 
+static inline struct kernfs_node *kernfs_dentry_node(struct dentry *dentry)
+{
+       if (d_really_is_negative(dentry))
+               return NULL;
+       return d_inode(dentry)->i_private;
+}
+
 extern const struct super_operations kernfs_sops;
 extern struct kmem_cache *kernfs_node_cache;
 
index 69c48bec8a632b98ba0041aec5d489a7a2b332f8..acd542625fd8a645772f7a91dedf3e4fa0e62d4f 100644 (file)
@@ -33,7 +33,7 @@ static int kernfs_sop_remount_fs(struct super_block *sb, int *flags, char *data)
 
 static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry)
 {
-       struct kernfs_root *root = kernfs_root(dentry->d_fsdata);
+       struct kernfs_root *root = kernfs_root(kernfs_dentry_node(dentry));
        struct kernfs_syscall_ops *scops = root->syscall_ops;
 
        if (scops && scops->show_options)
@@ -43,7 +43,7 @@ static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry)
 
 static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry)
 {
-       struct kernfs_node *node = dentry->d_fsdata;
+       struct kernfs_node *node = kernfs_dentry_node(dentry);
        struct kernfs_root *root = kernfs_root(node);
        struct kernfs_syscall_ops *scops = root->syscall_ops;
 
@@ -176,8 +176,6 @@ static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
                pr_debug("%s: could not get root dentry!\n", __func__);
                return -ENOMEM;
        }
-       kernfs_get(info->root->kn);
-       root->d_fsdata = info->root->kn;
        sb->s_root = root;
        sb->s_d_op = &kernfs_dops;
        return 0;
@@ -283,7 +281,6 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
 void kernfs_kill_sb(struct super_block *sb)
 {
        struct kernfs_super_info *info = kernfs_info(sb);
-       struct kernfs_node *root_kn = sb->s_root->d_fsdata;
 
        mutex_lock(&kernfs_mutex);
        list_del(&info->node);
@@ -295,7 +292,6 @@ void kernfs_kill_sb(struct super_block *sb)
         */
        kill_anon_super(sb);
        kfree(info);
-       kernfs_put(root_kn);
 }
 
 /**
index 1684af4a8b9b4eaf752dfffc063b3a2cc622d472..08ccabd7047f390151b8ab31f72baa21efeefb6f 100644 (file)
@@ -98,9 +98,9 @@ static int kernfs_get_target_path(struct kernfs_node *parent,
        return 0;
 }
 
-static int kernfs_getlink(struct dentry *dentry, char *path)
+static int kernfs_getlink(struct inode *inode, char *path)
 {
-       struct kernfs_node *kn = dentry->d_fsdata;
+       struct kernfs_node *kn = inode->i_private;
        struct kernfs_node *parent = kn->parent;
        struct kernfs_node *target = kn->symlink.target_kn;
        int error;
@@ -124,7 +124,7 @@ static const char *kernfs_iop_get_link(struct dentry *dentry,
        body = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (!body)
                return ERR_PTR(-ENOMEM);
-       error = kernfs_getlink(dentry, body);
+       error = kernfs_getlink(inode, body);
        if (unlikely(error < 0)) {
                kfree(body);
                return ERR_PTR(error);