mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-27 13:00:25 +09:00
ANDROID: fuse-bpf: support FUSE_LSEEK
Adds support for lseek via fuse-bpf Bug: 224855060 Test: bpf_test_lseek Signed-off-by: Daniel Rosenberg <drosen@google.com> Change-Id: Ic282940d53b9bb44a291cb3a5dfe09847b4e5c9a
This commit is contained in:
@@ -403,6 +403,65 @@ void *fuse_flush_finalize(struct fuse_args *fa, struct file *file, fl_owner_t id
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int fuse_lseek_initialize(struct fuse_args *fa, struct fuse_lseek_io *flio,
|
||||
struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
struct fuse_file *fuse_file = file->private_data;
|
||||
|
||||
flio->fli = (struct fuse_lseek_in) {
|
||||
.fh = fuse_file->fh,
|
||||
.offset = offset,
|
||||
.whence = whence,
|
||||
};
|
||||
|
||||
*fa = (struct fuse_args) {
|
||||
.nodeid = get_node_id(file->f_inode),
|
||||
.opcode = FUSE_LSEEK,
|
||||
.in_numargs = 1,
|
||||
.in_args[0].size = sizeof(flio->fli),
|
||||
.in_args[0].value = &flio->fli,
|
||||
.out_numargs = 1,
|
||||
.out_args[0].size = sizeof(flio->flo),
|
||||
.out_args[0].value = &flio->flo,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_lseek_backing(struct fuse_args *fa, struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
const struct fuse_lseek_in *fli = fa->in_args[0].value;
|
||||
struct fuse_lseek_out *flo = fa->out_args[0].value;
|
||||
struct fuse_file *fuse_file = file->private_data;
|
||||
struct file *backing_file = fuse_file->backing_file;
|
||||
loff_t ret;
|
||||
|
||||
/* TODO: Handle changing of the file handle */
|
||||
if (offset == 0) {
|
||||
if (whence == SEEK_CUR)
|
||||
return file->f_pos;
|
||||
|
||||
if (whence == SEEK_SET)
|
||||
return vfs_setpos(file, 0, 0);
|
||||
}
|
||||
|
||||
inode_lock(file->f_inode);
|
||||
backing_file->f_pos = file->f_pos;
|
||||
ret = vfs_llseek(backing_file, fli->offset, fli->whence);
|
||||
flo->offset = ret;
|
||||
inode_unlock(file->f_inode);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *fuse_lseek_finalize(struct fuse_args *fa, struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
struct fuse_lseek_out *flo = fa->out_args[0].value;
|
||||
|
||||
if (!fa->error_in)
|
||||
file->f_pos = flo->offset;
|
||||
return ERR_PTR(flo->offset);
|
||||
}
|
||||
|
||||
int fuse_copy_file_range_initialize(struct fuse_args *fa, struct fuse_copy_file_range_io *fcf,
|
||||
struct file *file_in, loff_t pos_in, struct file *file_out,
|
||||
loff_t pos_out, size_t len, unsigned int flags)
|
||||
|
||||
@@ -2738,6 +2738,17 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence)
|
||||
{
|
||||
loff_t retval;
|
||||
struct inode *inode = file_inode(file);
|
||||
#ifdef CONFIG_FUSE_BPF
|
||||
struct fuse_err_ret fer;
|
||||
|
||||
fer = fuse_bpf_backing(inode, struct fuse_lseek_io,
|
||||
fuse_lseek_initialize,
|
||||
fuse_lseek_backing,
|
||||
fuse_lseek_finalize,
|
||||
file, offset, whence);
|
||||
if (fer.ret)
|
||||
return PTR_ERR(fer.result);
|
||||
#endif
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
|
||||
@@ -1433,6 +1433,16 @@ int fuse_flush_backing(struct fuse_args *fa, struct file *file, fl_owner_t id);
|
||||
void *fuse_flush_finalize(struct fuse_args *fa,
|
||||
struct file *file, fl_owner_t id);
|
||||
|
||||
struct fuse_lseek_io {
|
||||
struct fuse_lseek_in fli;
|
||||
struct fuse_lseek_out flo;
|
||||
};
|
||||
|
||||
int fuse_lseek_initialize(struct fuse_args *fa, struct fuse_lseek_io *fli,
|
||||
struct file *file, loff_t offset, int whence);
|
||||
int fuse_lseek_backing(struct fuse_args *fa, struct file *file, loff_t offset, int whence);
|
||||
void *fuse_lseek_finalize(struct fuse_args *fa, struct file *file, loff_t offset, int whence);
|
||||
|
||||
struct fuse_copy_file_range_io {
|
||||
struct fuse_copy_file_range_in fci;
|
||||
struct fuse_write_out fwo;
|
||||
|
||||
@@ -289,6 +289,13 @@ int trace_daemon(struct fuse_args *fa)
|
||||
return FUSE_BPF_BACKING;
|
||||
}
|
||||
|
||||
case FUSE_LSEEK | FUSE_PREFILTER: {
|
||||
const struct fuse_lseek_in *fli = fa->in_args[0].value;
|
||||
|
||||
bpf_printk("lseek type:%d, offset:%lld", fli->whence, fli->offset);
|
||||
return FUSE_BPF_BACKING;
|
||||
}
|
||||
|
||||
default:
|
||||
if (fa->opcode & FUSE_PREFILTER)
|
||||
bpf_printk("prefilter *** UNKNOWN *** opcode: %d",
|
||||
|
||||
@@ -1450,6 +1450,48 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int bpf_test_lseek(const char *mount_dir)
|
||||
{
|
||||
const char *file = "real";
|
||||
const char *test_data = "data";
|
||||
int result = TEST_FAILURE;
|
||||
int src_fd = -1;
|
||||
int bpf_fd = -1;
|
||||
int fuse_dev = -1;
|
||||
int fd = -1;
|
||||
|
||||
TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
|
||||
src_fd != -1);
|
||||
TEST(fd = openat(src_fd, file, O_CREAT | O_RDWR | O_CLOEXEC, 0777),
|
||||
fd != -1);
|
||||
TESTEQUAL(write(fd, test_data, strlen(test_data)), strlen(test_data));
|
||||
TESTSYSCALL(close(fd));
|
||||
fd = -1;
|
||||
TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
|
||||
&bpf_fd, NULL, NULL), 0);
|
||||
TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
|
||||
|
||||
TEST(fd = s_open(s_path(s(mount_dir), s(file)), O_RDONLY | O_CLOEXEC),
|
||||
fd != -1);
|
||||
TESTEQUAL(lseek(fd, 3, SEEK_SET), 3);
|
||||
TESTEQUAL(bpf_test_trace("lseek"), 0);
|
||||
TESTEQUAL(lseek(fd, 5, SEEK_END), 9);
|
||||
TESTEQUAL(bpf_test_trace("lseek"), 0);
|
||||
TESTEQUAL(lseek(fd, 1, SEEK_CUR), 10);
|
||||
TESTEQUAL(bpf_test_trace("lseek"), 0);
|
||||
TESTEQUAL(lseek(fd, 1, SEEK_DATA), 1);
|
||||
TESTEQUAL(bpf_test_trace("lseek"), 0);
|
||||
result = TEST_SUCCESS;
|
||||
out:
|
||||
close(fd);
|
||||
umount(mount_dir);
|
||||
close(fuse_dev);
|
||||
close(bpf_fd);
|
||||
close(src_fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int parse_options(int argc, char *const *argv)
|
||||
{
|
||||
signed char c;
|
||||
@@ -1553,6 +1595,7 @@ int main(int argc, char *argv[])
|
||||
MAKE_TEST(readdir_perms_test),
|
||||
MAKE_TEST(inotify_test),
|
||||
MAKE_TEST(bpf_test_statfs),
|
||||
MAKE_TEST(bpf_test_lseek),
|
||||
};
|
||||
#undef MAKE_TEST
|
||||
|
||||
|
||||
@@ -346,6 +346,13 @@ int trace_test(struct fuse_args *fa)
|
||||
return FUSE_BPF_BACKING;
|
||||
}
|
||||
|
||||
case FUSE_LSEEK | FUSE_PREFILTER: {
|
||||
const struct fuse_lseek_in *fli = fa->in_args[0].value;
|
||||
|
||||
bpf_printk("lseek type:%d, offset:%lld", fli->whence, fli->offset);
|
||||
return FUSE_BPF_BACKING;
|
||||
}
|
||||
|
||||
default:
|
||||
bpf_printk("Unknown opcode %d", fa->opcode);
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user