Re: [PATCH v3 7/9] vfs: move open right after ->tmpfile()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Sep 20, 2022 at 09:36:30PM +0200, Miklos Szeredi wrote:
> Create a helper finish_open_simple() that opens the file with the original
> dentry.  Handle the error case here as well to simplify callers.
> 
> Call this helper right after ->tmpfile() is called.
> 
> Next patch will change the tmpfile API and move this call into tmpfile
> instances.
> 
> Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxxxxx>
> ---
>  fs/namei.c         | 79 ++++++++++++++++++----------------------------
>  include/linux/fs.h |  9 ++++++
>  2 files changed, 40 insertions(+), 48 deletions(-)
> 
> diff --git a/fs/namei.c b/fs/namei.c
> index 652d09ae66fb..4faf7e743664 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -3583,44 +3583,43 @@ static int do_open(struct nameidata *nd,
>   * On non-idmapped mounts or if permission checking is to be performed on the
>   * raw inode simply passs init_user_ns.
>   */
> -static struct dentry *vfs_tmpfile(struct user_namespace *mnt_userns,
> -			   struct dentry *dentry, umode_t mode, int open_flag)
> +static int vfs_tmpfile(struct user_namespace *mnt_userns,
> +		       const struct path *parentpath,
> +		       struct file *file, umode_t mode)
>  {
> -	struct dentry *child = NULL;
> -	struct inode *dir = dentry->d_inode;
> +	struct dentry *child;
> +	struct inode *dir = d_inode(parentpath->dentry);
>  	struct inode *inode;
>  	int error;
>  
>  	/* we want directory to be writable */
>  	error = inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC);
>  	if (error)
> -		goto out_err;
> -	error = -EOPNOTSUPP;
> +		return error;
>  	if (!dir->i_op->tmpfile)
> -		goto out_err;
> -	error = -ENOMEM;
> -	child = d_alloc(dentry, &slash_name);
> +		return -EOPNOTSUPP;
> +	child = d_alloc(parentpath->dentry, &slash_name);
>  	if (unlikely(!child))
> -		goto out_err;
> +		return -ENOMEM;
> +	file->f_path.mnt = parentpath->mnt;
> +	file->f_path.dentry = child;
>  	mode = vfs_prepare_mode(mnt_userns, dir, mode, mode, mode);
>  	error = dir->i_op->tmpfile(mnt_userns, dir, child, mode);
> +	error = finish_open_simple(file, error);
> +	dput(child);
>  	if (error)
> -		goto out_err;
> -	error = -ENOENT;
> +		return error;
> +	error = may_open(mnt_userns, &file->f_path, 0, file->f_flags);
> +	if (error)
> +		return error;
>  	inode = child->d_inode;
> -	if (unlikely(!inode))
> -		goto out_err;
> -	if (!(open_flag & O_EXCL)) {
> +	if (!(file->f_flags & O_EXCL)) {
>  		spin_lock(&inode->i_lock);
>  		inode->i_state |= I_LINKABLE;
>  		spin_unlock(&inode->i_lock);
>  	}
>  	ima_post_create_tmpfile(mnt_userns, inode);
> -	return child;
> -
> -out_err:
> -	dput(child);
> -	return ERR_PTR(error);
> +	return 0;
>  }
>  
>  /**
> @@ -3641,25 +3640,15 @@ struct file *tmpfile_open(struct user_namespace *mnt_userns,
>  {
>  	struct file *file;
>  	int error;
> -	struct path path = { .mnt = parentpath->mnt };
> -
> -	path.dentry = vfs_tmpfile(mnt_userns, parentpath->dentry, mode, open_flag);
> -	if (IS_ERR(path.dentry))
> -		return ERR_CAST(path.dentry);
> -
> -	error = may_open(mnt_userns, &path, 0, open_flag);
> -	file = ERR_PTR(error);
> -	if (error)
> -		goto out_dput;
> -
> -	/*
> -	 * This relies on the "noaccount" property of fake open, otherwise
> -	 * equivalent to dentry_open().
> -	 */
> -	file = open_with_fake_path(&path, open_flag, d_inode(path.dentry), cred);
> -out_dput:
> -	dput(path.dentry);
>  
> +	file = alloc_empty_file_noaccount(open_flag, cred);
> +	if (!IS_ERR(file)) {
> +		error = vfs_tmpfile(mnt_userns, parentpath, file, mode);
> +		if (error) {
> +			fput(file);
> +			file = ERR_PTR(error);
> +		}
> +	}
>  	return file;
>  }
>  EXPORT_SYMBOL(tmpfile_open);
> @@ -3669,26 +3658,20 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
>  		struct file *file)
>  {
>  	struct user_namespace *mnt_userns;
> -	struct dentry *child;
>  	struct path path;
>  	int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path);
> +
>  	if (unlikely(error))
>  		return error;
>  	error = mnt_want_write(path.mnt);
>  	if (unlikely(error))
>  		goto out;
>  	mnt_userns = mnt_user_ns(path.mnt);
> -	child = vfs_tmpfile(mnt_userns, path.dentry, op->mode, op->open_flag);
> -	error = PTR_ERR(child);
> -	if (IS_ERR(child))
> +	error = vfs_tmpfile(mnt_userns, &path, file, op->mode);
> +	if (error)
>  		goto out2;
> -	dput(path.dentry);
> -	path.dentry = child;
> -	audit_inode(nd->name, child, 0);
> +	audit_inode(nd->name, file->f_path.dentry, 0);
>  	/* Don't check for other permissions, the inode was just created */
> -	error = may_open(mnt_userns, &path, 0, op->open_flag);
> -	if (!error)
> -		error = vfs_open(&path, file);
>  out2:
>  	mnt_drop_write(path.mnt);
>  out:
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index a445da4842e0..f0d17eefb966 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -2780,6 +2780,15 @@ extern int finish_open(struct file *file, struct dentry *dentry,
>  			int (*open)(struct inode *, struct file *));
>  extern int finish_no_open(struct file *file, struct dentry *dentry);
>  
> +/* Helper for the simple case when original dentry is used */
> +static inline int finish_open_simple(struct file *file, int error)

It would be nice if the new helpers would would be called
vfs_finish_open()/vfs_finish_open_simple() and vfs_tmpfile_open() to
stick with our vfs_* prefix convention.

It is extremely helpful when looking/grepping for helpers and the
consistency we have gained there in recent years is pretty good.



[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux