mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-06 05:13:18 +00:00
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: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
3e9d4c5935
commit
9751b33865
83
fs/namei.c
83
fs/namei.c
@ -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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
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,
|
|||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user