mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 06:43:09 +00:00
fuse: implement splice read/write passthrough
This allows passing fstests generic/249 and generic/591. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
57e1176e60
commit
5ca7346861
@ -1723,6 +1723,31 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
return fuse_cache_write_iter(iocb, from);
|
||||
}
|
||||
|
||||
static ssize_t fuse_splice_read(struct file *in, loff_t *ppos,
|
||||
struct pipe_inode_info *pipe, size_t len,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct fuse_file *ff = in->private_data;
|
||||
|
||||
/* FOPEN_DIRECT_IO overrides FOPEN_PASSTHROUGH */
|
||||
if (fuse_file_passthrough(ff) && !(ff->open_flags & FOPEN_DIRECT_IO))
|
||||
return fuse_passthrough_splice_read(in, ppos, pipe, len, flags);
|
||||
else
|
||||
return filemap_splice_read(in, ppos, pipe, len, flags);
|
||||
}
|
||||
|
||||
static ssize_t fuse_splice_write(struct pipe_inode_info *pipe, struct file *out,
|
||||
loff_t *ppos, size_t len, unsigned int flags)
|
||||
{
|
||||
struct fuse_file *ff = out->private_data;
|
||||
|
||||
/* FOPEN_DIRECT_IO overrides FOPEN_PASSTHROUGH */
|
||||
if (fuse_file_passthrough(ff) && !(ff->open_flags & FOPEN_DIRECT_IO))
|
||||
return fuse_passthrough_splice_write(pipe, out, ppos, len, flags);
|
||||
else
|
||||
return iter_file_splice_write(pipe, out, ppos, len, flags);
|
||||
}
|
||||
|
||||
static void fuse_writepage_free(struct fuse_writepage_args *wpa)
|
||||
{
|
||||
struct fuse_args_pages *ap = &wpa->ia.ap;
|
||||
@ -3303,8 +3328,8 @@ static const struct file_operations fuse_file_operations = {
|
||||
.lock = fuse_file_lock,
|
||||
.get_unmapped_area = thp_get_unmapped_area,
|
||||
.flock = fuse_file_flock,
|
||||
.splice_read = filemap_splice_read,
|
||||
.splice_write = iter_file_splice_write,
|
||||
.splice_read = fuse_splice_read,
|
||||
.splice_write = fuse_splice_write,
|
||||
.unlocked_ioctl = fuse_file_ioctl,
|
||||
.compat_ioctl = fuse_file_compat_ioctl,
|
||||
.poll = fuse_file_poll,
|
||||
|
@ -1468,5 +1468,11 @@ static inline struct file *fuse_file_passthrough(struct fuse_file *ff)
|
||||
|
||||
ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *iter);
|
||||
ssize_t fuse_passthrough_write_iter(struct kiocb *iocb, struct iov_iter *iter);
|
||||
ssize_t fuse_passthrough_splice_read(struct file *in, loff_t *ppos,
|
||||
struct pipe_inode_info *pipe,
|
||||
size_t len, unsigned int flags);
|
||||
ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
|
||||
struct file *out, loff_t *ppos,
|
||||
size_t len, unsigned int flags);
|
||||
|
||||
#endif /* _FS_FUSE_I_H */
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <linux/file.h>
|
||||
#include <linux/backing-file.h>
|
||||
#include <linux/splice.h>
|
||||
|
||||
static void fuse_file_accessed(struct file *file)
|
||||
{
|
||||
@ -79,6 +80,50 @@ ssize_t fuse_passthrough_write_iter(struct kiocb *iocb,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t fuse_passthrough_splice_read(struct file *in, loff_t *ppos,
|
||||
struct pipe_inode_info *pipe,
|
||||
size_t len, unsigned int flags)
|
||||
{
|
||||
struct fuse_file *ff = in->private_data;
|
||||
struct file *backing_file = fuse_file_passthrough(ff);
|
||||
struct backing_file_ctx ctx = {
|
||||
.cred = ff->cred,
|
||||
.user_file = in,
|
||||
.accessed = fuse_file_accessed,
|
||||
};
|
||||
|
||||
pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
|
||||
backing_file, ppos ? *ppos : 0, len, flags);
|
||||
|
||||
return backing_file_splice_read(backing_file, ppos, pipe, len, flags,
|
||||
&ctx);
|
||||
}
|
||||
|
||||
ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
|
||||
struct file *out, loff_t *ppos,
|
||||
size_t len, unsigned int flags)
|
||||
{
|
||||
struct fuse_file *ff = out->private_data;
|
||||
struct file *backing_file = fuse_file_passthrough(ff);
|
||||
struct inode *inode = file_inode(out);
|
||||
ssize_t ret;
|
||||
struct backing_file_ctx ctx = {
|
||||
.cred = ff->cred,
|
||||
.user_file = out,
|
||||
.end_write = fuse_file_modified,
|
||||
};
|
||||
|
||||
pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
|
||||
backing_file, ppos ? *ppos : 0, len, flags);
|
||||
|
||||
inode_lock(inode);
|
||||
ret = backing_file_splice_write(pipe, backing_file, ppos, len, flags,
|
||||
&ctx);
|
||||
inode_unlock(inode);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
|
||||
{
|
||||
if (fb && refcount_inc_not_zero(&fb->count))
|
||||
|
Loading…
Reference in New Issue
Block a user