Files
msm-5.15/tools/testing/selftests/filesystems/fuse/fd_bpf.c
Daniel Rosenberg f5f4199c10 ANDROID: fuse-bpf v1.1
These patches extend FUSE to be able to act as a stacked filesystem. This
allows pure passthrough, where the fuse file system simply reflects the lower
filesystem, and also allows optional pre and post filtering in BPF and/or the
userspace daemon as needed. This can dramatically reduce or even eliminate
transitions to and from userspace.

See https://lwn.net/Articles/915717/

Note that this patch set has been extensively tested in
common-android13-5.10

This is a squash of these changes cherry-picked from common-android13-5.10

ANDROID: fuse-bpf: Make compile and pass test
ANDROID: fuse-bpf: set error_in to ENOENT in negative lookup
ANDROID: fuse-bpf: Add ability to run ranges of tests to fuse_test
ANDROID: fuse-bpf: Add test for lookup postfilter
ANDROID: fuse-bpf: readddir postfilter fixes
ANDROID: fix kernelci error in fs/fuse/dir.c
ANDROID: fuse-bpf: Fix RCU/reference issue
ANDROID: fuse-bpf: Always call revalidate for backing
ANDROID: fuse-bpf: Adjust backing handle funcs
ANDROID: fuse-bpf: Fix revalidate error path and backing handling
ANDROID: fuse-bpf: Fix use of get_fuse_inode
ANDROID: fuse: Don't use readdirplus w/ nodeid 0
ANDROID: fuse-bpf: Introduce readdirplus test case for fuse bpf
ANDROID: fuse-bpf: Make sure force_again flag is false by default
ANDROID: fuse-bpf: Make inodes with backing_fd reachable for regular FUSE fuse_iget
Revert "ANDROID: fuse-bpf: use target instead of parent inode to execute backing revalidate"
ANDROID: fuse-bpf: use target instead of parent inode to execute backing revalidate
ANDROID: fuse-bpf: Fix misuse of args.out_args
ANDROID: fuse-bpf: Fix non-fusebpf build
ANDROID: fuse-bpf: Use fuse_bpf_args in uapi
ANDROID: fuse-bpf: Fix read_iter
ANDROID: fuse-bpf: Use cache and refcount
ANDROID: fuse-bpf: Rename iocb_fuse to iocb_orig
ANDROID: fuse-bpf: Fix fixattr in rename
ANDROID: fuse-bpf: Fix readdir
ANDROID: fuse-bpf: Fix lseek return value for offset 0
ANDROID: fuse-bpf: fix read_iter and write_iter
ANDROID: fuse-bpf: fix special devices
ANDROID: fuse-bpf: support FUSE_LSEEK
ANDROID: fuse-bpf: Add support for FUSE_COPY_FILE_RANGE
ANDROID: fuse-bpf: Report errors to finalize
ANDROID: fuse-bpf: Avoid reusing uint64_t for file
ANDROID: fuse-bpf: Fix CONFIG_FUSE_BPF typo in FUSE_FSYNCDIR
ANDROID: fuse-bpf: Move fd operations to be synchronous
ANDROID: fuse-bpf: Invalidate if lower is unhashed
ANDROID: fuse-bpf: Move bpf earlier in fuse_permission
ANDROID: fuse-bpf: Update attributes on file write
ANDROID: fuse: allow mounting with no userspace daemon
ANDROID: fuse-bpf: Support FUSE_STATFS
ANDROID: fuse-bpf: Fix filldir
ANDROID: fuse-bpf: fix fuse_create_open_finalize
ANDROID: fuse: add bpf support for removexattr
ANDROID: fuse-bpf: Fix truncate
ANDROID: fuse-bpf: Support inotify
ANDROID: fuse-bpf: Make compile with CONFIG_FUSE but no CONFIG_FUSE_BPF
ANDROID: fuse-bpf: Fix perms on readdir
ANDROID: fuse: Fix umasking in backing
ANDROID: fs/fuse: Backing move returns EXDEV if TO not backed
ANDROID: bpf-fuse: Fix Setattr
ANDROID: fuse-bpf: Check if mkdir dentry setup
ANDROID: fuse-bpf: Close backing fds in fuse_dentry_revalidate
ANDROID: fuse-bpf: Close backing-fd on both paths
ANDROID: fuse-bpf: Partial fix for mmap'd files
ANDROID: fuse-bpf: Restore a missing const
ANDROID: Add fuse-bpf self tests
ANDROID: Add FUSE_BPF to gki_defconfig
ANDROID: fuse-bpf v1
ANDROID: fuse: Move functions in preparation for fuse-bpf

Bug: 202785178
Test: test_fuse passes on linux.
      On cuttlefish,
      atest android.scopedstorage.cts.host.ScopedStorageHostTest
      passes with fuse-bpf enabled and disabled
Change-Id: Idb099c281f9b39ff2c46fa3ebc63e508758416ee
Signed-off-by: Paul Lawrence <paullawrence@google.com>
Signed-off-by: Daniel Rosenberg <drosen@google.com>
2023-02-17 22:10:50 +00:00

253 lines
6.2 KiB
C

// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
// Copyright (c) 2021 Google LLC
#include "test_fuse_bpf.h"
SEC("maps") struct fuse_bpf_map test_map = {
BPF_MAP_TYPE_ARRAY,
sizeof(uint32_t),
sizeof(uint32_t),
1000,
};
SEC("maps") struct fuse_bpf_map test_map2 = {
BPF_MAP_TYPE_HASH,
sizeof(uint32_t),
sizeof(uint64_t),
76,
};
SEC("test_daemon") int trace_daemon(struct fuse_bpf_args *fa)
{
uint64_t uid_gid = bpf_get_current_uid_gid();
uint32_t uid = uid_gid & 0xffffffff;
uint64_t pid_tgid = bpf_get_current_pid_tgid();
uint32_t pid = pid_tgid & 0xffffffff;
uint32_t key = 23;
uint32_t *pvalue;
pvalue = bpf_map_lookup_elem(&test_map, &key);
if (pvalue) {
uint32_t value = *pvalue;
bpf_printk("pid %u uid %u value %u", pid, uid, value);
value++;
bpf_map_update_elem(&test_map, &key, &value, BPF_ANY);
}
switch (fa->opcode) {
case FUSE_ACCESS | FUSE_PREFILTER: {
bpf_printk("Access: %d", fa->nodeid);
return FUSE_BPF_BACKING;
}
case FUSE_GETATTR | FUSE_PREFILTER: {
const struct fuse_getattr_in *fgi = fa->in_args[0].value;
bpf_printk("Get Attr %d", fgi->fh);
return FUSE_BPF_BACKING;
}
case FUSE_SETATTR | FUSE_PREFILTER: {
const struct fuse_setattr_in *fsi = fa->in_args[0].value;
bpf_printk("Set Attr %d", fsi->fh);
return FUSE_BPF_BACKING;
}
case FUSE_OPENDIR | FUSE_PREFILTER: {
bpf_printk("Open Dir: %d", fa->nodeid);
return FUSE_BPF_BACKING;
}
case FUSE_READDIR | FUSE_PREFILTER: {
const struct fuse_read_in *fri = fa->in_args[0].value;
bpf_printk("Read Dir: fh: %lu", fri->fh, fri->offset);
return FUSE_BPF_BACKING;
}
case FUSE_LOOKUP | FUSE_PREFILTER: {
const char *name = fa->in_args[0].value;
bpf_printk("Lookup: %lx %s", fa->nodeid, name);
if (fa->nodeid == 1)
return FUSE_BPF_USER_FILTER | FUSE_BPF_BACKING;
else
return FUSE_BPF_BACKING;
}
case FUSE_MKNOD | FUSE_PREFILTER: {
const struct fuse_mknod_in *fmi = fa->in_args[0].value;
const char *name = fa->in_args[1].value;
bpf_printk("mknod %s %x %x", name, fmi->rdev | fmi->mode, fmi->umask);
return FUSE_BPF_BACKING;
}
case FUSE_MKDIR | FUSE_PREFILTER: {
const struct fuse_mkdir_in *fmi = fa->in_args[0].value;
const char *name = fa->in_args[1].value;
bpf_printk("mkdir: %s %x %x", name, fmi->mode, fmi->umask);
return FUSE_BPF_BACKING;
}
case FUSE_RMDIR | FUSE_PREFILTER: {
const char *name = fa->in_args[0].value;
bpf_printk("rmdir: %s", name);
return FUSE_BPF_BACKING;
}
case FUSE_RENAME | FUSE_PREFILTER: {
const char *oldname = fa->in_args[1].value;
const char *newname = fa->in_args[2].value;
bpf_printk("rename from %s", oldname);
bpf_printk("rename to %s", newname);
return FUSE_BPF_BACKING;
}
case FUSE_RENAME2 | FUSE_PREFILTER: {
const struct fuse_rename2_in *fri = fa->in_args[0].value;
uint32_t flags = fri->flags;
const char *oldname = fa->in_args[1].value;
const char *newname = fa->in_args[2].value;
bpf_printk("rename(%x) from %s", flags, oldname);
bpf_printk("rename to %s", newname);
return FUSE_BPF_BACKING;
}
case FUSE_UNLINK | FUSE_PREFILTER: {
const char *name = fa->in_args[0].value;
bpf_printk("unlink: %s", name);
return FUSE_BPF_BACKING;
}
case FUSE_LINK | FUSE_PREFILTER: {
const struct fuse_link_in *fli = fa->in_args[0].value;
const char *dst_name = fa->in_args[1].value;
bpf_printk("Link: %d %s", fli->oldnodeid, dst_name);
return FUSE_BPF_BACKING;
}
case FUSE_SYMLINK | FUSE_PREFILTER: {
const char *link_name = fa->in_args[0].value;
const char *link_dest = fa->in_args[1].value;
bpf_printk("symlink from %s", link_name);
bpf_printk("symlink to %s", link_dest);
return FUSE_BPF_BACKING;
}
case FUSE_READLINK | FUSE_PREFILTER: {
const char *link_name = fa->in_args[0].value;
bpf_printk("readlink from %s", link_name);
return FUSE_BPF_BACKING;
}
case FUSE_RELEASE | FUSE_PREFILTER: {
const struct fuse_release_in *fri = fa->in_args[0].value;
bpf_printk("Release: %d", fri->fh);
return FUSE_BPF_BACKING;
}
case FUSE_RELEASEDIR | FUSE_PREFILTER: {
const struct fuse_release_in *fri = fa->in_args[0].value;
bpf_printk("Release Dir: %d", fri->fh);
return FUSE_BPF_BACKING;
}
case FUSE_CREATE | FUSE_PREFILTER: {
bpf_printk("Create %s", fa->in_args[1].value);
return FUSE_BPF_BACKING;
}
case FUSE_OPEN | FUSE_PREFILTER: {
bpf_printk("Open: %d", fa->nodeid);
return FUSE_BPF_BACKING;
}
case FUSE_READ | FUSE_PREFILTER: {
const struct fuse_read_in *fri = fa->in_args[0].value;
bpf_printk("Read: fh: %lu, offset %lu, size %lu",
fri->fh, fri->offset, fri->size);
return FUSE_BPF_BACKING;
}
case FUSE_WRITE | FUSE_PREFILTER: {
const struct fuse_write_in *fwi = fa->in_args[0].value;
bpf_printk("Write: fh: %lu, offset %lu, size %lu",
fwi->fh, fwi->offset, fwi->size);
return FUSE_BPF_BACKING;
}
case FUSE_FLUSH | FUSE_PREFILTER: {
const struct fuse_flush_in *ffi = fa->in_args[0].value;
bpf_printk("Flush %d", ffi->fh);
return FUSE_BPF_BACKING;
}
case FUSE_FALLOCATE | FUSE_PREFILTER: {
const struct fuse_fallocate_in *ffa = fa->in_args[0].value;
bpf_printk("Fallocate %d %lu", ffa->fh, ffa->length);
return FUSE_BPF_BACKING;
}
case FUSE_GETXATTR | FUSE_PREFILTER: {
const char *name = fa->in_args[1].value;
bpf_printk("Getxattr %d %s", fa->nodeid, name);
return FUSE_BPF_BACKING;
}
case FUSE_LISTXATTR | FUSE_PREFILTER: {
const char *name = fa->in_args[1].value;
bpf_printk("Listxattr %d %s", fa->nodeid, name);
return FUSE_BPF_BACKING;
}
case FUSE_SETXATTR | FUSE_PREFILTER: {
const char *name = fa->in_args[1].value;
bpf_printk("Setxattr %d %s", fa->nodeid, name);
return FUSE_BPF_BACKING;
}
case FUSE_STATFS | FUSE_PREFILTER: {
bpf_printk("statfs %d", fa->nodeid);
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",
fa->opcode & FUSE_OPCODE_FILTER);
else if (fa->opcode & FUSE_POSTFILTER)
bpf_printk("postfilter *** UNKNOWN *** opcode: %d",
fa->opcode & FUSE_OPCODE_FILTER);
else
bpf_printk("*** UNKNOWN *** opcode: %d", fa->opcode);
return FUSE_BPF_BACKING;
}
}