ANDROID: fuse-bpf: Support fuse_splice_read/write fully
Need to support fuse_splice_read and fuse_splice_write in both fuse bpf and fuse passthrough modes. Bug: 349258571 Test: fuse_test Change-Id: I641b917d3decc4be1eea7ea39fac2b1f50c7e41b Signed-off-by: Paul Lawrence <paullawrence@google.com>
This commit is contained in:
@@ -1001,6 +1001,22 @@ ssize_t fuse_splice_read_backing(struct file *in, loff_t *ppos,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t fuse_splice_write_backing(struct pipe_inode_info *pipe,
|
||||
struct file *out, loff_t *ppos, size_t len, unsigned long flags)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct fuse_file *ff = out->private_data;
|
||||
|
||||
inode_lock(file_inode(out));
|
||||
file_start_write(ff->backing_file);
|
||||
ret = iter_file_splice_write(pipe, ff->backing_file, ppos, len, flags);
|
||||
file_end_write(ff->backing_file);
|
||||
if (ret > 0)
|
||||
fuse_copyattr(out, ff->backing_file);
|
||||
inode_unlock(file_inode(out));
|
||||
return ret;
|
||||
}
|
||||
|
||||
long fuse_backing_ioctl(struct file *file, unsigned int command, unsigned long arg, int flags)
|
||||
{
|
||||
struct fuse_file *ff = file->private_data;
|
||||
|
||||
+8
-1
@@ -15,6 +15,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/splice.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/uio.h>
|
||||
@@ -1843,9 +1844,9 @@ static ssize_t fuse_splice_read(struct file *in, loff_t *ppos,
|
||||
struct pipe_inode_info *pipe, size_t len,
|
||||
unsigned int flags)
|
||||
{
|
||||
#ifdef CONFIG_FUSE_BPF
|
||||
struct fuse_file *ff = in->private_data;
|
||||
|
||||
#ifdef CONFIG_FUSE_BPF
|
||||
/* TODO - this is simply passthrough, not a proper BPF filter */
|
||||
if (ff->backing_file)
|
||||
return fuse_splice_read_backing(in, ppos, pipe, len, flags);
|
||||
@@ -1863,6 +1864,12 @@ static ssize_t fuse_splice_write(struct pipe_inode_info *pipe, struct file *out,
|
||||
{
|
||||
struct fuse_file *ff = out->private_data;
|
||||
|
||||
#ifdef CONFIG_FUSE_BPF
|
||||
/* TODO - this is simply passthrough, not a proper BPF filter */
|
||||
if (ff->backing_file)
|
||||
return fuse_splice_write_backing(pipe, out, ppos, len, flags);
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
|
||||
@@ -1815,6 +1815,8 @@ void *fuse_file_write_iter_finalize(struct fuse_bpf_args *fa,
|
||||
|
||||
ssize_t fuse_splice_read_backing(struct file *in, loff_t *ppos,
|
||||
struct pipe_inode_info *pipe, size_t len, unsigned long flags);
|
||||
ssize_t fuse_splice_write_backing(struct pipe_inode_info *pipe,
|
||||
struct file *out, loff_t *ppos, size_t len, unsigned long flags);
|
||||
|
||||
long fuse_backing_ioctl(struct file *file, unsigned int command, unsigned long arg, int flags);
|
||||
|
||||
|
||||
@@ -2114,6 +2114,60 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int splice_test(const char *mount_dir)
|
||||
{
|
||||
const char *in_name = "in";
|
||||
const char *out_name = "out";
|
||||
const int splice_size = 4096;
|
||||
|
||||
int result = TEST_FAILURE;
|
||||
int file_fd = -1;
|
||||
int src_fd = -1;
|
||||
int fuse_dev = -1;
|
||||
int in_fd = -1;
|
||||
int out_fd = -1;
|
||||
int pipefd[2] = {-1, -1};
|
||||
|
||||
TEST(file_fd = s_creat(s_path(s(ft_src), s(in_name)), 0777),
|
||||
file_fd != -1);
|
||||
TESTSYSCALL(fallocate(file_fd, 0, 0, splice_size));
|
||||
TESTSYSCALL(close(file_fd));
|
||||
file_fd = -1;
|
||||
|
||||
TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
|
||||
src_fd != -1);
|
||||
TEST(fuse_dev = open("/dev/fuse", O_RDWR | O_CLOEXEC), fuse_dev != -1);
|
||||
TESTEQUAL(mount_fuse(mount_dir, -1, src_fd, &fuse_dev), 0);
|
||||
|
||||
TESTSYSCALL(pipe(pipefd));
|
||||
TEST(in_fd = s_open(s_path(s(mount_dir), s(in_name)), O_RDONLY),
|
||||
in_fd != -1);
|
||||
TEST(out_fd = s_creat(s_path(s(mount_dir), s(out_name)), 0777),
|
||||
out_fd != -1);
|
||||
TESTEQUAL(splice(in_fd, NULL, pipefd[1], NULL, splice_size, 0),
|
||||
splice_size);
|
||||
TESTEQUAL(splice(pipefd[0], NULL, out_fd, NULL, splice_size, 0),
|
||||
splice_size);
|
||||
TESTSYSCALL(close(in_fd));
|
||||
in_fd = -1;
|
||||
TESTSYSCALL(close(out_fd));
|
||||
out_fd = -1;
|
||||
TESTSYSCALL(close(pipefd[0]));
|
||||
pipefd[0] = -1;
|
||||
TESTSYSCALL(close(pipefd[1]));
|
||||
pipefd[1] = -1;
|
||||
result = TEST_SUCCESS;
|
||||
out:
|
||||
umount(mount_dir);
|
||||
close(fuse_dev);
|
||||
close(src_fd);
|
||||
close(in_fd);
|
||||
close(out_fd);
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that fuse passthrough correctly traverses a mount point on the lower fs
|
||||
*/
|
||||
@@ -2288,6 +2342,7 @@ int main(int argc, char *argv[])
|
||||
MAKE_TEST(bpf_test_create_and_remove_bpf),
|
||||
MAKE_TEST(bpf_test_mkdir_and_remove_bpf),
|
||||
MAKE_TEST(bpf_test_readahead),
|
||||
MAKE_TEST(splice_test),
|
||||
MAKE_TEST(bpf_test_follow_mounts),
|
||||
};
|
||||
#undef MAKE_TEST
|
||||
|
||||
Reference in New Issue
Block a user