diff options
-rw-r--r-- | fs/internal.h | 8 | ||||
-rw-r--r-- | fs/libfs.c | 41 | ||||
-rw-r--r-- | fs/nsfs.c | 33 | ||||
-rw-r--r-- | fs/pidfs.c | 24 |
4 files changed, 66 insertions, 40 deletions
diff --git a/fs/internal.h b/fs/internal.h index b0c843c3fa3c..7d3edcdf59cc 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -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); diff --git a/fs/libfs.c b/fs/libfs.c index 472f21bd0325..65322e11bcda 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -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) diff --git a/fs/nsfs.c b/fs/nsfs.c index 2ce229af34e9..7aaafb5cb9fc 100644 --- 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; } diff --git a/fs/pidfs.c b/fs/pidfs.c index d38b7a184994..8fd71a00be9c 100644 --- a/fs/pidfs.c +++ b/fs/pidfs.c @@ -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); |