]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
libfs: improve path_from_stashed()
authorChristian Brauner <brauner@kernel.org>
Fri, 1 Mar 2024 09:26:03 +0000 (10:26 +0100)
committerChristian Brauner <brauner@kernel.org>
Fri, 1 Mar 2024 21:31:40 +0000 (22:31 +0100)
Right now we pass a bunch of info that is fs specific which doesn't make
a lot of sense and it bleeds fs sepcific details into the generic
helper. nsfs and pidfs have slightly different needs when initializing
inodes. Add simple operations that are stashed in sb->s_fs_info that
both can implement. This also allows us to get rid of cleaning up
references in the caller. All in all path_from_stashed() becomes way
simpler.

Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/internal.h
fs/libfs.c
fs/nsfs.c
fs/pidfs.c

index b0c843c3fa3c4eae13531ecfea64dc2606fbf11b..7d3edcdf59cc159e54e804b5751beb738cf7d6e6 100644 (file)
@@ -310,8 +310,10 @@ ssize_t __kernel_write_iter(struct file *file, struct iov_iter *from, loff_t *po
 struct mnt_idmap *alloc_mnt_idmap(struct user_namespace *mnt_userns);
 struct mnt_idmap *mnt_idmap_get(struct mnt_idmap *idmap);
 void mnt_idmap_put(struct mnt_idmap *idmap);
+struct stashed_operations {
+       void (*put_data)(void *data);
+       void (*init_inode)(struct inode *inode, void *data);
+};
 int path_from_stashed(struct dentry **stashed, unsigned long ino,
-                     struct vfsmount *mnt, const struct file_operations *fops,
-                     const struct inode_operations *iops, void *data,
-                     struct path *path);
+                     struct vfsmount *mnt, void *data, struct path *path);
 void stashed_dentry_prune(struct dentry *dentry);
index 472f21bd032549c5531ed8054f49aac5648f223b..65322e11bcdae27c7a52dd20b96072eb799e68fe 100644 (file)
@@ -1991,12 +1991,11 @@ static inline struct dentry *get_stashed_dentry(struct dentry *stashed)
 static struct dentry *prepare_anon_dentry(struct dentry **stashed,
                                          unsigned long ino,
                                          struct super_block *sb,
-                                         const struct file_operations *fops,
-                                         const struct inode_operations *iops,
                                          void *data)
 {
        struct dentry *dentry;
        struct inode *inode;
+       const struct stashed_operations *sops = sb->s_fs_info;
 
        dentry = d_alloc_anon(sb);
        if (!dentry)
@@ -2010,15 +2009,13 @@ static struct dentry *prepare_anon_dentry(struct dentry **stashed,
 
        inode->i_ino = ino;
        inode->i_flags |= S_IMMUTABLE;
-       if (is_pidfs_sb(sb))
-               inode->i_flags |= S_PRIVATE;
-       inode->i_mode = S_IFREG | S_IRUGO;
-       if (iops)
-               inode->i_op = iops;
-       if (fops)
-               inode->i_fop = fops;
-       inode->i_private = data;
+       inode->i_mode = S_IFREG;
        simple_inode_init_ts(inode);
+       sops->init_inode(inode, data);
+
+       /* Notice when this is changed. */
+       WARN_ON_ONCE(!S_ISREG(inode->i_mode));
+       WARN_ON_ONCE(!IS_IMMUTABLE(inode));
 
        /* Store address of location where dentry's supposed to be stashed. */
        dentry->d_fsdata = stashed;
@@ -2055,8 +2052,6 @@ static struct dentry *stash_dentry(struct dentry **stashed,
  * @stashed:    where to retrieve or stash dentry
  * @ino:        inode number to use
  * @mnt:        mnt of the filesystems to use
- * @iops:       inode operations to use
- * @fops:       file operations to use
  * @data:       data to store in inode->i_private
  * @path:       path to create
  *
@@ -2068,38 +2063,38 @@ static struct dentry *stash_dentry(struct dentry **stashed,
  *
  * Special-purpose helper for nsfs and pidfs.
  *
- * Return: If 0 or an error is returned the caller can be sure that @data must
- *         be cleaned up. If 1 is returned @data is owned by the filesystem.
+ * Return: On success zero and on failure a negative error is returned.
  */
 int path_from_stashed(struct dentry **stashed, unsigned long ino,
-                     struct vfsmount *mnt, const struct file_operations *fops,
-                     const struct inode_operations *iops, void *data,
-                     struct path *path)
+                     struct vfsmount *mnt, void *data, struct path *path)
 {
        struct dentry *dentry;
-       int ret = 0;
+       const struct stashed_operations *sops = mnt->mnt_sb->s_fs_info;
 
        /* See if dentry can be reused. */
        path->dentry = get_stashed_dentry(*stashed);
-       if (path->dentry)
+       if (path->dentry) {
+               sops->put_data(data);
                goto out_path;
+       }
 
        /* Allocate a new dentry. */
-       dentry = prepare_anon_dentry(stashed, ino, mnt->mnt_sb, fops, iops, data);
-       if (IS_ERR(dentry))
+       dentry = prepare_anon_dentry(stashed, ino, mnt->mnt_sb, data);
+       if (IS_ERR(dentry)) {
+               sops->put_data(data);
                return PTR_ERR(dentry);
+       }
 
        /* Added a new dentry. @data is now owned by the filesystem. */
        path->dentry = stash_dentry(stashed, dentry);
        if (path->dentry != dentry)
                dput(dentry);
-       ret = 1;
 
 out_path:
        WARN_ON_ONCE(path->dentry->d_fsdata != stashed);
        WARN_ON_ONCE(d_inode(path->dentry)->i_private != data);
        path->mnt = mntget(mnt);
-       return ret;
+       return 0;
 }
 
 void stashed_dentry_prune(struct dentry *dentry)
index 2ce229af34e97ce79d50da0fb671cd599568f06c..7aaafb5cb9fc9f7792c7d7198b49f561ee14be0b 100644 (file)
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -50,19 +50,13 @@ static void nsfs_evict(struct inode *inode)
 int ns_get_path_cb(struct path *path, ns_get_path_helper_t *ns_get_cb,
                     void *private_data)
 {
-       int ret;
        struct ns_common *ns;
 
        ns = ns_get_cb(private_data);
        if (!ns)
                return -ENOENT;
-       ret = path_from_stashed(&ns->stashed, ns->inum, nsfs_mnt,
-                               &ns_file_operations, NULL, ns, path);
-       if (ret <= 0)
-               ns->ops->put(ns);
-       if (ret < 0)
-               return ret;
-       return 0;
+
+       return path_from_stashed(&ns->stashed, ns->inum, nsfs_mnt, ns, path);
 }
 
 struct ns_get_path_task_args {
@@ -108,9 +102,7 @@ int open_related_ns(struct ns_common *ns,
        }
 
        err = path_from_stashed(&relative->stashed, relative->inum, nsfs_mnt,
-                               &ns_file_operations, NULL, relative, &path);
-       if (err <= 0)
-               relative->ops->put(relative);
+                               relative, &path);
        if (err < 0) {
                put_unused_fd(fd);
                return err;
@@ -207,6 +199,24 @@ static const struct super_operations nsfs_ops = {
        .show_path = nsfs_show_path,
 };
 
+static void nsfs_init_inode(struct inode *inode, void *data)
+{
+       inode->i_private = data;
+       inode->i_mode |= S_IRUGO;
+       inode->i_fop = &ns_file_operations;
+}
+
+static void nsfs_put_data(void *data)
+{
+       struct ns_common *ns = data;
+       ns->ops->put(ns);
+}
+
+static const struct stashed_operations nsfs_stashed_ops = {
+       .init_inode = nsfs_init_inode,
+       .put_data = nsfs_put_data,
+};
+
 static int nsfs_init_fs_context(struct fs_context *fc)
 {
        struct pseudo_fs_context *ctx = init_pseudo(fc, NSFS_MAGIC);
@@ -214,6 +224,7 @@ static int nsfs_init_fs_context(struct fs_context *fc)
                return -ENOMEM;
        ctx->ops = &nsfs_ops;
        ctx->dops = &ns_dentry_operations;
+       fc->s_fs_info = (void *)&nsfs_stashed_ops;
        return 0;
 }
 
index d38b7a18499420940c32612d47a2974bf34a0c5b..8fd71a00be9c0cbfca51b2e717db2293710e6ac4 100644 (file)
@@ -193,6 +193,26 @@ static const struct dentry_operations pidfs_dentry_operations = {
        .d_prune        = stashed_dentry_prune,
 };
 
+static void pidfs_init_inode(struct inode *inode, void *data)
+{
+       inode->i_private = data;
+       inode->i_flags |= S_PRIVATE;
+       inode->i_mode |= S_IRWXU;
+       inode->i_op = &pidfs_inode_operations;
+       inode->i_fop = &pidfs_file_operations;
+}
+
+static void pidfs_put_data(void *data)
+{
+       struct pid *pid = data;
+       put_pid(pid);
+}
+
+static const struct stashed_operations pidfs_stashed_ops = {
+       .init_inode = pidfs_init_inode,
+       .put_data = pidfs_put_data,
+};
+
 static int pidfs_init_fs_context(struct fs_context *fc)
 {
        struct pseudo_fs_context *ctx;
@@ -203,6 +223,7 @@ static int pidfs_init_fs_context(struct fs_context *fc)
 
        ctx->ops = &pidfs_sops;
        ctx->dops = &pidfs_dentry_operations;
+       fc->s_fs_info = (void *)&pidfs_stashed_ops;
        return 0;
 }
 
@@ -225,10 +246,7 @@ struct file *pidfs_alloc_file(struct pid *pid, unsigned int flags)
        * for pseudo filesystems.
         */
        ret = path_from_stashed(&pid->stashed, pid->ino, pidfs_mnt,
-                               &pidfs_file_operations, &pidfs_inode_operations,
                                get_pid(pid), &path);
-       if (ret <= 0)
-               put_pid(pid);
        if (ret < 0)
                return ERR_PTR(ret);