Skip to content

Commit

Permalink
Merge tag 'pull-tmpfile' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/viro/vfs

Pull vfs tmpfile updates from Al Viro:
 "Miklos' ->tmpfile() signature change; pass an unopened struct file to
  it, let it open the damn thing. Allows to add tmpfile support to FUSE"

* tag 'pull-tmpfile' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  fuse: implement ->tmpfile()
  vfs: open inside ->tmpfile()
  vfs: move open right after ->tmpfile()
  vfs: make vfs_tmpfile() static
  ovl: use vfs_tmpfile_open() helper
  cachefiles: use vfs_tmpfile_open() helper
  cachefiles: only pass inode to *mark_inode_inuse() helpers
  cachefiles: tmpfile error handling cleanup
  hugetlbfs: cleanup mknod and tmpfile
  vfs: add vfs_tmpfile_open() helper
  • Loading branch information
torvalds committed Oct 11, 2022
2 parents 27bc50f + 7d37539 commit f721d24
Show file tree
Hide file tree
Showing 26 changed files with 301 additions and 238 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 @@ -933,3 +933,13 @@ to) and true - "keep going" (as 0 in old calling conventions). Rationale:
callers never looked at specific -E... values anyway. ->iterate() and
->iterate_shared() instance require no changes at all, all filldir_t ones in
the tree converted.

---

**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 @@ -442,7 +442,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 @@ -592,7 +592,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 @@ -10018,15 +10018,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 @@ -10063,7 +10063,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 @@ -10075,7 +10075,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
122 changes: 52 additions & 70 deletions fs/cachefiles/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@
* file or directory. The caller must hold the inode lock.
*/
static bool __cachefiles_mark_inode_in_use(struct cachefiles_object *object,
struct dentry *dentry)
struct inode *inode)
{
struct inode *inode = d_backing_inode(dentry);
bool can_use = false;

if (!(inode->i_flags & S_KERNEL_FILE)) {
Expand All @@ -26,21 +25,18 @@ static bool __cachefiles_mark_inode_in_use(struct cachefiles_object *object,
can_use = true;
} else {
trace_cachefiles_mark_failed(object, inode);
pr_notice("cachefiles: Inode already in use: %pd (B=%lx)\n",
dentry, inode->i_ino);
}

return can_use;
}

static bool cachefiles_mark_inode_in_use(struct cachefiles_object *object,
struct dentry *dentry)
struct inode *inode)
{
struct inode *inode = d_backing_inode(dentry);
bool can_use;

inode_lock(inode);
can_use = __cachefiles_mark_inode_in_use(object, dentry);
can_use = __cachefiles_mark_inode_in_use(object, inode);
inode_unlock(inode);
return can_use;
}
Expand All @@ -49,21 +45,17 @@ static bool cachefiles_mark_inode_in_use(struct cachefiles_object *object,
* Unmark a backing inode. The caller must hold the inode lock.
*/
static void __cachefiles_unmark_inode_in_use(struct cachefiles_object *object,
struct dentry *dentry)
struct inode *inode)
{
struct inode *inode = d_backing_inode(dentry);

inode->i_flags &= ~S_KERNEL_FILE;
trace_cachefiles_mark_inactive(object, inode);
}

static void cachefiles_do_unmark_inode_in_use(struct cachefiles_object *object,
struct dentry *dentry)
struct inode *inode)
{
struct inode *inode = d_backing_inode(dentry);

inode_lock(inode);
__cachefiles_unmark_inode_in_use(object, dentry);
__cachefiles_unmark_inode_in_use(object, inode);
inode_unlock(inode);
}

Expand All @@ -77,14 +69,12 @@ void cachefiles_unmark_inode_in_use(struct cachefiles_object *object,
struct cachefiles_cache *cache = object->volume->cache;
struct inode *inode = file_inode(file);

if (inode) {
cachefiles_do_unmark_inode_in_use(object, file->f_path.dentry);
cachefiles_do_unmark_inode_in_use(object, inode);

if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
atomic_long_add(inode->i_blocks, &cache->b_released);
if (atomic_inc_return(&cache->f_released))
cachefiles_state_changed(cache);
}
if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
atomic_long_add(inode->i_blocks, &cache->b_released);
if (atomic_inc_return(&cache->f_released))
cachefiles_state_changed(cache);
}
}

Expand Down Expand Up @@ -164,8 +154,11 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
inode_lock(d_inode(subdir));
inode_unlock(d_inode(dir));

if (!__cachefiles_mark_inode_in_use(NULL, subdir))
if (!__cachefiles_mark_inode_in_use(NULL, d_inode(subdir))) {
pr_notice("cachefiles: Inode already in use: %pd (B=%lx)\n",
subdir, d_inode(subdir)->i_ino);
goto mark_error;
}

inode_unlock(d_inode(subdir));

Expand Down Expand Up @@ -224,9 +217,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
void cachefiles_put_directory(struct dentry *dir)
{
if (dir) {
inode_lock(dir->d_inode);
__cachefiles_unmark_inode_in_use(NULL, dir);
inode_unlock(dir->d_inode);
cachefiles_do_unmark_inode_in_use(NULL, d_inode(dir));
dput(dir);
}
}
Expand Down Expand Up @@ -410,7 +401,7 @@ int cachefiles_bury_object(struct cachefiles_cache *cache,
"Rename failed with error %d", ret);
}

__cachefiles_unmark_inode_in_use(object, rep);
__cachefiles_unmark_inode_in_use(object, d_inode(rep));
unlock_rename(cache->graveyard, dir);
dput(grave);
_leave(" = 0");
Expand Down Expand Up @@ -451,84 +442,72 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object)
const struct cred *saved_cred;
struct dentry *fan = volume->fanout[(u8)object->cookie->key_hash];
struct file *file;
struct path path;
const struct path parentpath = { .mnt = cache->mnt, .dentry = fan };
uint64_t ni_size;
long ret;


cachefiles_begin_secure(cache, &saved_cred);

path.mnt = cache->mnt;
ret = cachefiles_inject_write_error();
if (ret == 0)
path.dentry = vfs_tmpfile(&init_user_ns, fan, S_IFREG, O_RDWR);
else
path.dentry = ERR_PTR(ret);
if (IS_ERR(path.dentry)) {
trace_cachefiles_vfs_error(object, d_inode(fan), PTR_ERR(path.dentry),
if (ret == 0) {
file = vfs_tmpfile_open(&init_user_ns, &parentpath, S_IFREG,
O_RDWR | O_LARGEFILE | O_DIRECT,
cache->cache_cred);
ret = PTR_ERR_OR_ZERO(file);
}
if (ret) {
trace_cachefiles_vfs_error(object, d_inode(fan), ret,
cachefiles_trace_tmpfile_error);
if (PTR_ERR(path.dentry) == -EIO)
if (ret == -EIO)
cachefiles_io_error_obj(object, "Failed to create tmpfile");
file = ERR_CAST(path.dentry);
goto out;
goto err;
}

trace_cachefiles_tmpfile(object, d_backing_inode(path.dentry));
trace_cachefiles_tmpfile(object, file_inode(file));

if (!cachefiles_mark_inode_in_use(object, path.dentry)) {
file = ERR_PTR(-EBUSY);
goto out_dput;
}
/* This is a newly created file with no other possible user */
if (!cachefiles_mark_inode_in_use(object, file_inode(file)))
WARN_ON(1);

ret = cachefiles_ondemand_init_object(object);
if (ret < 0) {
file = ERR_PTR(ret);
goto out_unuse;
}
if (ret < 0)
goto err_unuse;

ni_size = object->cookie->object_size;
ni_size = round_up(ni_size, CACHEFILES_DIO_BLOCK_SIZE);

if (ni_size > 0) {
trace_cachefiles_trunc(object, d_backing_inode(path.dentry), 0, ni_size,
trace_cachefiles_trunc(object, file_inode(file), 0, ni_size,
cachefiles_trunc_expand_tmpfile);
ret = cachefiles_inject_write_error();
if (ret == 0)
ret = vfs_truncate(&path, ni_size);
ret = vfs_truncate(&file->f_path, ni_size);
if (ret < 0) {
trace_cachefiles_vfs_error(
object, d_backing_inode(path.dentry), ret,
object, file_inode(file), ret,
cachefiles_trace_trunc_error);
file = ERR_PTR(ret);
goto out_unuse;
goto err_unuse;
}
}

file = open_with_fake_path(&path, O_RDWR | O_LARGEFILE | O_DIRECT,
d_backing_inode(path.dentry), cache->cache_cred);
if (IS_ERR(file)) {
trace_cachefiles_vfs_error(object, d_backing_inode(path.dentry),
PTR_ERR(file),
cachefiles_trace_open_error);
goto out_unuse;
}
ret = -EINVAL;
if (unlikely(!file->f_op->read_iter) ||
unlikely(!file->f_op->write_iter)) {
fput(file);
pr_notice("Cache does not support read_iter and write_iter\n");
file = ERR_PTR(-EINVAL);
goto out_unuse;
goto err_unuse;
}

goto out_dput;

out_unuse:
cachefiles_do_unmark_inode_in_use(object, path.dentry);
out_dput:
dput(path.dentry);
out:
cachefiles_end_secure(cache, saved_cred);
return file;

err_unuse:
cachefiles_do_unmark_inode_in_use(object, file_inode(file));
fput(file);
err:
file = ERR_PTR(ret);
goto out;
}

/*
Expand Down Expand Up @@ -569,8 +548,11 @@ static bool cachefiles_open_file(struct cachefiles_object *object,

_enter("%pd", dentry);

if (!cachefiles_mark_inode_in_use(object, dentry))
if (!cachefiles_mark_inode_in_use(object, d_inode(dentry))) {
pr_notice("cachefiles: Inode already in use: %pd (B=%lx)\n",
dentry, d_inode(dentry)->i_ino);
return false;
}

/* We need to open a file interface onto a data file now as we can't do
* it on demand because writeback called from do_exit() sees
Expand Down Expand Up @@ -624,7 +606,7 @@ static bool cachefiles_open_file(struct cachefiles_object *object,
error_fput:
fput(file);
error:
cachefiles_do_unmark_inode_in_use(object, dentry);
cachefiles_do_unmark_inode_in_use(object, d_inode(dentry));
dput(dentry);
return false;
}
Expand Down
4 changes: 3 additions & 1 deletion fs/dcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -3249,8 +3249,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 @@ -2854,7 +2854,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 @@ -2876,7 +2876,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 @@ -2887,7 +2887,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
Loading

0 comments on commit f721d24

Please sign in to comment.