Skip to content

Commit

Permalink
vfs: open inside ->tmpfile()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Miklos Szeredi committed Sep 24, 2022
1 parent 9751b33 commit 863f144
Show file tree
Hide file tree
Showing 19 changed files with 70 additions and 49 deletions.
3 changes: 2 additions & 1 deletion Documentation/filesystems/locking.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ prototypes::
int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag,
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,
struct dentry *dentry, struct fileattr *fa);
int (*fileattr_get)(struct dentry *dentry, struct fileattr *fa);
Expand Down
10 changes: 10 additions & 0 deletions Documentation/filesystems/porting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
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.

---

**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()).
6 changes: 4 additions & 2 deletions Documentation/filesystems/vfs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ As of kernel 2.6.22, the following members are defined:
void (*update_time)(struct inode *, struct timespec *, int);
int (*atomic_open)(struct inode *, struct dentry *, struct file *,
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 (*fileattr_set)(struct user_namespace *mnt_userns,
struct dentry *dentry, struct fileattr *fa);
Expand Down Expand Up @@ -589,7 +589,9 @@ otherwise noted.
``tmpfile``
called in the end of O_TMPFILE open(). Optional, equivalent to
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``
called on ioctl(FS_IOC_GETFLAGS) and ioctl(FS_IOC_FSGETXATTR) to
Expand Down
2 changes: 1 addition & 1 deletion fs/bad_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct inode *inode, struct dentry *dentry,
struct inode *inode, struct file *file,
umode_t mode)
{
return -EIO;
Expand Down
8 changes: 4 additions & 4 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -10168,15 +10168,15 @@ static int btrfs_permission(struct user_namespace *mnt_userns,
}

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_trans_handle *trans;
struct btrfs_root *root = BTRFS_I(dir)->root;
struct inode *inode;
struct btrfs_new_inode_args new_inode_args = {
.dir = dir,
.dentry = dentry,
.dentry = file->f_path.dentry,
.orphan = true,
};
unsigned int trans_num_items;
Expand Down Expand Up @@ -10213,7 +10213,7 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
set_nlink(inode, 1);

if (!ret) {
d_tmpfile(dentry, inode);
d_tmpfile(file, inode);
unlock_new_inode(inode);
mark_inode_dirty(inode);
}
Expand All @@ -10225,7 +10225,7 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
out_inode:
if (ret)
iput(inode);
return ret;
return finish_open_simple(file, ret);
}

void btrfs_set_range_writeback(struct btrfs_inode *inode, u64 start, u64 end)
Expand Down
4 changes: 3 additions & 1 deletion fs/dcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -3258,8 +3258,10 @@ void d_genocide(struct dentry *parent)

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);
BUG_ON(dentry->d_name.name != dentry->d_iname ||
!hlist_unhashed(&dentry->d_u.d_alias) ||
Expand Down
6 changes: 3 additions & 3 deletions fs/ext2/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,17 @@ static int ext2_create (struct user_namespace * mnt_userns,
}

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);
if (IS_ERR(inode))
return PTR_ERR(inode);

ext2_set_file_ops(inode);
mark_inode_dirty(inode);
d_tmpfile(dentry, inode);
d_tmpfile(file, 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,
Expand Down
6 changes: 3 additions & 3 deletions fs/ext4/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -2849,7 +2849,7 @@ static int ext4_mknod(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;
struct inode *inode;
Expand All @@ -2871,7 +2871,7 @@ static int ext4_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
inode->i_op = &ext4_file_inode_operations;
inode->i_fop = &ext4_file_operations;
ext4_set_aops(inode);
d_tmpfile(dentry, inode);
d_tmpfile(file, inode);
err = ext4_orphan_add(handle, inode);
if (err)
goto err_unlock_inode;
Expand All @@ -2882,7 +2882,7 @@ static int ext4_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
ext4_journal_stop(handle);
if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
goto retry;
return err;
return finish_open_simple(file, err);
err_unlock_inode:
ext4_journal_stop(handle);
unlock_new_inode(inode);
Expand Down
13 changes: 8 additions & 5 deletions fs/f2fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@ static int f2fs_mknod(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 f2fs_sb_info *sbi = F2FS_I_SB(dir);
Expand Down Expand Up @@ -892,8 +892,8 @@ static int __f2fs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
inode->i_state |= I_LINKABLE;
spin_unlock(&inode->i_lock);
} else {
if (dentry)
d_tmpfile(dentry, inode);
if (file)
d_tmpfile(file, inode);
else
f2fs_i_links_write(inode, false);
}
Expand All @@ -915,16 +915,19 @@ 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);
int err;

if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
if (!f2fs_is_checkpoint_ready(sbi))
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,
Expand Down
6 changes: 3 additions & 3 deletions fs/hugetlbfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ static int hugetlbfs_create(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)
{
struct inode *inode;
Expand All @@ -926,8 +926,8 @@ static int hugetlbfs_tmpfile(struct user_namespace *mnt_userns,
if (!inode)
return -ENOSPC;
dir->i_ctime = dir->i_mtime = current_time(dir);
d_tmpfile(dentry, inode);
return 0;
d_tmpfile(file, inode);
return finish_open_simple(file, 0);
}

static int hugetlbfs_symlink(struct user_namespace *mnt_userns,
Expand Down
6 changes: 3 additions & 3 deletions fs/minix/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct dentry *dentry, umode_t mode)
struct file *file, umode_t mode)
{
int error;
struct inode *inode = minix_new_inode(dir, mode, &error);
if (inode) {
minix_set_inode(inode, 0);
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,
Expand Down
3 changes: 1 addition & 2 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -3604,8 +3604,7 @@ static int vfs_tmpfile(struct user_namespace *mnt_userns,
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);
error = dir->i_op->tmpfile(mnt_userns, dir, file, mode);
dput(child);
if (error)
return error;
Expand Down
6 changes: 3 additions & 3 deletions fs/ramfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct inode *dir, struct dentry *dentry, umode_t mode)
struct inode *dir, struct file *file, umode_t mode)
{
struct inode *inode;

inode = ramfs_get_inode(dir->i_sb, dir, mode, 0);
if (!inode)
return -ENOSPC;
d_tmpfile(dentry, inode);
return 0;
d_tmpfile(file, inode);
return finish_open_simple(file, 0);
}

static const struct inode_operations ramfs_dir_inode_operations = {
Expand Down
7 changes: 4 additions & 3 deletions fs/ubifs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct dentry *dentry, umode_t mode)
struct file *file, umode_t mode)
{
struct dentry *dentry = file->f_path.dentry;
struct inode *inode;
struct ubifs_info *c = dir->i_sb->s_fs_info;
struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1,
Expand Down Expand Up @@ -475,7 +476,7 @@ static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,

mutex_lock(&ui->ui_mutex);
insert_inode_hash(inode);
d_tmpfile(dentry, inode);
d_tmpfile(file, inode);
ubifs_assert(c, ui->dirty);

instantiated = 1;
Expand All @@ -489,7 +490,7 @@ static int ubifs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,

ubifs_release_budget(c, &req);

return 0;
return finish_open_simple(file, 0);

out_cancel:
unlock_2_inodes(dir, inode);
Expand Down
6 changes: 3 additions & 3 deletions fs/udf/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
struct dentry *dentry, umode_t mode)
struct file *file, umode_t mode)
{
struct inode *inode = udf_new_inode(dir, mode);

Expand All @@ -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_fop = &udf_file_operations;
mark_inode_dirty(inode);
d_tmpfile(dentry, inode);
d_tmpfile(file, 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,
Expand Down
16 changes: 9 additions & 7 deletions fs/xfs/xfs_iops.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ xfs_generic_create(
struct dentry *dentry,
umode_t mode,
dev_t rdev,
bool tmpfile) /* unnamed file */
struct file *tmpfile) /* unnamed file */
{
struct inode *inode;
struct xfs_inode *ip = NULL;
Expand Down Expand Up @@ -234,7 +234,7 @@ xfs_generic_create(
* d_tmpfile can immediately set it back to zero.
*/
set_nlink(inode, 1);
d_tmpfile(dentry, inode);
d_tmpfile(tmpfile, inode);
} else
d_instantiate(dentry, inode);

Expand All @@ -261,7 +261,7 @@ xfs_vn_mknod(
umode_t mode,
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
Expand All @@ -272,7 +272,7 @@ xfs_vn_create(
umode_t mode,
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
Expand All @@ -283,7 +283,7 @@ xfs_vn_mkdir(
umode_t mode)
{
return xfs_generic_create(mnt_userns, dir, dentry, mode | S_IFDIR, 0,
false);
NULL);
}

STATIC struct dentry *
Expand Down Expand Up @@ -1080,10 +1080,12 @@ STATIC int
xfs_vn_tmpfile(
struct user_namespace *mnt_userns,
struct inode *dir,
struct dentry *dentry,
struct file *file,
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 = {
Expand Down
3 changes: 2 additions & 1 deletion include/linux/dcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <linux/wait.h>

struct path;
struct file;
struct vfsmount;

/*
Expand Down Expand Up @@ -250,7 +251,7 @@ extern struct dentry * d_make_root(struct inode *);
/* <clickety>-<click> the ramfs-type tree */
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 void d_prune_aliases(struct inode *);
Expand Down
2 changes: 1 addition & 1 deletion include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -2168,7 +2168,7 @@ struct inode_operations {
struct file *, unsigned open_flag,
umode_t create_mode);
int (*tmpfile) (struct user_namespace *, struct inode *,
struct dentry *, umode_t);
struct file *, umode_t);
int (*set_acl)(struct user_namespace *, struct inode *,
struct posix_acl *, int);
int (*fileattr_set)(struct user_namespace *mnt_userns,
Expand Down
Loading

0 comments on commit 863f144

Please sign in to comment.