vfs: open inside ->tmpfile()

This is in preparation for adding tmpfile support to fuse, which requires
that the tmpfile creation and opening are done as a single operation.

Replace the 'struct dentry *' argument of i_op->tmpfile with
'struct file *'.

Call finish_open_simple() as the last thing in ->tmpfile() instances (may
be omitted in the error case).

Change d_tmpfile() argument to 'struct file *' as well to make callers more
readable.

Reviewed-by: Christian Brauner (Microsoft) <brauner@kernel.org>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Miklos Szeredi 2022-09-24 07:00:00 +02:00
parent 9751b33865
commit 863f144f12
19 changed files with 70 additions and 49 deletions

View file

@ -79,7 +79,8 @@ prototypes::
int (*atomic_open)(struct inode *, struct dentry *, int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag, struct file *, unsigned open_flag,
umode_t create_mode); umode_t create_mode);
int (*tmpfile) (struct inode *, struct dentry *, umode_t); int (*tmpfile) (struct user_namespace *, struct inode *,
struct file *, umode_t);
int (*fileattr_set)(struct user_namespace *mnt_userns, int (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa); struct dentry *dentry, struct fileattr *fa);
int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa); int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa);

View file

@ -922,3 +922,13 @@ is provided - file_open_root_mnt(). In-tree users adjusted.
no_llseek is gone; don't set .llseek to that - just leave it NULL instead. no_llseek is gone; don't set .llseek to that - just leave it NULL instead.
Checks for "does that file have llseek(2), or should it fail with ESPIPE" Checks for "does that file have llseek(2), or should it fail with ESPIPE"
should be done by looking at FMODE_LSEEK in file->f_mode. should be done by looking at FMODE_LSEEK in file->f_mode.
---
**mandatory**
Calling conventions for ->tmpfile() have changed. It now takes a struct
file pointer instead of struct dentry pointer. d_tmpfile() is similarly
changed to simplify callers. The passed file is in a non-open state and on
success must be opened before returning (e.g. by calling
finish_open_simple()).

View file

@ -439,7 +439,7 @@ As of kernel 2.6.22, the following members are defined:
void (*update_time)(struct inode *, struct timespec *, int); void (*update_time)(struct inode *, struct timespec *, int);
int (*atomic_open)(struct inode *, struct dentry *, struct file *, int (*atomic_open)(struct inode *, struct dentry *, struct file *,
unsigned open_flag, umode_t create_mode); unsigned open_flag, umode_t create_mode);
int (*tmpfile) (struct user_namespace *, struct inode *, struct dentry *, umode_t); int (*tmpfile) (struct user_namespace *, struct inode *, struct file *, umode_t);
int (*set_acl)(struct user_namespace *, struct inode *, struct posix_acl *, int); int (*set_acl)(struct user_namespace *, struct inode *, struct posix_acl *, int);
int (*fileattr_set)(struct user_namespace *mnt_userns, int (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa); struct dentry *dentry, struct fileattr *fa);
@ -589,7 +589,9 @@ otherwise noted.
``tmpfile`` ``tmpfile``
called in the end of O_TMPFILE open(). Optional, equivalent to called in the end of O_TMPFILE open(). Optional, equivalent to
atomically creating, opening and unlinking a file in given atomically creating, opening and unlinking a file in given
directory. directory. On success needs to return with the file already
open; this can be done by calling finish_open_simple() right at
the end.
``fileattr_get`` ``fileattr_get``
called on ioctl(FS_IOC_GETFLAGS) and ioctl(FS_IOC_FSGETXATTR) to called on ioctl(FS_IOC_GETFLAGS) and ioctl(FS_IOC_FSGETXATTR) to

View file

@ -147,7 +147,7 @@ static int bad_inode_atomic_open(struct inode *inode, struct dentry *dentry,
} }
static int bad_inode_tmpfile(struct user_namespace *mnt_userns, static int bad_inode_tmpfile(struct user_namespace *mnt_userns,
struct inode *inode, struct dentry *dentry, struct inode *inode, struct file *file,
umode_t mode) umode_t mode)
{ {
return -EIO; return -EIO;

View file

@ -10168,7 +10168,7 @@ static int btrfs_permission(struct user_namespace *mnt_userns,
} }
static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode) struct file *file, umode_t mode)
{ {
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
@ -10176,7 +10176,7 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct inode *inode; struct inode *inode;
struct btrfs_new_inode_args new_inode_args = { struct btrfs_new_inode_args new_inode_args = {
.dir = dir, .dir = dir,
.dentry = dentry, .dentry = file->f_path.dentry,
.orphan = true, .orphan = true,
}; };
unsigned int trans_num_items; unsigned int trans_num_items;
@ -10213,7 +10213,7 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
set_nlink(inode, 1); set_nlink(inode, 1);
if (!ret) { if (!ret) {
d_tmpfile(dentry, inode); d_tmpfile(file, inode);
unlock_new_inode(inode); unlock_new_inode(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
} }
@ -10225,7 +10225,7 @@ out_new_inode_args:
out_inode: out_inode:
if (ret) if (ret)
iput(inode); iput(inode);
return ret; return finish_open_simple(file, ret);
} }
void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end) void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end)

View file

@ -3258,8 +3258,10 @@ void d_genocide(struct dentry *parent)
EXPORT_SYMBOL(d_genocide); EXPORT_SYMBOL(d_genocide);
void d_tmpfile(struct dentry *dentry, struct inode *inode) void d_tmpfile(struct file *file, struct inode *inode)
{ {
struct dentry *dentry = file->f_path.dentry;
inode_dec_link_count(inode); inode_dec_link_count(inode);
BUG_ON(dentry->d_name.name != dentry->d_iname || BUG_ON(dentry->d_name.name != dentry->d_iname ||
!hlist_unhashed(&dentry->d_u.d_alias) || !hlist_unhashed(&dentry->d_u.d_alias) ||

View file

@ -120,7 +120,7 @@ static int ext2_create (struct user_namespace * mnt_userns,
} }
static int ext2_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, static int ext2_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode) struct file *file, umode_t mode)
{ {
struct inode *inode = ext2_new_inode(dir, mode, NULL); struct inode *inode = ext2_new_inode(dir, mode, NULL);
if (IS_ERR(inode)) if (IS_ERR(inode))
@ -128,9 +128,9 @@ static int ext2_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
ext2_set_file_ops(inode); ext2_set_file_ops(inode);
mark_inode_dirty(inode); mark_inode_dirty(inode);
d_tmpfile(dentry, inode); d_tmpfile(file, inode);
unlock_new_inode(inode); unlock_new_inode(inode);
return 0; return finish_open_simple(file, 0);
} }
static int ext2_mknod (struct user_namespace * mnt_userns, struct inode * dir, static int ext2_mknod (struct user_namespace * mnt_userns, struct inode * dir,

View file

@ -2849,7 +2849,7 @@ retry:
} }
static int ext4_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, static int ext4_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode) struct file *file, umode_t mode)
{ {
handle_t *handle; handle_t *handle;
struct inode *inode; struct inode *inode;
@ -2871,7 +2871,7 @@ retry:
inode->i_op = &ext4_file_inode_operations; inode->i_op = &ext4_file_inode_operations;
inode->i_fop = &ext4_file_operations; inode->i_fop = &ext4_file_operations;
ext4_set_aops(inode); ext4_set_aops(inode);
d_tmpfile(dentry, inode); d_tmpfile(file, inode);
err = ext4_orphan_add(handle, inode); err = ext4_orphan_add(handle, inode);
if (err) if (err)
goto err_unlock_inode; goto err_unlock_inode;
@ -2882,7 +2882,7 @@ retry:
ext4_journal_stop(handle); ext4_journal_stop(handle);
if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
goto retry; goto retry;
return err; return finish_open_simple(file, err);
err_unlock_inode: err_unlock_inode:
ext4_journal_stop(handle); ext4_journal_stop(handle);
unlock_new_inode(inode); unlock_new_inode(inode);

View file

@ -845,7 +845,7 @@ out:
} }
static int __f2fs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, static int __f2fs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode, bool is_whiteout, struct file *file, umode_t mode, bool is_whiteout,
struct inode **new_inode) struct inode **new_inode)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
@ -892,8 +892,8 @@ static int __f2fs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
inode->i_state |= I_LINKABLE; inode->i_state |= I_LINKABLE;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
} else { } else {
if (dentry) if (file)
d_tmpfile(dentry, inode); d_tmpfile(file, inode);
else else
f2fs_i_links_write(inode, false); f2fs_i_links_write(inode, false);
} }
@ -915,16 +915,19 @@ out:
} }
static int f2fs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, static int f2fs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode) struct file *file, umode_t mode)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
int err;
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return -EIO; return -EIO;
if (!f2fs_is_checkpoint_ready(sbi)) if (!f2fs_is_checkpoint_ready(sbi))
return -ENOSPC; return -ENOSPC;
return __f2fs_tmpfile(mnt_userns, dir, dentry, mode, false, NULL); err = __f2fs_tmpfile(mnt_userns, dir, file, mode, false, NULL);
return finish_open_simple(file, err);
} }
static int f2fs_create_whiteout(struct user_namespace *mnt_userns, static int f2fs_create_whiteout(struct user_namespace *mnt_userns,

View file

@ -917,7 +917,7 @@ static int hugetlbfs_create(struct user_namespace *mnt_userns,
} }
static int hugetlbfs_tmpfile(struct user_namespace *mnt_userns, static int hugetlbfs_tmpfile(struct user_namespace *mnt_userns,
struct inode *dir, struct dentry *dentry, struct inode *dir, struct file *file,
umode_t mode) umode_t mode)
{ {
struct inode *inode; struct inode *inode;
@ -926,8 +926,8 @@ static int hugetlbfs_tmpfile(struct user_namespace *mnt_userns,
if (!inode) if (!inode)
return -ENOSPC; return -ENOSPC;
dir->i_ctime = dir->i_mtime = current_time(dir); dir->i_ctime = dir->i_mtime = current_time(dir);
d_tmpfile(dentry, inode); d_tmpfile(file, inode);
return 0; return finish_open_simple(file, 0);
} }
static int hugetlbfs_symlink(struct user_namespace *mnt_userns, static int hugetlbfs_symlink(struct user_namespace *mnt_userns,

View file

@ -53,16 +53,16 @@ static int minix_mknod(struct user_namespace *mnt_userns, struct inode *dir,
} }
static int minix_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, static int minix_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode) struct file *file, umode_t mode)
{ {
int error; int error;
struct inode *inode = minix_new_inode(dir, mode, &error); struct inode *inode = minix_new_inode(dir, mode, &error);
if (inode) { if (inode) {
minix_set_inode(inode, 0); minix_set_inode(inode, 0);
mark_inode_dirty(inode); mark_inode_dirty(inode);
d_tmpfile(dentry, inode); d_tmpfile(file, inode);
} }
return error; return finish_open_simple(file, error);
} }
static int minix_create(struct user_namespace *mnt_userns, struct inode *dir, static int minix_create(struct user_namespace *mnt_userns, struct inode *dir,

View file

@ -3604,8 +3604,7 @@ static int vfs_tmpfile(struct user_namespace *mnt_userns,
file->f_path.mnt = parentpath->mnt; file->f_path.mnt = parentpath->mnt;
file->f_path.dentry = child; 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, file, mode);
error = finish_open_simple(file, error);
dput(child); dput(child);
if (error) if (error)
return error; return error;

View file

@ -146,15 +146,15 @@ static int ramfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
} }
static int ramfs_tmpfile(struct user_namespace *mnt_userns, static int ramfs_tmpfile(struct user_namespace *mnt_userns,
struct inode *dir, struct dentry *dentry, umode_t mode) struct inode *dir, struct file *file, umode_t mode)
{ {
struct inode *inode; struct inode *inode;
inode = ramfs_get_inode(dir->i_sb, dir, mode, 0); inode = ramfs_get_inode(dir->i_sb, dir, mode, 0);
if (!inode) if (!inode)
return -ENOSPC; return -ENOSPC;
d_tmpfile(dentry, inode); d_tmpfile(file, inode);
return 0; return finish_open_simple(file, 0);
} }
static const struct inode_operations ramfs_dir_inode_operations = { static const struct inode_operations ramfs_dir_inode_operations = {

View file

@ -424,8 +424,9 @@ static void unlock_2_inodes(struct inode *inode1, struct inode *inode2)
} }
static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode) struct file *file, umode_t mode)
{ {
struct dentry *dentry = file->f_path.dentry;
struct inode *inode; struct inode *inode;
struct ubifs_info *c = dir->i_sb->s_fs_info; struct ubifs_info *c = dir->i_sb->s_fs_info;
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
@ -475,7 +476,7 @@ static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
mutex_lock(&ui->ui_mutex); mutex_lock(&ui->ui_mutex);
insert_inode_hash(inode); insert_inode_hash(inode);
d_tmpfile(dentry, inode); d_tmpfile(file, inode);
ubifs_assert(c, ui->dirty); ubifs_assert(c, ui->dirty);
instantiated = 1; instantiated = 1;
@ -489,7 +490,7 @@ static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
ubifs_release_budget(c, &req); ubifs_release_budget(c, &req);
return 0; return finish_open_simple(file, 0);
out_cancel: out_cancel:
unlock_2_inodes(dir, inode); unlock_2_inodes(dir, inode);

View file

@ -626,7 +626,7 @@ static int udf_create(struct user_namespace *mnt_userns, struct inode *dir,
} }
static int udf_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, static int udf_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode) struct file *file, umode_t mode)
{ {
struct inode *inode = udf_new_inode(dir, mode); struct inode *inode = udf_new_inode(dir, mode);
@ -640,9 +640,9 @@ static int udf_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
inode->i_op = &udf_file_inode_operations; inode->i_op = &udf_file_inode_operations;
inode->i_fop = &udf_file_operations; inode->i_fop = &udf_file_operations;
mark_inode_dirty(inode); mark_inode_dirty(inode);
d_tmpfile(dentry, inode); d_tmpfile(file, inode);
unlock_new_inode(inode); unlock_new_inode(inode);
return 0; return finish_open_simple(file, 0);
} }
static int udf_mknod(struct user_namespace *mnt_userns, struct inode *dir, static int udf_mknod(struct user_namespace *mnt_userns, struct inode *dir,

View file

@ -167,7 +167,7 @@ xfs_generic_create(
struct dentry *dentry, struct dentry *dentry,
umode_t mode, umode_t mode,
dev_t rdev, dev_t rdev,
bool tmpfile) /* unnamed file */ struct file *tmpfile) /* unnamed file */
{ {
struct inode *inode; struct inode *inode;
struct xfs_inode *ip = NULL; struct xfs_inode *ip = NULL;
@ -234,7 +234,7 @@ xfs_generic_create(
* d_tmpfile can immediately set it back to zero. * d_tmpfile can immediately set it back to zero.
*/ */
set_nlink(inode, 1); set_nlink(inode, 1);
d_tmpfile(dentry, inode); d_tmpfile(tmpfile, inode);
} else } else
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
@ -261,7 +261,7 @@ xfs_vn_mknod(
umode_t mode, umode_t mode,
dev_t rdev) dev_t rdev)
{ {
return xfs_generic_create(mnt_userns, dir, dentry, mode, rdev, false); return xfs_generic_create(mnt_userns, dir, dentry, mode, rdev, NULL);
} }
STATIC int STATIC int
@ -272,7 +272,7 @@ xfs_vn_create(
umode_t mode, umode_t mode,
bool flags) bool flags)
{ {
return xfs_generic_create(mnt_userns, dir, dentry, mode, 0, false); return xfs_generic_create(mnt_userns, dir, dentry, mode, 0, NULL);
} }
STATIC int STATIC int
@ -283,7 +283,7 @@ xfs_vn_mkdir(
umode_t mode) umode_t mode)
{ {
return xfs_generic_create(mnt_userns, dir, dentry, mode | S_IFDIR, 0, return xfs_generic_create(mnt_userns, dir, dentry, mode | S_IFDIR, 0,
false); NULL);
} }
STATIC struct dentry * STATIC struct dentry *
@ -1080,10 +1080,12 @@ STATIC int
xfs_vn_tmpfile( xfs_vn_tmpfile(
struct user_namespace *mnt_userns, struct user_namespace *mnt_userns,
struct inode *dir, struct inode *dir,
struct dentry *dentry, struct file *file,
umode_t mode) umode_t mode)
{ {
return xfs_generic_create(mnt_userns, dir, dentry, mode, 0, true); int err = xfs_generic_create(mnt_userns, dir, file->f_path.dentry, mode, 0, file);
return finish_open_simple(file, err);
} }
static const struct inode_operations xfs_inode_operations = { static const struct inode_operations xfs_inode_operations = {

View file

@ -16,6 +16,7 @@
#include <linux/wait.h> #include <linux/wait.h>
struct path; struct path;
struct file;
struct vfsmount; struct vfsmount;
/* /*
@ -250,7 +251,7 @@ extern struct dentry * d_make_root(struct inode *);
/* <clickety>-<click> the ramfs-type tree */ /* <clickety>-<click> the ramfs-type tree */
extern void d_genocide(struct dentry *); extern void d_genocide(struct dentry *);
extern void d_tmpfile(struct dentry *, struct inode *); extern void d_tmpfile(struct file *, struct inode *);
extern struct dentry *d_find_alias(struct inode *); extern struct dentry *d_find_alias(struct inode *);
extern void d_prune_aliases(struct inode *); extern void d_prune_aliases(struct inode *);

View file

@ -2168,7 +2168,7 @@ struct inode_operations {
struct file *, unsigned open_flag, struct file *, unsigned open_flag,
umode_t create_mode); umode_t create_mode);
int (*tmpfile) (struct user_namespace *, struct inode *, int (*tmpfile) (struct user_namespace *, struct inode *,
struct dentry *, umode_t); struct file *, umode_t);
int (*set_acl)(struct user_namespace *, struct inode *, int (*set_acl)(struct user_namespace *, struct inode *,
struct posix_acl *, int); struct posix_acl *, int);
int (*fileattr_set)(struct user_namespace *mnt_userns, int (*fileattr_set)(struct user_namespace *mnt_userns,

View file

@ -2912,7 +2912,7 @@ out_iput:
static int static int
shmem_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, shmem_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode) struct file *file, umode_t mode)
{ {
struct inode *inode; struct inode *inode;
int error = -ENOSPC; int error = -ENOSPC;
@ -2927,9 +2927,9 @@ shmem_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
error = simple_acl_create(dir, inode); error = simple_acl_create(dir, inode);
if (error) if (error)
goto out_iput; goto out_iput;
d_tmpfile(dentry, inode); d_tmpfile(file, inode);
} }
return error; return finish_open_simple(file, error);
out_iput: out_iput:
iput(inode); iput(inode);
return error; return error;