Skip to content

Commit

Permalink
Merge tag 'fuse-update-5.11' of git://git.kernel.org/pub/scm/linux/ke…
Browse files Browse the repository at this point in the history
…rnel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi:

 - Improve performance of virtio-fs in mixed read/write workloads

 - Try to revalidate cache before returning EEXIST on exclusive create

 - Add a couple of miscellaneous bug fixes as well as some code cleanups

* tag 'fuse-update-5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: fix bad inode
  fuse: support SB_NOSEC flag to improve write performance
  fuse: add a flag FUSE_OPEN_KILL_SUIDGID for open() request
  fuse: don't send ATTR_MODE to kill suid/sgid for handle_killpriv_v2
  fuse: setattr should set FATTR_KILL_SUIDGID
  fuse: set FUSE_WRITE_KILL_SUIDGID in cached write path
  fuse: rename FUSE_WRITE_KILL_PRIV to FUSE_WRITE_KILL_SUIDGID
  fuse: introduce the notion of FUSE_HANDLE_KILLPRIV_V2
  fuse: always revalidate if exclusive create
  virtiofs: clean up error handling in virtio_fs_get_tree()
  fuse: add fuse_sb_destroy() helper
  fuse: simplify get_fuse_conn*()
  fuse: get rid of fuse_mount refcount
  virtiofs: simplify sb setup
  virtiofs fix leak in setup
  fuse: launder page should wait for page writeback
  • Loading branch information
torvalds committed Dec 17, 2020
2 parents ff49c86 + 5d069db commit 65de0b8
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 104 deletions.
6 changes: 6 additions & 0 deletions fs/fuse/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ struct posix_acl *fuse_get_acl(struct inode *inode, int type)
void *value = NULL;
struct posix_acl *acl;

if (fuse_is_bad(inode))
return ERR_PTR(-EIO);

if (!fc->posix_acl || fc->no_getxattr)
return NULL;

Expand Down Expand Up @@ -53,6 +56,9 @@ int fuse_set_acl(struct inode *inode, struct posix_acl *acl, int type)
const char *name;
int ret;

if (fuse_is_bad(inode))
return -EIO;

if (!fc->posix_acl || fc->no_setxattr)
return -EOPNOTSUPP;

Expand Down
60 changes: 51 additions & 9 deletions fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,10 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
int ret;

inode = d_inode_rcu(entry);
if (inode && is_bad_inode(inode))
if (inode && fuse_is_bad(inode))
goto invalid;
else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
(flags & LOOKUP_REVAL)) {
(flags & (LOOKUP_EXCL | LOOKUP_REVAL))) {
struct fuse_entry_out outarg;
FUSE_ARGS(args);
struct fuse_forget_link *forget;
Expand Down Expand Up @@ -328,12 +328,11 @@ static struct vfsmount *fuse_dentry_automount(struct path *path)
if (!fm)
goto out_put_fsc;

refcount_set(&fm->count, 1);
fsc->s_fs_info = fm;
sb = sget_fc(fsc, NULL, set_anon_super_fc);
if (IS_ERR(sb)) {
err = PTR_ERR(sb);
fuse_mount_put(fm);
kfree(fm);
goto out_put_fsc;
}
fm->fc = fuse_conn_get(fc);
Expand Down Expand Up @@ -463,6 +462,9 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
bool outarg_valid = true;
bool locked;

if (fuse_is_bad(dir))
return ERR_PTR(-EIO);

locked = fuse_lock_inode(dir);
err = fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name,
&outarg, &inode);
Expand Down Expand Up @@ -542,6 +544,12 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
inarg.flags = flags;
inarg.mode = mode;
inarg.umask = current_umask();

if (fm->fc->handle_killpriv_v2 && (flags & O_TRUNC) &&
!(flags & O_EXCL) && !capable(CAP_FSETID)) {
inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID;
}

args.opcode = FUSE_CREATE;
args.nodeid = get_node_id(dir);
args.in_numargs = 2;
Expand Down Expand Up @@ -606,6 +614,9 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
struct fuse_conn *fc = get_fuse_conn(dir);
struct dentry *res = NULL;

if (fuse_is_bad(dir))
return -EIO;

if (d_in_lookup(entry)) {
res = fuse_lookup(dir, entry, 0);
if (IS_ERR(res))
Expand Down Expand Up @@ -654,6 +665,9 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
int err;
struct fuse_forget_link *forget;

if (fuse_is_bad(dir))
return -EIO;

forget = fuse_alloc_forget();
if (!forget)
return -ENOMEM;
Expand Down Expand Up @@ -781,6 +795,9 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
struct fuse_mount *fm = get_fuse_mount(dir);
FUSE_ARGS(args);

if (fuse_is_bad(dir))
return -EIO;

args.opcode = FUSE_UNLINK;
args.nodeid = get_node_id(dir);
args.in_numargs = 1;
Expand Down Expand Up @@ -817,6 +834,9 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
struct fuse_mount *fm = get_fuse_mount(dir);
FUSE_ARGS(args);

if (fuse_is_bad(dir))
return -EIO;

args.opcode = FUSE_RMDIR;
args.nodeid = get_node_id(dir);
args.in_numargs = 1;
Expand Down Expand Up @@ -895,6 +915,9 @@ static int fuse_rename2(struct inode *olddir, struct dentry *oldent,
struct fuse_conn *fc = get_fuse_conn(olddir);
int err;

if (fuse_is_bad(olddir))
return -EIO;

if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
return -EINVAL;

Expand Down Expand Up @@ -1030,7 +1053,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
if (!err) {
if (fuse_invalid_attr(&outarg.attr) ||
(inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
make_bad_inode(inode);
fuse_make_bad(inode);
err = -EIO;
} else {
fuse_change_attributes(inode, &outarg.attr,
Expand Down Expand Up @@ -1232,6 +1255,9 @@ static int fuse_permission(struct inode *inode, int mask)
bool refreshed = false;
int err = 0;

if (fuse_is_bad(inode))
return -EIO;

if (!fuse_allow_current_process(fc))
return -EACCES;

Expand Down Expand Up @@ -1327,7 +1353,7 @@ static const char *fuse_get_link(struct dentry *dentry, struct inode *inode,
int err;

err = -EIO;
if (is_bad_inode(inode))
if (fuse_is_bad(inode))
goto out_err;

if (fc->cache_symlinks)
Expand Down Expand Up @@ -1375,7 +1401,7 @@ static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end,
struct fuse_conn *fc = get_fuse_conn(inode);
int err;

if (is_bad_inode(inode))
if (fuse_is_bad(inode))
return -EIO;

if (fc->no_fsyncdir)
Expand Down Expand Up @@ -1649,10 +1675,20 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
inarg.valid |= FATTR_FH;
inarg.fh = ff->fh;
}

/* Kill suid/sgid for non-directory chown unconditionally */
if (fc->handle_killpriv_v2 && !S_ISDIR(inode->i_mode) &&
attr->ia_valid & (ATTR_UID | ATTR_GID))
inarg.valid |= FATTR_KILL_SUIDGID;

if (attr->ia_valid & ATTR_SIZE) {
/* For mandatory locking in truncate */
inarg.valid |= FATTR_LOCKOWNER;
inarg.lock_owner = fuse_lock_owner_id(fc, current->files);

/* Kill suid/sgid for truncate only if no CAP_FSETID */
if (fc->handle_killpriv_v2 && !capable(CAP_FSETID))
inarg.valid |= FATTR_KILL_SUIDGID;
}
fuse_setattr_fill(fc, &args, inode, &inarg, &outarg);
err = fuse_simple_request(fm, &args);
Expand All @@ -1664,7 +1700,7 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,

if (fuse_invalid_attr(&outarg.attr) ||
(inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
make_bad_inode(inode);
fuse_make_bad(inode);
err = -EIO;
goto error;
}
Expand Down Expand Up @@ -1727,6 +1763,9 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
struct file *file = (attr->ia_valid & ATTR_FILE) ? attr->ia_file : NULL;
int ret;

if (fuse_is_bad(inode))
return -EIO;

if (!fuse_allow_current_process(get_fuse_conn(inode)))
return -EACCES;

Expand All @@ -1740,7 +1779,7 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
*
* This should be done on write(), truncate() and chown().
*/
if (!fc->handle_killpriv) {
if (!fc->handle_killpriv && !fc->handle_killpriv_v2) {
/*
* ia_mode calculation may have used stale i_mode.
* Refresh and recalculate.
Expand Down Expand Up @@ -1785,6 +1824,9 @@ static int fuse_getattr(const struct path *path, struct kstat *stat,
struct inode *inode = d_inode(path->dentry);
struct fuse_conn *fc = get_fuse_conn(inode);

if (fuse_is_bad(inode))
return -EIO;

if (!fuse_allow_current_process(fc)) {
if (!request_mask) {
/*
Expand Down
41 changes: 31 additions & 10 deletions fs/fuse/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, struct file *file,
inarg.flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY);
if (!fm->fc->atomic_o_trunc)
inarg.flags &= ~O_TRUNC;

if (fm->fc->handle_killpriv_v2 &&
(inarg.flags & O_TRUNC) && !capable(CAP_FSETID)) {
inarg.open_flags |= FUSE_OPEN_KILL_SUIDGID;
}

args.opcode = opcode;
args.nodeid = nodeid;
args.in_numargs = 1;
Expand Down Expand Up @@ -226,6 +232,9 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir)
bool dax_truncate = (file->f_flags & O_TRUNC) &&
fc->atomic_o_trunc && FUSE_IS_DAX(inode);

if (fuse_is_bad(inode))
return -EIO;

err = generic_file_open(inode, file);
if (err)
return err;
Expand Down Expand Up @@ -463,7 +472,7 @@ static int fuse_flush(struct file *file, fl_owner_t id)
FUSE_ARGS(args);
int err;

if (is_bad_inode(inode))
if (fuse_is_bad(inode))
return -EIO;

err = write_inode_now(inode, 1);
Expand Down Expand Up @@ -535,7 +544,7 @@ static int fuse_fsync(struct file *file, loff_t start, loff_t end,
struct fuse_conn *fc = get_fuse_conn(inode);
int err;

if (is_bad_inode(inode))
if (fuse_is_bad(inode))
return -EIO;

inode_lock(inode);
Expand Down Expand Up @@ -859,7 +868,7 @@ static int fuse_readpage(struct file *file, struct page *page)
int err;

err = -EIO;
if (is_bad_inode(inode))
if (fuse_is_bad(inode))
goto out;

err = fuse_do_readpage(file, page);
Expand Down Expand Up @@ -952,7 +961,7 @@ static void fuse_readahead(struct readahead_control *rac)
struct fuse_conn *fc = get_fuse_conn(inode);
unsigned int i, max_pages, nr_pages = 0;

if (is_bad_inode(inode))
if (fuse_is_bad(inode))
return;

max_pages = min_t(unsigned int, fc->max_pages,
Expand Down Expand Up @@ -1097,6 +1106,8 @@ static ssize_t fuse_send_write_pages(struct fuse_io_args *ia,

fuse_write_args_fill(ia, ff, pos, count);
ia->write.in.flags = fuse_write_flags(iocb);
if (fm->fc->handle_killpriv_v2 && !capable(CAP_FSETID))
ia->write.in.write_flags |= FUSE_WRITE_KILL_SUIDGID;

err = fuse_simple_request(fm, &ap->args);
if (!err && ia->write.out.size > count)
Expand Down Expand Up @@ -1260,17 +1271,24 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
ssize_t written_buffered = 0;
struct inode *inode = mapping->host;
ssize_t err;
struct fuse_conn *fc = get_fuse_conn(inode);
loff_t endbyte = 0;

if (get_fuse_conn(inode)->writeback_cache) {
if (fc->writeback_cache) {
/* Update size (EOF optimization) and mode (SUID clearing) */
err = fuse_update_attributes(mapping->host, file);
if (err)
return err;

if (fc->handle_killpriv_v2 &&
should_remove_suid(file_dentry(file))) {
goto writethrough;
}

return generic_file_write_iter(iocb, from);
}

writethrough:
inode_lock(inode);

/* We can write back this queue in page reclaim */
Expand Down Expand Up @@ -1451,7 +1469,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,

if (write) {
if (!capable(CAP_FSETID))
ia->write.in.write_flags |= FUSE_WRITE_KILL_PRIV;
ia->write.in.write_flags |= FUSE_WRITE_KILL_SUIDGID;

nres = fuse_send_write(ia, pos, nbytes, owner);
} else {
Expand Down Expand Up @@ -1555,7 +1573,7 @@ static ssize_t fuse_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
struct fuse_file *ff = file->private_data;
struct inode *inode = file_inode(file);

if (is_bad_inode(inode))
if (fuse_is_bad(inode))
return -EIO;

if (FUSE_IS_DAX(inode))
Expand All @@ -1573,7 +1591,7 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct fuse_file *ff = file->private_data;
struct inode *inode = file_inode(file);

if (is_bad_inode(inode))
if (fuse_is_bad(inode))
return -EIO;

if (FUSE_IS_DAX(inode))
Expand Down Expand Up @@ -2172,7 +2190,7 @@ static int fuse_writepages(struct address_space *mapping,
int err;

err = -EIO;
if (is_bad_inode(inode))
if (fuse_is_bad(inode))
goto out;

data.inode = inode;
Expand Down Expand Up @@ -2281,6 +2299,9 @@ static int fuse_launder_page(struct page *page)
int err = 0;
if (clear_page_dirty_for_io(page)) {
struct inode *inode = page->mapping->host;

/* Serialize with pending writeback for the same page */
fuse_wait_on_page_writeback(inode, page->index);
err = fuse_writepage_locked(page);
if (!err)
fuse_wait_on_page_writeback(inode, page->index);
Expand Down Expand Up @@ -2954,7 +2975,7 @@ long fuse_ioctl_common(struct file *file, unsigned int cmd,
if (!fuse_allow_current_process(fc))
return -EACCES;

if (is_bad_inode(inode))
if (fuse_is_bad(inode))
return -EIO;

return fuse_do_ioctl(file, cmd, arg, flags);
Expand Down
Loading

0 comments on commit 65de0b8

Please sign in to comment.