提交 f721d24e 编写于 作者: L Linus Torvalds

Merge tag 'pull-tmpfile' of git://git.kernel.org/pub/scm/linux/kernel/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
...@@ -79,7 +79,8 @@ prototypes:: ...@@ -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);
......
...@@ -933,3 +933,13 @@ to) and true - "keep going" (as 0 in old calling conventions). Rationale: ...@@ -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 callers never looked at specific -E... values anyway. ->iterate() and
->iterate_shared() instance require no changes at all, all filldir_t ones in ->iterate_shared() instance require no changes at all, all filldir_t ones in
the tree converted. 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()).
...@@ -442,7 +442,7 @@ As of kernel 2.6.22, the following members are defined: ...@@ -442,7 +442,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);
...@@ -592,7 +592,9 @@ otherwise noted. ...@@ -592,7 +592,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
......
...@@ -147,7 +147,7 @@ static int bad_inode_atomic_open(struct inode *inode, struct dentry *dentry, ...@@ -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;
......
...@@ -10018,7 +10018,7 @@ static int btrfs_permission(struct user_namespace *mnt_userns, ...@@ -10018,7 +10018,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;
...@@ -10026,7 +10026,7 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -10026,7 +10026,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;
...@@ -10063,7 +10063,7 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -10063,7 +10063,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);
} }
...@@ -10075,7 +10075,7 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -10075,7 +10075,7 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
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)
......
...@@ -15,9 +15,8 @@ ...@@ -15,9 +15,8 @@
* file or directory. The caller must hold the inode lock. * file or directory. The caller must hold the inode lock.
*/ */
static bool __cachefiles_mark_inode_in_use(struct cachefiles_object *object, 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; bool can_use = false;
if (!(inode->i_flags & S_KERNEL_FILE)) { if (!(inode->i_flags & S_KERNEL_FILE)) {
...@@ -26,21 +25,18 @@ static bool __cachefiles_mark_inode_in_use(struct cachefiles_object *object, ...@@ -26,21 +25,18 @@ static bool __cachefiles_mark_inode_in_use(struct cachefiles_object *object,
can_use = true; can_use = true;
} else { } else {
trace_cachefiles_mark_failed(object, inode); trace_cachefiles_mark_failed(object, inode);
pr_notice("cachefiles: Inode already in use: %pd (B=%lx)\n",
dentry, inode->i_ino);
} }
return can_use; return can_use;
} }
static bool cachefiles_mark_inode_in_use(struct cachefiles_object *object, 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; bool can_use;
inode_lock(inode); inode_lock(inode);
can_use = __cachefiles_mark_inode_in_use(object, dentry); can_use = __cachefiles_mark_inode_in_use(object, inode);
inode_unlock(inode); inode_unlock(inode);
return can_use; return can_use;
} }
...@@ -49,21 +45,17 @@ static bool cachefiles_mark_inode_in_use(struct cachefiles_object *object, ...@@ -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. * Unmark a backing inode. The caller must hold the inode lock.
*/ */
static void __cachefiles_unmark_inode_in_use(struct cachefiles_object *object, 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; inode->i_flags &= ~S_KERNEL_FILE;
trace_cachefiles_mark_inactive(object, inode); trace_cachefiles_mark_inactive(object, inode);
} }
static void cachefiles_do_unmark_inode_in_use(struct cachefiles_object *object, 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); inode_lock(inode);
__cachefiles_unmark_inode_in_use(object, dentry); __cachefiles_unmark_inode_in_use(object, inode);
inode_unlock(inode); inode_unlock(inode);
} }
...@@ -77,14 +69,12 @@ void cachefiles_unmark_inode_in_use(struct cachefiles_object *object, ...@@ -77,14 +69,12 @@ void cachefiles_unmark_inode_in_use(struct cachefiles_object *object,
struct cachefiles_cache *cache = object->volume->cache; struct cachefiles_cache *cache = object->volume->cache;
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
if (inode) { cachefiles_do_unmark_inode_in_use(object, inode);
cachefiles_do_unmark_inode_in_use(object, file->f_path.dentry);
if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) { if (!test_bit(CACHEFILES_OBJECT_USING_TMPFILE, &object->flags)) {
atomic_long_add(inode->i_blocks, &cache->b_released); atomic_long_add(inode->i_blocks, &cache->b_released);
if (atomic_inc_return(&cache->f_released)) if (atomic_inc_return(&cache->f_released))
cachefiles_state_changed(cache); cachefiles_state_changed(cache);
}
} }
} }
...@@ -164,8 +154,11 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, ...@@ -164,8 +154,11 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
inode_lock(d_inode(subdir)); inode_lock(d_inode(subdir));
inode_unlock(d_inode(dir)); 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; goto mark_error;
}
inode_unlock(d_inode(subdir)); inode_unlock(d_inode(subdir));
...@@ -224,9 +217,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, ...@@ -224,9 +217,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
void cachefiles_put_directory(struct dentry *dir) void cachefiles_put_directory(struct dentry *dir)
{ {
if (dir) { if (dir) {
inode_lock(dir->d_inode); cachefiles_do_unmark_inode_in_use(NULL, d_inode(dir));
__cachefiles_unmark_inode_in_use(NULL, dir);
inode_unlock(dir->d_inode);
dput(dir); dput(dir);
} }
} }
...@@ -410,7 +401,7 @@ int cachefiles_bury_object(struct cachefiles_cache *cache, ...@@ -410,7 +401,7 @@ int cachefiles_bury_object(struct cachefiles_cache *cache,
"Rename failed with error %d", ret); "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); unlock_rename(cache->graveyard, dir);
dput(grave); dput(grave);
_leave(" = 0"); _leave(" = 0");
...@@ -451,84 +442,72 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object) ...@@ -451,84 +442,72 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object)
const struct cred *saved_cred; const struct cred *saved_cred;
struct dentry *fan = volume->fanout[(u8)object->cookie->key_hash]; struct dentry *fan = volume->fanout[(u8)object->cookie->key_hash];
struct file *file; struct file *file;
struct path path; const struct path parentpath = { .mnt = cache->mnt, .dentry = fan };
uint64_t ni_size; uint64_t ni_size;
long ret; long ret;
cachefiles_begin_secure(cache, &saved_cred); cachefiles_begin_secure(cache, &saved_cred);
path.mnt = cache->mnt;
ret = cachefiles_inject_write_error(); ret = cachefiles_inject_write_error();
if (ret == 0) if (ret == 0) {
path.dentry = vfs_tmpfile(&init_user_ns, fan, S_IFREG, O_RDWR); file = vfs_tmpfile_open(&init_user_ns, &parentpath, S_IFREG,
else O_RDWR | O_LARGEFILE | O_DIRECT,
path.dentry = ERR_PTR(ret); cache->cache_cred);
if (IS_ERR(path.dentry)) { ret = PTR_ERR_OR_ZERO(file);
trace_cachefiles_vfs_error(object, d_inode(fan), PTR_ERR(path.dentry), }
if (ret) {
trace_cachefiles_vfs_error(object, d_inode(fan), ret,
cachefiles_trace_tmpfile_error); cachefiles_trace_tmpfile_error);
if (PTR_ERR(path.dentry) == -EIO) if (ret == -EIO)
cachefiles_io_error_obj(object, "Failed to create tmpfile"); cachefiles_io_error_obj(object, "Failed to create tmpfile");
file = ERR_CAST(path.dentry); goto err;
goto out;
} }
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)) { /* This is a newly created file with no other possible user */
file = ERR_PTR(-EBUSY); if (!cachefiles_mark_inode_in_use(object, file_inode(file)))
goto out_dput; WARN_ON(1);
}
ret = cachefiles_ondemand_init_object(object); ret = cachefiles_ondemand_init_object(object);
if (ret < 0) { if (ret < 0)
file = ERR_PTR(ret); goto err_unuse;
goto out_unuse;
}
ni_size = object->cookie->object_size; ni_size = object->cookie->object_size;
ni_size = round_up(ni_size, CACHEFILES_DIO_BLOCK_SIZE); ni_size = round_up(ni_size, CACHEFILES_DIO_BLOCK_SIZE);
if (ni_size > 0) { 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); cachefiles_trunc_expand_tmpfile);
ret = cachefiles_inject_write_error(); ret = cachefiles_inject_write_error();
if (ret == 0) if (ret == 0)
ret = vfs_truncate(&path, ni_size); ret = vfs_truncate(&file->f_path, ni_size);
if (ret < 0) { if (ret < 0) {
trace_cachefiles_vfs_error( trace_cachefiles_vfs_error(
object, d_backing_inode(path.dentry), ret, object, file_inode(file), ret,
cachefiles_trace_trunc_error); cachefiles_trace_trunc_error);
file = ERR_PTR(ret); goto err_unuse;
goto out_unuse;
} }
} }
file = open_with_fake_path(&path, O_RDWR | O_LARGEFILE | O_DIRECT, ret = -EINVAL;
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;
}
if (unlikely(!file->f_op->read_iter) || if (unlikely(!file->f_op->read_iter) ||
unlikely(!file->f_op->write_iter)) { unlikely(!file->f_op->write_iter)) {
fput(file); fput(file);
pr_notice("Cache does not support read_iter and write_iter\n"); pr_notice("Cache does not support read_iter and write_iter\n");
file = ERR_PTR(-EINVAL); goto err_unuse;
goto out_unuse;
} }
goto out_dput;
out_unuse:
cachefiles_do_unmark_inode_in_use(object, path.dentry);
out_dput:
dput(path.dentry);
out: out:
cachefiles_end_secure(cache, saved_cred); cachefiles_end_secure(cache, saved_cred);
return file; return file;
err_unuse:
cachefiles_do_unmark_inode_in_use(object, file_inode(file));
fput(file);
err:
file = ERR_PTR(ret);
goto out;
} }
/* /*
...@@ -569,8 +548,11 @@ static bool cachefiles_open_file(struct cachefiles_object *object, ...@@ -569,8 +548,11 @@ static bool cachefiles_open_file(struct cachefiles_object *object,
_enter("%pd", dentry); _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; return false;
}
/* We need to open a file interface onto a data file now as we can't do /* 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 * it on demand because writeback called from do_exit() sees
...@@ -624,7 +606,7 @@ static bool cachefiles_open_file(struct cachefiles_object *object, ...@@ -624,7 +606,7 @@ static bool cachefiles_open_file(struct cachefiles_object *object,
error_fput: error_fput:
fput(file); fput(file);
error: error:
cachefiles_do_unmark_inode_in_use(object, dentry); cachefiles_do_unmark_inode_in_use(object, d_inode(dentry));
dput(dentry); dput(dentry);
return false; return false;
} }
......
...@@ -3249,8 +3249,10 @@ void d_genocide(struct dentry *parent) ...@@ -3249,8 +3249,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) ||
......
...@@ -120,7 +120,7 @@ static int ext2_create (struct user_namespace * mnt_userns, ...@@ -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, ...@@ -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,
......
...@@ -2854,7 +2854,7 @@ static int ext4_mknod(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -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, 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;
...@@ -2876,7 +2876,7 @@ static int ext4_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -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_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;
...@@ -2887,7 +2887,7 @@ static int ext4_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -2887,7 +2887,7 @@ static int ext4_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
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);
......
...@@ -845,7 +845,7 @@ static int f2fs_mknod(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -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, 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, ...@@ -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 @@ static int __f2fs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -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, 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,
......
...@@ -529,7 +529,7 @@ static int get_security_context(struct dentry *entry, umode_t mode, ...@@ -529,7 +529,7 @@ static int get_security_context(struct dentry *entry, umode_t mode,
*/ */
static int fuse_create_open(struct inode *dir, struct dentry *entry, static int fuse_create_open(struct inode *dir, struct dentry *entry,
struct file *file, unsigned int flags, struct file *file, unsigned int flags,
umode_t mode) umode_t mode, u32 opcode)
{ {
int err; int err;
struct inode *inode; struct inode *inode;
...@@ -573,7 +573,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, ...@@ -573,7 +573,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID; inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID;
} }
args.opcode = FUSE_CREATE; args.opcode = opcode;
args.nodeid = get_node_id(dir); args.nodeid = get_node_id(dir);
args.in_numargs = 2; args.in_numargs = 2;
args.in_args[0].size = sizeof(inarg); args.in_args[0].size = sizeof(inarg);
...@@ -676,7 +676,7 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry, ...@@ -676,7 +676,7 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
if (fc->no_create) if (fc->no_create)
goto mknod; goto mknod;
err = fuse_create_open(dir, entry, file, flags, mode); err = fuse_create_open(dir, entry, file, flags, mode, FUSE_CREATE);
if (err == -ENOSYS) { if (err == -ENOSYS) {
fc->no_create = 1; fc->no_create = 1;
goto mknod; goto mknod;
...@@ -802,6 +802,23 @@ static int fuse_create(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -802,6 +802,23 @@ static int fuse_create(struct user_namespace *mnt_userns, struct inode *dir,
return fuse_mknod(&init_user_ns, dir, entry, mode, 0); return fuse_mknod(&init_user_ns, dir, entry, mode, 0);
} }
static int fuse_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
struct file *file, umode_t mode)
{
struct fuse_conn *fc = get_fuse_conn(dir);
int err;
if (fc->no_tmpfile)
return -EOPNOTSUPP;
err = fuse_create_open(dir, file->f_path.dentry, file, file->f_flags, mode, FUSE_TMPFILE);
if (err == -ENOSYS) {
fc->no_tmpfile = 1;
err = -EOPNOTSUPP;
}
return err;
}
static int fuse_mkdir(struct user_namespace *mnt_userns, struct inode *dir, static int fuse_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *entry, umode_t mode) struct dentry *entry, umode_t mode)
{ {
...@@ -1913,6 +1930,7 @@ static const struct inode_operations fuse_dir_inode_operations = { ...@@ -1913,6 +1930,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
.setattr = fuse_setattr, .setattr = fuse_setattr,
.create = fuse_create, .create = fuse_create,
.atomic_open = fuse_atomic_open, .atomic_open = fuse_atomic_open,
.tmpfile = fuse_tmpfile,
.mknod = fuse_mknod, .mknod = fuse_mknod,
.permission = fuse_permission, .permission = fuse_permission,
.getattr = fuse_getattr, .getattr = fuse_getattr,
......
...@@ -784,6 +784,9 @@ struct fuse_conn { ...@@ -784,6 +784,9 @@ struct fuse_conn {
/* Does the filesystem support per inode DAX? */ /* Does the filesystem support per inode DAX? */
unsigned int inode_dax:1; unsigned int inode_dax:1;
/* Is tmpfile not implemented by fs? */
unsigned int no_tmpfile:1;
/** The number of requests waiting for completion */ /** The number of requests waiting for completion */
atomic_t num_waiting; atomic_t num_waiting;
......
...@@ -1013,33 +1013,18 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, ...@@ -1013,33 +1013,18 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
/* /*
* File creation. Allocate an inode, and we're done.. * File creation. Allocate an inode, and we're done..
*/ */
static int do_hugetlbfs_mknod(struct inode *dir, static int hugetlbfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, struct dentry *dentry, umode_t mode, dev_t dev)
umode_t mode,
dev_t dev,
bool tmpfile)
{ {
struct inode *inode; struct inode *inode;
int error = -ENOSPC;
inode = hugetlbfs_get_inode(dir->i_sb, dir, mode, dev); inode = hugetlbfs_get_inode(dir->i_sb, dir, mode, dev);
if (inode) { if (!inode)
dir->i_ctime = dir->i_mtime = current_time(dir); return -ENOSPC;
if (tmpfile) { dir->i_ctime = dir->i_mtime = current_time(dir);
d_tmpfile(dentry, inode); d_instantiate(dentry, inode);
} else { dget(dentry);/* Extra count - pin the dentry in core */
d_instantiate(dentry, inode); return 0;
dget(dentry);/* Extra count - pin the dentry in core */
}
error = 0;
}
return error;
}
static int hugetlbfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
struct dentry *dentry, umode_t mode, dev_t dev)
{
return do_hugetlbfs_mknod(dir, dentry, mode, dev, false);
} }
static int hugetlbfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir, static int hugetlbfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
...@@ -1060,10 +1045,17 @@ static int hugetlbfs_create(struct user_namespace *mnt_userns, ...@@ -1060,10 +1045,17 @@ 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)
{ {
return do_hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0, true); struct inode *inode;
inode = hugetlbfs_get_inode(dir->i_sb, dir, mode | S_IFREG, 0);
if (!inode)
return -ENOSPC;
dir->i_ctime = dir->i_mtime = current_time(dir);
d_tmpfile(file, inode);
return finish_open_simple(file, 0);
} }
static int hugetlbfs_symlink(struct user_namespace *mnt_userns, static int hugetlbfs_symlink(struct user_namespace *mnt_userns,
......
...@@ -53,16 +53,16 @@ static int minix_mknod(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -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,
......
...@@ -3583,72 +3583,94 @@ static int do_open(struct nameidata *nd, ...@@ -3583,72 +3583,94 @@ 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.
*/ */
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, file, mode);
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); * vfs_tmpfile_open - open a tmpfile for kernel internal use
return ERR_PTR(error); * @mnt_userns: user namespace of the mount the inode was found from
* @parentpath: path of the base directory
* @mode: mode of the new tmpfile
* @open_flag: flags
* @cred: credentials for open
*
* Create and open a temporary file. The file is not accounted in nr_files,
* hence this is only for kernel internal use, and must not be installed into
* file tables or such.
*/
struct file *vfs_tmpfile_open(struct user_namespace *mnt_userns,
const struct path *parentpath,
umode_t mode, int open_flag, const struct cred *cred)
{
struct file *file;
int error;
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;
} }
EXPORT_SYMBOL(vfs_tmpfile); EXPORT_SYMBOL(vfs_tmpfile_open);
static int do_tmpfile(struct nameidata *nd, unsigned flags, static int do_tmpfile(struct nameidata *nd, unsigned flags,
const struct open_flags *op, const struct open_flags *op,
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:
......
...@@ -193,11 +193,11 @@ static int ovl_copy_fileattr(struct inode *inode, const struct path *old, ...@@ -193,11 +193,11 @@ static int ovl_copy_fileattr(struct inode *inode, const struct path *old,
return ovl_real_fileattr_set(new, &newfa); return ovl_real_fileattr_set(new, &newfa);
} }
static int ovl_copy_up_data(struct ovl_fs *ofs, const struct path *old, static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
const struct path *new, loff_t len) struct file *new_file, loff_t len)
{ {
struct path datapath;
struct file *old_file; struct file *old_file;
struct file *new_file;
loff_t old_pos = 0; loff_t old_pos = 0;
loff_t new_pos = 0; loff_t new_pos = 0;
loff_t cloned; loff_t cloned;
...@@ -206,23 +206,18 @@ static int ovl_copy_up_data(struct ovl_fs *ofs, const struct path *old, ...@@ -206,23 +206,18 @@ static int ovl_copy_up_data(struct ovl_fs *ofs, const struct path *old,
bool skip_hole = false; bool skip_hole = false;
int error = 0; int error = 0;
if (len == 0) ovl_path_lowerdata(dentry, &datapath);
return 0; if (WARN_ON(datapath.dentry == NULL))
return -EIO;
old_file = ovl_path_open(old, O_LARGEFILE | O_RDONLY); old_file = ovl_path_open(&datapath, O_LARGEFILE | O_RDONLY);
if (IS_ERR(old_file)) if (IS_ERR(old_file))
return PTR_ERR(old_file); return PTR_ERR(old_file);
new_file = ovl_path_open(new, O_LARGEFILE | O_WRONLY);
if (IS_ERR(new_file)) {
error = PTR_ERR(new_file);
goto out_fput;
}
/* Try to use clone_file_range to clone up within the same fs */ /* Try to use clone_file_range to clone up within the same fs */
cloned = do_clone_file_range(old_file, 0, new_file, 0, len, 0); cloned = do_clone_file_range(old_file, 0, new_file, 0, len, 0);
if (cloned == len) if (cloned == len)
goto out; goto out_fput;
/* Couldn't clone, so now we try to copy the data */ /* Couldn't clone, so now we try to copy the data */
/* Check if lower fs supports seek operation */ /* Check if lower fs supports seek operation */
...@@ -282,10 +277,8 @@ static int ovl_copy_up_data(struct ovl_fs *ofs, const struct path *old, ...@@ -282,10 +277,8 @@ static int ovl_copy_up_data(struct ovl_fs *ofs, const struct path *old,
len -= bytes; len -= bytes;
} }
out:
if (!error && ovl_should_sync(ofs)) if (!error && ovl_should_sync(ofs))
error = vfs_fsync(new_file, 0); error = vfs_fsync(new_file, 0);
fput(new_file);
out_fput: out_fput:
fput(old_file); fput(old_file);
return error; return error;
...@@ -556,30 +549,31 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c) ...@@ -556,30 +549,31 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
return err; return err;
} }
static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp) static int ovl_copy_up_data(struct ovl_copy_up_ctx *c, const struct path *temp)
{ {
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb); struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
struct inode *inode = d_inode(c->dentry); struct file *new_file;
struct path upperpath, datapath;
int err; int err;
ovl_path_upper(c->dentry, &upperpath); if (!S_ISREG(c->stat.mode) || c->metacopy || !c->stat.size)
if (WARN_ON(upperpath.dentry != NULL)) return 0;
return -EIO;
upperpath.dentry = temp; new_file = ovl_path_open(temp, O_LARGEFILE | O_WRONLY);
if (IS_ERR(new_file))
return PTR_ERR(new_file);
/* err = ovl_copy_up_file(ofs, c->dentry, new_file, c->stat.size);
* Copy up data first and then xattrs. Writing data after fput(new_file);
* xattrs will remove security.capability xattr automatically.
*/ return err;
if (S_ISREG(c->stat.mode) && !c->metacopy) { }
ovl_path_lowerdata(c->dentry, &datapath);
err = ovl_copy_up_data(ofs, &datapath, &upperpath, static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
c->stat.size); {
if (err) struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
return err; struct inode *inode = d_inode(c->dentry);
} struct path upperpath = { .mnt = ovl_upper_mnt(ofs), .dentry = temp };
int err;
err = ovl_copy_xattr(c->dentry->d_sb, &c->lowerpath, temp); err = ovl_copy_xattr(c->dentry->d_sb, &c->lowerpath, temp);
if (err) if (err)
...@@ -662,6 +656,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c) ...@@ -662,6 +656,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb); struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
struct inode *inode; struct inode *inode;
struct inode *udir = d_inode(c->destdir), *wdir = d_inode(c->workdir); struct inode *udir = d_inode(c->destdir), *wdir = d_inode(c->workdir);
struct path path = { .mnt = ovl_upper_mnt(ofs) };
struct dentry *temp, *upper; struct dentry *temp, *upper;
struct ovl_cu_creds cc; struct ovl_cu_creds cc;
int err; int err;
...@@ -688,7 +683,16 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c) ...@@ -688,7 +683,16 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
if (IS_ERR(temp)) if (IS_ERR(temp))
goto unlock; goto unlock;
err = ovl_copy_up_inode(c, temp); /*
* Copy up data first and then xattrs. Writing data after
* xattrs will remove security.capability xattr automatically.
*/
path.dentry = temp;
err = ovl_copy_up_data(c, &path);
if (err)
goto cleanup;
err = ovl_copy_up_metadata(c, temp);
if (err) if (err)
goto cleanup; goto cleanup;
...@@ -732,6 +736,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) ...@@ -732,6 +736,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb); struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
struct inode *udir = d_inode(c->destdir); struct inode *udir = d_inode(c->destdir);
struct dentry *temp, *upper; struct dentry *temp, *upper;
struct file *tmpfile;
struct ovl_cu_creds cc; struct ovl_cu_creds cc;
int err; int err;
...@@ -739,15 +744,22 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) ...@@ -739,15 +744,22 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
if (err) if (err)
return err; return err;
temp = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode); tmpfile = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode);
ovl_revert_cu_creds(&cc); ovl_revert_cu_creds(&cc);
if (IS_ERR(temp)) if (IS_ERR(tmpfile))
return PTR_ERR(temp); return PTR_ERR(tmpfile);
err = ovl_copy_up_inode(c, temp); temp = tmpfile->f_path.dentry;
if (!c->metacopy && c->stat.size) {
err = ovl_copy_up_file(ofs, c->dentry, tmpfile, c->stat.size);
if (err)
return err;
}
err = ovl_copy_up_metadata(c, temp);
if (err) if (err)
goto out_dput; goto out_fput;
inode_lock_nested(udir, I_MUTEX_PARENT); inode_lock_nested(udir, I_MUTEX_PARENT);
...@@ -761,16 +773,14 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) ...@@ -761,16 +773,14 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
inode_unlock(udir); inode_unlock(udir);
if (err) if (err)
goto out_dput; goto out_fput;
if (!c->metacopy) if (!c->metacopy)
ovl_set_upperdata(d_inode(c->dentry)); ovl_set_upperdata(d_inode(c->dentry));
ovl_inode_update(d_inode(c->dentry), temp); ovl_inode_update(d_inode(c->dentry), dget(temp));
return 0; out_fput:
fput(tmpfile);
out_dput:
dput(temp);
return err; return err;
} }
...@@ -899,7 +909,7 @@ static ssize_t ovl_getxattr_value(const struct path *path, char *name, char **va ...@@ -899,7 +909,7 @@ static ssize_t ovl_getxattr_value(const struct path *path, char *name, char **va
static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
{ {
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb); struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
struct path upperpath, datapath; struct path upperpath;
int err; int err;
char *capability = NULL; char *capability = NULL;
ssize_t cap_size; ssize_t cap_size;
...@@ -908,10 +918,6 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) ...@@ -908,10 +918,6 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
if (WARN_ON(upperpath.dentry == NULL)) if (WARN_ON(upperpath.dentry == NULL))
return -EIO; return -EIO;
ovl_path_lowerdata(c->dentry, &datapath);
if (WARN_ON(datapath.dentry == NULL))
return -EIO;
if (c->stat.size) { if (c->stat.size) {
err = cap_size = ovl_getxattr_value(&upperpath, XATTR_NAME_CAPS, err = cap_size = ovl_getxattr_value(&upperpath, XATTR_NAME_CAPS,
&capability); &capability);
...@@ -919,7 +925,7 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) ...@@ -919,7 +925,7 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
goto out; goto out;
} }
err = ovl_copy_up_data(ofs, &datapath, &upperpath, c->stat.size); err = ovl_copy_up_data(c, &upperpath);
if (err) if (err)
goto out_free; goto out_free;
......
...@@ -310,14 +310,16 @@ static inline int ovl_do_whiteout(struct ovl_fs *ofs, ...@@ -310,14 +310,16 @@ static inline int ovl_do_whiteout(struct ovl_fs *ofs,
return err; return err;
} }
static inline struct dentry *ovl_do_tmpfile(struct ovl_fs *ofs, static inline struct file *ovl_do_tmpfile(struct ovl_fs *ofs,
struct dentry *dentry, umode_t mode) struct dentry *dentry, umode_t mode)
{ {
struct dentry *ret = vfs_tmpfile(ovl_upper_mnt_userns(ofs), dentry, mode, 0); struct path path = { .mnt = ovl_upper_mnt(ofs), .dentry = dentry };
int err = PTR_ERR_OR_ZERO(ret); struct file *file = vfs_tmpfile_open(ovl_upper_mnt_userns(ofs), &path, mode,
O_LARGEFILE | O_WRONLY, current_cred());
int err = PTR_ERR_OR_ZERO(file);
pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err); pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err);
return ret; return file;
} }
static inline struct dentry *ovl_lookup_upper(struct ovl_fs *ofs, static inline struct dentry *ovl_lookup_upper(struct ovl_fs *ofs,
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/posix_acl_xattr.h> #include <linux/posix_acl_xattr.h>
#include <linux/exportfs.h> #include <linux/exportfs.h>
#include <linux/file.h>
#include "overlayfs.h" #include "overlayfs.h"
MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
...@@ -1369,7 +1370,8 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, ...@@ -1369,7 +1370,8 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
const struct path *workpath) const struct path *workpath)
{ {
struct vfsmount *mnt = ovl_upper_mnt(ofs); struct vfsmount *mnt = ovl_upper_mnt(ofs);
struct dentry *temp, *workdir; struct dentry *workdir;
struct file *tmpfile;
bool rename_whiteout; bool rename_whiteout;
bool d_type; bool d_type;
int fh_type; int fh_type;
...@@ -1405,10 +1407,10 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, ...@@ -1405,10 +1407,10 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
pr_warn("upper fs needs to support d_type.\n"); pr_warn("upper fs needs to support d_type.\n");
/* Check if upper/work fs supports O_TMPFILE */ /* Check if upper/work fs supports O_TMPFILE */
temp = ovl_do_tmpfile(ofs, ofs->workdir, S_IFREG | 0); tmpfile = ovl_do_tmpfile(ofs, ofs->workdir, S_IFREG | 0);
ofs->tmpfile = !IS_ERR(temp); ofs->tmpfile = !IS_ERR(tmpfile);
if (ofs->tmpfile) if (ofs->tmpfile)
dput(temp); fput(tmpfile);
else else
pr_warn("upper fs does not support tmpfile.\n"); pr_warn("upper fs does not support tmpfile.\n");
......
...@@ -146,15 +146,15 @@ static int ramfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -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 = {
......
...@@ -424,8 +424,9 @@ static void unlock_2_inodes(struct inode *inode1, struct inode *inode2) ...@@ -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, ...@@ -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, ...@@ -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);
......
...@@ -626,7 +626,7 @@ static int udf_create(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -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, ...@@ -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,
......
...@@ -167,7 +167,7 @@ xfs_generic_create( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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( ...@@ -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 *
...@@ -1090,10 +1090,12 @@ STATIC int ...@@ -1090,10 +1090,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 = {
......
...@@ -16,6 +16,7 @@ ...@@ -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 *); ...@@ -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 *);
......
...@@ -2004,8 +2004,9 @@ static inline int vfs_whiteout(struct user_namespace *mnt_userns, ...@@ -2004,8 +2004,9 @@ static inline int vfs_whiteout(struct user_namespace *mnt_userns,
WHITEOUT_DEV); WHITEOUT_DEV);
} }
struct dentry *vfs_tmpfile(struct user_namespace *mnt_userns, struct file *vfs_tmpfile_open(struct user_namespace *mnt_userns,
struct dentry *dentry, umode_t mode, int open_flag); const struct path *parentpath,
umode_t mode, int open_flag, const struct cred *cred);
int vfs_mkobj(struct dentry *, umode_t, int vfs_mkobj(struct dentry *, umode_t,
int (*f)(struct dentry *, umode_t, void *), int (*f)(struct dentry *, umode_t, void *),
...@@ -2170,7 +2171,7 @@ struct inode_operations { ...@@ -2170,7 +2171,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,
...@@ -2783,6 +2784,15 @@ extern int finish_open(struct file *file, struct dentry *dentry, ...@@ -2783,6 +2784,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);
......
...@@ -194,6 +194,9 @@ ...@@ -194,6 +194,9 @@
* - add FUSE_SECURITY_CTX init flag * - add FUSE_SECURITY_CTX init flag
* - add security context to create, mkdir, symlink, and mknod requests * - add security context to create, mkdir, symlink, and mknod requests
* - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX * - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX
*
* 7.37
* - add FUSE_TMPFILE
*/ */
#ifndef _LINUX_FUSE_H #ifndef _LINUX_FUSE_H
...@@ -229,7 +232,7 @@ ...@@ -229,7 +232,7 @@
#define FUSE_KERNEL_VERSION 7 #define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */ /** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 36 #define FUSE_KERNEL_MINOR_VERSION 37
/** The node ID of the root inode */ /** The node ID of the root inode */
#define FUSE_ROOT_ID 1 #define FUSE_ROOT_ID 1
...@@ -537,6 +540,7 @@ enum fuse_opcode { ...@@ -537,6 +540,7 @@ enum fuse_opcode {
FUSE_SETUPMAPPING = 48, FUSE_SETUPMAPPING = 48,
FUSE_REMOVEMAPPING = 49, FUSE_REMOVEMAPPING = 49,
FUSE_SYNCFS = 50, FUSE_SYNCFS = 50,
FUSE_TMPFILE = 51,
/* CUSE specific operations */ /* CUSE specific operations */
CUSE_INIT = 4096, CUSE_INIT = 4096,
......
...@@ -2916,7 +2916,7 @@ shmem_mknod(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -2916,7 +2916,7 @@ shmem_mknod(struct user_namespace *mnt_userns, struct inode *dir,
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;
...@@ -2931,9 +2931,9 @@ shmem_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, ...@@ -2931,9 +2931,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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册