1
0
Fork 0

fuse fixes for 5.2-rc4

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQSQHSd0lITzzeNWNm3h3BK/laaZPAUCXPjJMAAKCRDh3BK/laaZ
 PDzlAP9CgHZsgCVfB5afSb9rqY9Fdzr3LxSOwaCXavA5XGJAVQEAhjldnlMOjEvO
 LrDEPG3zziJuQgCmMJ9xXoBYYjkCwgo=
 =nff/
 -----END PGP SIGNATURE-----

Merge tag 'fuse-fixes-5.2-rc4' of git://git.kernel.org/pub/scm/linux/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
hifive-unleashed-5.2
Linus Torvalds 2019-06-06 12:25:56 -07:00
commit 211758573b
2 changed files with 38 additions and 12 deletions

View File

@ -1377,10 +1377,17 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
if (err && !nbytes) if (err && !nbytes)
break; 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); nres = fuse_send_write(req, io, pos, nbytes, owner);
else } else {
nres = fuse_send_read(req, io, pos, nbytes, owner); nres = fuse_send_read(req, io, pos, nbytes, owner);
}
if (!io->async) if (!io->async)
fuse_release_user_pages(req, io->should_dirty); fuse_release_user_pages(req, io->should_dirty);
@ -3014,6 +3021,16 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
return ret; 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, static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
loff_t length) loff_t length)
{ {
@ -3042,12 +3059,10 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
inode_lock(inode); inode_lock(inode);
if (mode & FALLOC_FL_PUNCH_HOLE) { if (mode & FALLOC_FL_PUNCH_HOLE) {
loff_t endbyte = offset + length - 1; 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) if (err)
goto out; goto out;
fuse_sync_writes(inode);
} }
} }
@ -3055,7 +3070,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset,
offset + length > i_size_read(inode)) { offset + length > i_size_read(inode)) {
err = inode_newsize_ok(inode, offset + length); err = inode_newsize_ok(inode, offset + length);
if (err) if (err)
return err; goto out;
} }
if (!(mode & FALLOC_FL_KEEP_SIZE)) if (!(mode & FALLOC_FL_KEEP_SIZE))
@ -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_in = file_in->private_data;
struct fuse_file *ff_out = file_out->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 inode *inode_out = file_inode(file_out);
struct fuse_inode *fi_out = get_fuse_inode(inode_out); struct fuse_inode *fi_out = get_fuse_inode(inode_out);
struct fuse_conn *fc = ff_in->fc; struct fuse_conn *fc = ff_in->fc;
@ -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) if (fc->no_copy_file_range)
return -EOPNOTSUPP; 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); inode_lock(inode_out);
if (fc->writeback_cache) { if (fc->writeback_cache) {
err = filemap_write_and_wait_range(inode_out->i_mapping, err = fuse_writeback_range(inode_out, pos_out, pos_out + len);
pos_out, pos_out + len);
if (err) if (err)
goto out; goto out;
fuse_sync_writes(inode_out);
} }
if (is_unstable) if (is_unstable)

View File

@ -130,6 +130,9 @@
* 7.30 * 7.30
* - add FUSE_EXPLICIT_INVAL_DATA * - add FUSE_EXPLICIT_INVAL_DATA
* - add FUSE_IOCTL_COMPAT_X32 * - add FUSE_IOCTL_COMPAT_X32
*
* 7.31
* - add FUSE_WRITE_KILL_PRIV flag
*/ */
#ifndef _LINUX_FUSE_H #ifndef _LINUX_FUSE_H
@ -165,7 +168,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 30 #define FUSE_KERNEL_MINOR_VERSION 31
/** The node ID of the root inode */ /** The node ID of the root inode */
#define FUSE_ROOT_ID 1 #define FUSE_ROOT_ID 1
@ -327,9 +330,11 @@ struct fuse_file_lock {
* *
* FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed
* FUSE_WRITE_LOCKOWNER: lock_owner field is valid * 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_CACHE (1 << 0)
#define FUSE_WRITE_LOCKOWNER (1 << 1) #define FUSE_WRITE_LOCKOWNER (1 << 1)
#define FUSE_WRITE_KILL_PRIV (1 << 2)
/** /**
* Read flags * Read flags