On Tue, Nov 22, 2022 at 4:16 AM Daniel Rosenberg <drosen@xxxxxxxxxx> wrote: > > Fuse-bpf provides a short circuit path for Fuse implementations that act > as a stacked filesystem. For cases that are directly unchanged, > operations are passed directly to the backing filesystem. Small > adjustments can be handled by bpf prefilters or postfilters, with the > option to fall back to userspace as needed. > > Fuse implementations may supply backing node information, as well as bpf > programs via an optional add on to the lookup structure. > > This has been split over the next set of patches for readability. > Clusters of fuse ops have been split into their own patches, as well as > the actual bpf calls and userspace calls for filters. > > Signed-off-by: Daniel Rosenberg <drosen@xxxxxxxxxx> > Signed-off-by: Paul Lawrence <paullawrence@xxxxxxxxxx> > Signed-off-by: Alessio Balsini <balsini@xxxxxxxxxx> > --- > fs/fuse/Kconfig | 8 + > fs/fuse/Makefile | 1 + > fs/fuse/backing.c | 392 ++++++++++++++++++++++++++++++++++++++++++++++ > fs/fuse/dev.c | 41 ++++- > fs/fuse/dir.c | 187 +++++++++++++++++----- > fs/fuse/file.c | 25 ++- > fs/fuse/fuse_i.h | 99 +++++++++++- > fs/fuse/inode.c | 189 +++++++++++++++++----- > fs/fuse/ioctl.c | 2 +- > 9 files changed, 861 insertions(+), 83 deletions(-) > create mode 100644 fs/fuse/backing.c > > diff --git a/fs/fuse/Kconfig b/fs/fuse/Kconfig > index 038ed0b9aaa5..3a64fa73e591 100644 > --- a/fs/fuse/Kconfig > +++ b/fs/fuse/Kconfig > @@ -52,3 +52,11 @@ config FUSE_DAX > > If you want to allow mounting a Virtio Filesystem with the "dax" > option, answer Y. > + > +config FUSE_BPF > + bool "Adds BPF to fuse" > + depends on FUSE_FS > + depends on BPF > + help > + Extends FUSE by adding BPF to prefilter calls and potentially pass to a > + backing file system > diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile > index 0c48b35c058d..a0853c439db2 100644 > --- a/fs/fuse/Makefile > +++ b/fs/fuse/Makefile > @@ -9,5 +9,6 @@ obj-$(CONFIG_VIRTIO_FS) += virtiofs.o > > fuse-y := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o > fuse-$(CONFIG_FUSE_DAX) += dax.o > +fuse-$(CONFIG_FUSE_BPF) += backing.o > > virtiofs-y := virtio_fs.o > diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c > new file mode 100644 > index 000000000000..5a59a8963d52 > --- /dev/null > +++ b/fs/fuse/backing.c > @@ -0,0 +1,392 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * FUSE-BPF: Filesystem in Userspace with BPF > + * Copyright (c) 2021 Google LLC > + */ > + > +#include "fuse_i.h" > + > +#include <linux/fdtable.h> > +#include <linux/file.h> > +#include <linux/fs_stack.h> > +#include <linux/namei.h> > + > +/* > + * expression statement to wrap the backing filter logic > + * struct inode *inode: inode with bpf and backing inode > + * typedef io: (typically complex) type whose components fuse_args can point to. > + * An instance of this type is created locally and passed to initialize > + * void initialize_in(struct fuse_args *fa, io *in_out, args...): function that sets > + * up fa and io based on args > + * void initialize_out(struct fuse_args *fa, io *in_out, args...): function that sets > + * up fa and io based on args > + * int backing(struct fuse_bpf_args_internal *fa, args...): function that actually performs > + * the backing io operation > + * void *finalize(struct fuse_bpf_args *, args...): function that performs any final > + * work needed to commit the backing io > + */ > +#define fuse_bpf_backing(inode, io, out, initialize_in, initialize_out, \ > + backing, finalize, args...) \ > +({ \ > + struct fuse_inode *fuse_inode = get_fuse_inode(inode); \ > + struct fuse_args fa = { 0 }; \ > + bool initialized = false; \ > + bool handled = false; \ > + ssize_t res; \ > + io feo = { 0 }; \ > + int error = 0; \ > + \ > + do { \ > + if (!fuse_inode || !fuse_inode->backing_inode) \ > + break; \ > + \ > + handled = true; \ > + error = initialize_in(&fa, &feo, args); \ > + if (error) \ > + break; \ > + \ > + error = initialize_out(&fa, &feo, args); \ > + if (error) \ > + break; \ > + \ > + initialized = true; \ > + \ > + error = backing(&fa, out, args); \ > + if (error < 0) \ > + fa.error_in = error; \ > + \ > + } while (false); \ > + \ > + if (initialized && handled) { \ > + res = finalize(&fa, out, args); \ > + if (res) \ > + error = res; \ > + } \ > + \ > + *out = error ? _Generic((*out), \ > + default : \ > + error, \ > + struct dentry * : \ > + ERR_PTR(error), \ > + const char * : \ > + ERR_PTR(error) \ > + ) : (*out); \ > + handled; \ > +}) > + I hope there is a better way than this macro... Haven't studied the patches enough to be able to suggest one. Thanks, Amir.