Commit 9751b338 authored by Miklos Szeredi's avatar Miklos Szeredi

vfs: move open right after ->tmpfile()

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: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent 3e9d4c59
...@@ -3583,44 +3583,44 @@ static int do_open(struct nameidata *nd, ...@@ -3583,44 +3583,44 @@ static int do_open(struct nameidata *nd,
* On non-idmapped mounts or if permission checking is to be performed on the * On non-idmapped mounts or if permission checking is to be performed on the
* raw inode simply passs init_user_ns. * raw inode simply passs init_user_ns.
*/ */
static struct dentry *vfs_tmpfile(struct user_namespace *mnt_userns, static int vfs_tmpfile(struct user_namespace *mnt_userns,
struct dentry *dentry, umode_t mode, int open_flag) const struct path *parentpath,
struct file *file, umode_t mode)
{ {
struct dentry *child = NULL; struct dentry *child;
struct inode *dir = dentry->d_inode; struct inode *dir = d_inode(parentpath->dentry);
struct inode *inode; struct inode *inode;
int error; int error;
/* we want directory to be writable */ /* we want directory to be writable */
error = inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC); error = inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC);
if (error) if (error)
goto out_err; return error;
error = -EOPNOTSUPP;
if (!dir->i_op->tmpfile) if (!dir->i_op->tmpfile)
goto out_err; return -EOPNOTSUPP;
error = -ENOMEM; child = d_alloc(parentpath->dentry, &slash_name);
child = d_alloc(dentry, &slash_name);
if (unlikely(!child)) 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); mode = vfs_prepare_mode(mnt_userns, dir, mode, mode, mode);
error = dir->i_op->tmpfile(mnt_userns, dir, child, mode); error = dir->i_op->tmpfile(mnt_userns, dir, child, mode);
error = finish_open_simple(file, error);
dput(child);
if (error) if (error)
goto out_err; return error;
error = -ENOENT; /* Don't check for other permissions, the inode was just created */
inode = child->d_inode; error = may_open(mnt_userns, &file->f_path, 0, file->f_flags);
if (unlikely(!inode)) if (error)
goto out_err; return error;
if (!(open_flag & O_EXCL)) { inode = file_inode(file);
if (!(file->f_flags & O_EXCL)) {
spin_lock(&inode->i_lock); spin_lock(&inode->i_lock);
inode->i_state |= I_LINKABLE; inode->i_state |= I_LINKABLE;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} }
ima_post_create_tmpfile(mnt_userns, inode); ima_post_create_tmpfile(mnt_userns, inode);
return child; return 0;
out_err:
dput(child);
return ERR_PTR(error);
} }
/** /**
...@@ -3641,25 +3641,15 @@ struct file *vfs_tmpfile_open(struct user_namespace *mnt_userns, ...@@ -3641,25 +3641,15 @@ struct file *vfs_tmpfile_open(struct user_namespace *mnt_userns,
{ {
struct file *file; struct file *file;
int error; 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; return file;
} }
EXPORT_SYMBOL(vfs_tmpfile_open); EXPORT_SYMBOL(vfs_tmpfile_open);
...@@ -3669,26 +3659,19 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags, ...@@ -3669,26 +3659,19 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
struct file *file) struct file *file)
{ {
struct user_namespace *mnt_userns; struct user_namespace *mnt_userns;
struct dentry *child;
struct path path; struct path path;
int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path); int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path);
if (unlikely(error)) if (unlikely(error))
return error; return error;
error = mnt_want_write(path.mnt); error = mnt_want_write(path.mnt);
if (unlikely(error)) if (unlikely(error))
goto out; goto out;
mnt_userns = mnt_user_ns(path.mnt); mnt_userns = mnt_user_ns(path.mnt);
child = vfs_tmpfile(mnt_userns, path.dentry, op->mode, op->open_flag); error = vfs_tmpfile(mnt_userns, &path, file, op->mode);
error = PTR_ERR(child); if (error)
if (IS_ERR(child))
goto out2; goto out2;
dput(path.dentry); audit_inode(nd->name, file->f_path.dentry, 0);
path.dentry = child;
audit_inode(nd->name, child, 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: out2:
mnt_drop_write(path.mnt); mnt_drop_write(path.mnt);
out: out:
......
...@@ -2780,6 +2780,15 @@ extern int finish_open(struct file *file, struct dentry *dentry, ...@@ -2780,6 +2780,15 @@ extern int finish_open(struct file *file, struct dentry *dentry,
int (*open)(struct inode *, struct file *)); int (*open)(struct inode *, struct file *));
extern int finish_no_open(struct file *file, struct dentry *dentry); 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)
{
if (error)
return error;
return finish_open(file, file->f_path.dentry, NULL);
}
/* fs/dcache.c */ /* fs/dcache.c */
extern void __init vfs_caches_init_early(void); extern void __init vfs_caches_init_early(void);
extern void __init vfs_caches_init(void); extern void __init vfs_caches_init(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment