Skip to content

Commit

Permalink
Merge tag 'fuse-fixes-5.2-rc4' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/mszeredi/fuse

Pull fuse fixes from Miklos Szeredi:
 "This fixes a leaked inode lock in an error cleanup path and a data
  consistency issue with copy_file_range().

  It also adds a new flag for the WRITE request that allows userspace
  filesystems to clear suid/sgid bits on the file if necessary"

* tag 'fuse-fixes-5.2-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: extract helper for range writeback
  fuse: fix copy_file_range() in the writeback case
  fuse: add FUSE_WRITE_KILL_PRIV
  fuse: fallocate: fix return with locked inode
  • Loading branch information
torvalds committed Jun 6, 2019
2 parents 459aa07 + 26eb3ba commit 2117585
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 12 deletions.
43 changes: 32 additions & 11 deletions fs/fuse/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1377,10 +1377,17 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
if (err && !nbytes)
break;

if (write)
if (write) {
if (!capable(CAP_FSETID)) {
struct fuse_write_in *inarg;

inarg = &req->misc.write.in;
inarg->write_flags |= FUSE_WRITE_KILL_PRIV;
}
nres = fuse_send_write(req, io, pos, nbytes, owner);
else
} else {
nres = fuse_send_read(req, io, pos, nbytes, owner);
}

if (!io->async)
fuse_release_user_pages(req, io->should_dirty);
Expand Down Expand Up @@ -3014,6 +3021,16 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
return ret;
}

static int fuse_writeback_range(struct inode *inode, loff_t start, loff_t end)
{
int err = filemap_write_and_wait_range(inode->i_mapping, start, end);

if (!err)
fuse_sync_writes(inode);

return err;
}

static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
loff_t length)
{
Expand Down Expand Up @@ -3042,20 +3059,18 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
inode_lock(inode);
if (mode & FALLOC_FL_PUNCH_HOLE) {
loff_t endbyte = offset + length - 1;
err = filemap_write_and_wait_range(inode->i_mapping,
offset, endbyte);

err = fuse_writeback_range(inode, offset, endbyte);
if (err)
goto out;

fuse_sync_writes(inode);
}
}

if (!(mode & FALLOC_FL_KEEP_SIZE) &&
offset + length > i_size_read(inode)) {
err = inode_newsize_ok(inode, offset + length);
if (err)
return err;
goto out;
}

if (!(mode & FALLOC_FL_KEEP_SIZE))
Expand Down Expand Up @@ -3103,6 +3118,7 @@ static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in,
{
struct fuse_file *ff_in = file_in->private_data;
struct fuse_file *ff_out = file_out->private_data;
struct inode *inode_in = file_inode(file_in);
struct inode *inode_out = file_inode(file_out);
struct fuse_inode *fi_out = get_fuse_inode(inode_out);
struct fuse_conn *fc = ff_in->fc;
Expand All @@ -3126,15 +3142,20 @@ static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in,
if (fc->no_copy_file_range)
return -EOPNOTSUPP;

if (fc->writeback_cache) {
inode_lock(inode_in);
err = fuse_writeback_range(inode_in, pos_in, pos_in + len);
inode_unlock(inode_in);
if (err)
return err;
}

inode_lock(inode_out);

if (fc->writeback_cache) {
err = filemap_write_and_wait_range(inode_out->i_mapping,
pos_out, pos_out + len);
err = fuse_writeback_range(inode_out, pos_out, pos_out + len);
if (err)
goto out;

fuse_sync_writes(inode_out);
}

if (is_unstable)
Expand Down
7 changes: 6 additions & 1 deletion include/uapi/linux/fuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@
* 7.30
* - add FUSE_EXPLICIT_INVAL_DATA
* - add FUSE_IOCTL_COMPAT_X32
*
* 7.31
* - add FUSE_WRITE_KILL_PRIV flag
*/

#ifndef _LINUX_FUSE_H
Expand Down Expand Up @@ -165,7 +168,7 @@
#define FUSE_KERNEL_VERSION 7

/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 30
#define FUSE_KERNEL_MINOR_VERSION 31

/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
Expand Down Expand Up @@ -327,9 +330,11 @@ struct fuse_file_lock {
*
* FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
* FUSE_WRITE_LOCKOWNER: lock_owner field is valid
* FUSE_WRITE_KILL_PRIV: kill suid and sgid bits
*/
#define FUSE_WRITE_CACHE (1 << 0)
#define FUSE_WRITE_LOCKOWNER (1 << 1)
#define FUSE_WRITE_KILL_PRIV (1 << 2)

/**
* Read flags
Expand Down

0 comments on commit 2117585

Please sign in to comment.