Skip to content

Commit 5ca7346

Browse files
amir73ilMiklos Szeredi
authored andcommitted
fuse: implement splice read/write passthrough
This allows passing fstests generic/249 and generic/591. Signed-off-by: Amir Goldstein <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 57e1176 commit 5ca7346

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

fs/fuse/file.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,6 +1723,31 @@ static ssize_t fuse_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
17231723
return fuse_cache_write_iter(iocb, from);
17241724
}
17251725

1726+
static ssize_t fuse_splice_read(struct file *in, loff_t *ppos,
1727+
struct pipe_inode_info *pipe, size_t len,
1728+
unsigned int flags)
1729+
{
1730+
struct fuse_file *ff = in->private_data;
1731+
1732+
/* FOPEN_DIRECT_IO overrides FOPEN_PASSTHROUGH */
1733+
if (fuse_file_passthrough(ff) && !(ff->open_flags & FOPEN_DIRECT_IO))
1734+
return fuse_passthrough_splice_read(in, ppos, pipe, len, flags);
1735+
else
1736+
return filemap_splice_read(in, ppos, pipe, len, flags);
1737+
}
1738+
1739+
static ssize_t fuse_splice_write(struct pipe_inode_info *pipe, struct file *out,
1740+
loff_t *ppos, size_t len, unsigned int flags)
1741+
{
1742+
struct fuse_file *ff = out->private_data;
1743+
1744+
/* FOPEN_DIRECT_IO overrides FOPEN_PASSTHROUGH */
1745+
if (fuse_file_passthrough(ff) && !(ff->open_flags & FOPEN_DIRECT_IO))
1746+
return fuse_passthrough_splice_write(pipe, out, ppos, len, flags);
1747+
else
1748+
return iter_file_splice_write(pipe, out, ppos, len, flags);
1749+
}
1750+
17261751
static void fuse_writepage_free(struct fuse_writepage_args *wpa)
17271752
{
17281753
struct fuse_args_pages *ap = &wpa->ia.ap;
@@ -3303,8 +3328,8 @@ static const struct file_operations fuse_file_operations = {
33033328
.lock = fuse_file_lock,
33043329
.get_unmapped_area = thp_get_unmapped_area,
33053330
.flock = fuse_file_flock,
3306-
.splice_read = filemap_splice_read,
3307-
.splice_write = iter_file_splice_write,
3331+
.splice_read = fuse_splice_read,
3332+
.splice_write = fuse_splice_write,
33083333
.unlocked_ioctl = fuse_file_ioctl,
33093334
.compat_ioctl = fuse_file_compat_ioctl,
33103335
.poll = fuse_file_poll,

fs/fuse/fuse_i.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,5 +1468,11 @@ static inline struct file *fuse_file_passthrough(struct fuse_file *ff)
14681468

14691469
ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *iter);
14701470
ssize_t fuse_passthrough_write_iter(struct kiocb *iocb, struct iov_iter *iter);
1471+
ssize_t fuse_passthrough_splice_read(struct file *in, loff_t *ppos,
1472+
struct pipe_inode_info *pipe,
1473+
size_t len, unsigned int flags);
1474+
ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
1475+
struct file *out, loff_t *ppos,
1476+
size_t len, unsigned int flags);
14711477

14721478
#endif /* _FS_FUSE_I_H */

fs/fuse/passthrough.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <linux/file.h>
1111
#include <linux/backing-file.h>
12+
#include <linux/splice.h>
1213

1314
static void fuse_file_accessed(struct file *file)
1415
{
@@ -79,6 +80,50 @@ ssize_t fuse_passthrough_write_iter(struct kiocb *iocb,
7980
return ret;
8081
}
8182

83+
ssize_t fuse_passthrough_splice_read(struct file *in, loff_t *ppos,
84+
struct pipe_inode_info *pipe,
85+
size_t len, unsigned int flags)
86+
{
87+
struct fuse_file *ff = in->private_data;
88+
struct file *backing_file = fuse_file_passthrough(ff);
89+
struct backing_file_ctx ctx = {
90+
.cred = ff->cred,
91+
.user_file = in,
92+
.accessed = fuse_file_accessed,
93+
};
94+
95+
pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
96+
backing_file, ppos ? *ppos : 0, len, flags);
97+
98+
return backing_file_splice_read(backing_file, ppos, pipe, len, flags,
99+
&ctx);
100+
}
101+
102+
ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
103+
struct file *out, loff_t *ppos,
104+
size_t len, unsigned int flags)
105+
{
106+
struct fuse_file *ff = out->private_data;
107+
struct file *backing_file = fuse_file_passthrough(ff);
108+
struct inode *inode = file_inode(out);
109+
ssize_t ret;
110+
struct backing_file_ctx ctx = {
111+
.cred = ff->cred,
112+
.user_file = out,
113+
.end_write = fuse_file_modified,
114+
};
115+
116+
pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
117+
backing_file, ppos ? *ppos : 0, len, flags);
118+
119+
inode_lock(inode);
120+
ret = backing_file_splice_write(pipe, backing_file, ppos, len, flags,
121+
&ctx);
122+
inode_unlock(inode);
123+
124+
return ret;
125+
}
126+
82127
struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
83128
{
84129
if (fb && refcount_inc_not_zero(&fb->count))

0 commit comments

Comments
 (0)