diff options
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/Kconfig | 1 | ||||
-rw-r--r-- | fs/fuse/Makefile | 1 | ||||
-rw-r--r-- | fs/fuse/cuse.c | 3 | ||||
-rw-r--r-- | fs/fuse/dev.c | 10 | ||||
-rw-r--r-- | fs/fuse/file.c | 72 |
5 files changed, 61 insertions, 26 deletions
diff --git a/fs/fuse/Kconfig b/fs/fuse/Kconfig index 76f09ce7e5b2..24fc5a5c1b97 100644 --- a/fs/fuse/Kconfig +++ b/fs/fuse/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config FUSE_FS tristate "FUSE (Filesystem in Userspace) support" select FS_POSIX_ACL diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index f7b807bc1027..9485019c2a14 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Makefile for the FUSE filesystem. # diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c index 4b41df1d4642..bab7a0db81dd 100644 --- a/fs/fuse/cuse.c +++ b/fs/fuse/cuse.c @@ -1,11 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * CUSE: Character device in Userspace * * Copyright (C) 2008-2009 SUSE Linux Products GmbH * Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org> * - * This file is released under the GPLv2. - * * CUSE enables character devices to be implemented from userland much * like FUSE allows filesystems. On initialization /dev/cuse is * created. By opening the file and replying to the CUSE_INIT request diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 24ea19cfe07e..ea8237513dfa 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1317,16 +1317,6 @@ static ssize_t fuse_dev_do_read(struct fuse_dev *fud, struct file *file, unsigned reqsize; unsigned int hash; - /* - * Require sane minimum read buffer - that has capacity for fixed part - * of any request header + negotated max_write room for data. If the - * requirement is not satisfied return EINVAL to the filesystem server - * to indicate that it is not following FUSE server/client contract. - * Don't dequeue / abort any request. - */ - if (nbytes < max_t(size_t, FUSE_MIN_READ_BUFFER, 4096 + fc->max_write)) - return -EINVAL; - restart: spin_lock(&fiq->waitq.lock); err = -EAGAIN; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 3959f08279e6..5ae2828beb00 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -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); @@ -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) { @@ -3042,12 +3059,10 @@ 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); } } @@ -3055,7 +3070,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, 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)) @@ -3097,12 +3112,13 @@ out: return err; } -static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, - size_t len, unsigned int flags) +static ssize_t __fuse_copy_file_range(struct file *file_in, loff_t pos_in, + struct file *file_out, loff_t pos_out, + size_t len, unsigned int flags) { 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; @@ -3126,15 +3142,27 @@ static ssize_t fuse_copy_file_range(struct file *file_in, loff_t pos_in, if (fc->no_copy_file_range) return -EOPNOTSUPP; + if (file_inode(file_in)->i_sb != file_inode(file_out)->i_sb) + return -EXDEV; + + 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); + err = file_modified(file_out); + if (err) + goto 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) @@ -3169,10 +3197,26 @@ out: clear_bit(FUSE_I_SIZE_UNSTABLE, &fi_out->state); inode_unlock(inode_out); + file_accessed(file_in); return err; } +static ssize_t fuse_copy_file_range(struct file *src_file, loff_t src_off, + struct file *dst_file, loff_t dst_off, + size_t len, unsigned int flags) +{ + ssize_t ret; + + ret = __fuse_copy_file_range(src_file, src_off, dst_file, dst_off, + len, flags); + + if (ret == -EOPNOTSUPP || ret == -EXDEV) + ret = generic_copy_file_range(src_file, src_off, dst_file, + dst_off, len, flags); + return ret; +} + static const struct file_operations fuse_file_operations = { .llseek = fuse_file_llseek, .read_iter = fuse_file_read_iter, |