Skip to content

Commit 9751b33

Browse files
author
Miklos Szeredi
committed
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 <[email protected]>
1 parent 3e9d4c5 commit 9751b33

File tree

2 files changed

+42
-50
lines changed

2 files changed

+42
-50
lines changed

fs/namei.c

Lines changed: 33 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3583,44 +3583,44 @@ static int do_open(struct nameidata *nd,
35833583
* On non-idmapped mounts or if permission checking is to be performed on the
35843584
* raw inode simply passs init_user_ns.
35853585
*/
3586-
static struct dentry *vfs_tmpfile(struct user_namespace *mnt_userns,
3587-
struct dentry *dentry, umode_t mode, int open_flag)
3586+
static int vfs_tmpfile(struct user_namespace *mnt_userns,
3587+
const struct path *parentpath,
3588+
struct file *file, umode_t mode)
35883589
{
3589-
struct dentry *child = NULL;
3590-
struct inode *dir = dentry->d_inode;
3590+
struct dentry *child;
3591+
struct inode *dir = d_inode(parentpath->dentry);
35913592
struct inode *inode;
35923593
int error;
35933594

35943595
/* we want directory to be writable */
35953596
error = inode_permission(mnt_userns, dir, MAY_WRITE | MAY_EXEC);
35963597
if (error)
3597-
goto out_err;
3598-
error = -EOPNOTSUPP;
3598+
return error;
35993599
if (!dir->i_op->tmpfile)
3600-
goto out_err;
3601-
error = -ENOMEM;
3602-
child = d_alloc(dentry, &slash_name);
3600+
return -EOPNOTSUPP;
3601+
child = d_alloc(parentpath->dentry, &slash_name);
36033602
if (unlikely(!child))
3604-
goto out_err;
3603+
return -ENOMEM;
3604+
file->f_path.mnt = parentpath->mnt;
3605+
file->f_path.dentry = child;
36053606
mode = vfs_prepare_mode(mnt_userns, dir, mode, mode, mode);
36063607
error = dir->i_op->tmpfile(mnt_userns, dir, child, mode);
3608+
error = finish_open_simple(file, error);
3609+
dput(child);
36073610
if (error)
3608-
goto out_err;
3609-
error = -ENOENT;
3610-
inode = child->d_inode;
3611-
if (unlikely(!inode))
3612-
goto out_err;
3613-
if (!(open_flag & O_EXCL)) {
3611+
return error;
3612+
/* Don't check for other permissions, the inode was just created */
3613+
error = may_open(mnt_userns, &file->f_path, 0, file->f_flags);
3614+
if (error)
3615+
return error;
3616+
inode = file_inode(file);
3617+
if (!(file->f_flags & O_EXCL)) {
36143618
spin_lock(&inode->i_lock);
36153619
inode->i_state |= I_LINKABLE;
36163620
spin_unlock(&inode->i_lock);
36173621
}
36183622
ima_post_create_tmpfile(mnt_userns, inode);
3619-
return child;
3620-
3621-
out_err:
3622-
dput(child);
3623-
return ERR_PTR(error);
3623+
return 0;
36243624
}
36253625

36263626
/**
@@ -3641,25 +3641,15 @@ struct file *vfs_tmpfile_open(struct user_namespace *mnt_userns,
36413641
{
36423642
struct file *file;
36433643
int error;
3644-
struct path path = { .mnt = parentpath->mnt };
3645-
3646-
path.dentry = vfs_tmpfile(mnt_userns, parentpath->dentry, mode, open_flag);
3647-
if (IS_ERR(path.dentry))
3648-
return ERR_CAST(path.dentry);
3649-
3650-
error = may_open(mnt_userns, &path, 0, open_flag);
3651-
file = ERR_PTR(error);
3652-
if (error)
3653-
goto out_dput;
3654-
3655-
/*
3656-
* This relies on the "noaccount" property of fake open, otherwise
3657-
* equivalent to dentry_open().
3658-
*/
3659-
file = open_with_fake_path(&path, open_flag, d_inode(path.dentry), cred);
3660-
out_dput:
3661-
dput(path.dentry);
36623644

3645+
file = alloc_empty_file_noaccount(open_flag, cred);
3646+
if (!IS_ERR(file)) {
3647+
error = vfs_tmpfile(mnt_userns, parentpath, file, mode);
3648+
if (error) {
3649+
fput(file);
3650+
file = ERR_PTR(error);
3651+
}
3652+
}
36633653
return file;
36643654
}
36653655
EXPORT_SYMBOL(vfs_tmpfile_open);
@@ -3669,26 +3659,19 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
36693659
struct file *file)
36703660
{
36713661
struct user_namespace *mnt_userns;
3672-
struct dentry *child;
36733662
struct path path;
36743663
int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path);
3664+
36753665
if (unlikely(error))
36763666
return error;
36773667
error = mnt_want_write(path.mnt);
36783668
if (unlikely(error))
36793669
goto out;
36803670
mnt_userns = mnt_user_ns(path.mnt);
3681-
child = vfs_tmpfile(mnt_userns, path.dentry, op->mode, op->open_flag);
3682-
error = PTR_ERR(child);
3683-
if (IS_ERR(child))
3671+
error = vfs_tmpfile(mnt_userns, &path, file, op->mode);
3672+
if (error)
36843673
goto out2;
3685-
dput(path.dentry);
3686-
path.dentry = child;
3687-
audit_inode(nd->name, child, 0);
3688-
/* Don't check for other permissions, the inode was just created */
3689-
error = may_open(mnt_userns, &path, 0, op->open_flag);
3690-
if (!error)
3691-
error = vfs_open(&path, file);
3674+
audit_inode(nd->name, file->f_path.dentry, 0);
36923675
out2:
36933676
mnt_drop_write(path.mnt);
36943677
out:

include/linux/fs.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2780,6 +2780,15 @@ extern int finish_open(struct file *file, struct dentry *dentry,
27802780
int (*open)(struct inode *, struct file *));
27812781
extern int finish_no_open(struct file *file, struct dentry *dentry);
27822782

2783+
/* Helper for the simple case when original dentry is used */
2784+
static inline int finish_open_simple(struct file *file, int error)
2785+
{
2786+
if (error)
2787+
return error;
2788+
2789+
return finish_open(file, file->f_path.dentry, NULL);
2790+
}
2791+
27832792
/* fs/dcache.c */
27842793
extern void __init vfs_caches_init_early(void);
27852794
extern void __init vfs_caches_init(void);

0 commit comments

Comments
 (0)