All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Rosenberg <drosen@google.com>
To: Miklos Szeredi <miklos@szeredi.hu>,
	Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	John Fastabend <john.fastabend@gmail.com>
Cc: Andrii Nakryiko <andrii@kernel.org>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	Song Liu <song@kernel.org>, Yonghong Song <yhs@fb.com>,
	KP Singh <kpsingh@kernel.org>,
	Stanislav Fomichev <sdf@google.com>, Hao Luo <haoluo@google.com>,
	Jiri Olsa <jolsa@kernel.org>,
	Daniel Rosenberg <drosen@google.com>,
	Paul Lawrence <paullawrence@google.com>,
	Alessio Balsini <balsini@google.com>,
	David Anderson <dvander@google.com>,
	Sandeep Patil <sspatil@google.com>,
	linux-fsdevel@vger.kernel.org, bpf@vger.kernel.org,
	kernel-team@android.com
Subject: [PATCH 25/26] fuse-bpf: Add userspace pre/post filters
Date: Mon, 26 Sep 2022 16:18:21 -0700	[thread overview]
Message-ID: <20220926231822.994383-26-drosen@google.com> (raw)
In-Reply-To: <20220926231822.994383-1-drosen@google.com>

This allows fuse-bpf to call out to userspace to handle pre and post
filters. Any of the inputs may be changed by the prefilter, so we must
handle up to 3 outputs. For the postfilter, our inputs include the
output arguments, so we must handle up to 5 inputs.

As long as you don't request both pre-filter and post-filter in
userspace, we will end up doing fewer round trips to userspace.

Signed-off-by: Daniel Rosenberg <drosen@google.com>
---
 fs/fuse/backing.c        | 70 ++++++++++++++++++++++++++++++++++++++++
 fs/fuse/dev.c            |  2 ++
 fs/fuse/fuse_i.h         | 42 ++++++++++++++++++++++--
 include/linux/bpf_fuse.h |  1 +
 4 files changed, 113 insertions(+), 2 deletions(-)

diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
index 485b6f1e8503..7a3b1fdb2c56 100644
--- a/fs/fuse/backing.c
+++ b/fs/fuse/backing.c
@@ -2681,3 +2681,73 @@ void __exit fuse_bpf_cleanup(void)
 {
 	kmem_cache_destroy(fuse_bpf_aio_request_cachep);
 }
+
+static ssize_t fuse_bpf_simple_request(struct fuse_mount *fm, struct bpf_fuse_args *fa,
+				       unsigned short in_numargs, unsigned short out_numargs,
+				       struct bpf_fuse_arg *out_arg_array, bool add_out_to_in)
+{
+	int i;
+	uint32_t max_size;
+	ssize_t res;
+
+	struct fuse_args args = {
+		.nodeid = fa->nodeid,
+		.opcode = fa->opcode,
+		.error_in = fa->error_in,
+		.in_numargs = in_numargs,
+		.out_numargs = out_numargs,
+		.force = !!(fa->flags & FUSE_BPF_FORCE),
+		.out_argvar = !!(fa->flags & FUSE_BPF_OUT_ARGVAR),
+		.is_lookup = !!(fa->flags & FUSE_BPF_IS_LOOKUP),
+	};
+
+	/* Set in args */
+	for (i = 0; i < fa->in_numargs; ++i)
+		args.in_args[i] = (struct fuse_in_arg) {
+			.size = fa->in_args[i].size,
+			.value = fa->in_args[i].value,
+		};
+	if (add_out_to_in) {
+		for (i = 0; i < fa->out_numargs; ++i)
+			args.in_args[fa->in_numargs + i] = (struct fuse_in_arg) {
+				.size = fa->out_args[i].size,
+				.value = fa->out_args[i].value,
+			};
+	}
+
+	/* All out args must be writeable */
+	for (i = 0; i < out_numargs; ++i) {
+		max_size = out_arg_array[i].max_size ?: out_arg_array[i].size;
+		if (!bpf_fuse_get_writeable(&out_arg_array[i], max_size, true))
+			return -ENOMEM;
+	}
+
+	/* Set out args */
+	for (i = 0; i < out_numargs; ++i)
+		args.out_args[i] = (struct fuse_arg) {
+			.size = out_arg_array[i].size,
+			.value = out_arg_array[i].value,
+		};
+
+	res = fuse_simple_request(fm, &args);
+
+	/* update used areas of buffers */
+	for (i = 0; i < out_numargs; ++i)
+		if (out_arg_array[i].flags & BPF_FUSE_VARIABLE_SIZE)
+			out_arg_array[i].size = args.out_args[i].size;
+	fa->ret = args.ret;
+
+	return res;
+}
+
+ssize_t fuse_prefilter_simple_request(struct fuse_mount *fm, struct bpf_fuse_args *fa)
+{
+	return fuse_bpf_simple_request(fm, fa, fa->in_numargs, fa->in_numargs,
+				       fa->in_args, false);
+}
+
+ssize_t fuse_postfilter_simple_request(struct fuse_mount *fm, struct bpf_fuse_args *fa)
+{
+	return fuse_bpf_simple_request(fm, fa, fa->in_numargs + fa->out_numargs, fa->out_numargs,
+				       fa->out_args, true);
+}
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 626dbbf92874..765bc95bd560 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -520,6 +520,8 @@ ssize_t fuse_simple_request(struct fuse_mount *fm, struct fuse_args *args)
 		BUG_ON(args->out_numargs == 0);
 		ret = args->out_args[args->out_numargs - 1].size;
 	}
+	if (args->is_filter)
+		args->ret = req->out.h.error;
 	fuse_put_request(req);
 
 	return ret;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 07b50be2c6e4..a619c6eac6e5 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -305,6 +305,17 @@ struct fuse_page_desc {
 	unsigned int offset;
 };
 
+/* To deal with bpf pre and post filters in userspace calls, we must support
+ * passing the inputs and outputs as inputs, and we must have enough space in
+ * outputs to handle all of the inputs.
+ */
+#define FUSE_EXTENDED_MAX_ARGS_IN (FUSE_MAX_ARGS_IN + FUSE_MAX_ARGS_OUT)
+#if FUSE_MAX_ARGS_IN > FUSE_MAX_ARGS_OUT
+#define FUSE_EXTENDED_MAX_ARGS_OUT FUSE_MAX_ARGS_IN
+#else
+#define FUSE_EXTENDED_MAX_ARGS_OUT FUSE_MAX_ARGS_OUT
+#endif
+
 struct fuse_args {
 	uint64_t nodeid;
 	uint32_t opcode;
@@ -321,9 +332,11 @@ struct fuse_args {
 	bool page_zeroing:1;
 	bool page_replace:1;
 	bool may_block:1;
+	bool is_filter:1;
 	bool is_lookup:1;
-	struct fuse_in_arg in_args[3];
-	struct fuse_arg out_args[2];
+	uint32_t ret;
+	struct fuse_in_arg in_args[FUSE_EXTENDED_MAX_ARGS_IN];
+	struct fuse_arg out_args[FUSE_EXTENDED_MAX_ARGS_OUT];
 	void (*end)(struct fuse_mount *fm, struct fuse_args *args, int error);
 };
 
@@ -1936,6 +1949,9 @@ static inline void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatf
 int __init fuse_bpf_init(void);
 void __exit fuse_bpf_cleanup(void);
 
+ssize_t fuse_prefilter_simple_request(struct fuse_mount *fm, struct bpf_fuse_args *args);
+ssize_t fuse_postfilter_simple_request(struct fuse_mount *fm, struct bpf_fuse_args *args);
+
 static inline void fuse_bpf_set_in_ends(struct bpf_fuse_args *fa)
 {
 	int i;
@@ -1994,9 +2010,11 @@ static inline void fuse_bpf_free_alloced(struct bpf_fuse_args *fa)
 			 backing, finalize, args...)			\
 ({									\
 	struct fuse_inode *fuse_inode = get_fuse_inode(inode);		\
+	struct fuse_mount *fm = get_fuse_mount(inode);			\
 	struct bpf_fuse_args fa = { 0 };				\
 	bool initialized = false;					\
 	bool handled = false;						\
+	bool locked;							\
 	ssize_t res;							\
 	int bpf_next;							\
 	io feo = { 0 };							\
@@ -2021,6 +2039,16 @@ static inline void fuse_bpf_free_alloced(struct bpf_fuse_args *fa)
 			break;						\
 		}							\
 									\
+		if (bpf_next == BPF_FUSE_USER_PREFILTER) {		\
+			locked = fuse_lock_inode(inode);		\
+			res = fuse_prefilter_simple_request(fm, &fa);	\
+			fuse_unlock_inode(inode, locked);		\
+			if (res < 0) {					\
+				error = res;				\
+				break;					\
+			}						\
+			bpf_next = fa.ret;				\
+		}							\
 		fuse_bpf_set_in_immutable(&fa);				\
 									\
 		error = initialize_out(&fa, &feo, args);		\
@@ -2051,6 +2079,16 @@ static inline void fuse_bpf_free_alloced(struct bpf_fuse_args *fa)
 			break;						\
 		}							\
 									\
+		if (!(bpf_next == BPF_FUSE_USER_POSTFILTER))		\
+			break;						\
+									\
+		locked = fuse_lock_inode(inode);			\
+		res = fuse_postfilter_simple_request(fm, &fa);		\
+		fuse_unlock_inode(inode, locked);			\
+		if (res < 0) {						\
+			error = res;					\
+			break;						\
+		}							\
 	} while (false);						\
 									\
 	if (initialized && handled) {					\
diff --git a/include/linux/bpf_fuse.h b/include/linux/bpf_fuse.h
index ef5c8fdaffee..2802ca71ddd1 100644
--- a/include/linux/bpf_fuse.h
+++ b/include/linux/bpf_fuse.h
@@ -40,6 +40,7 @@ struct bpf_fuse_args {
 	uint32_t in_numargs;
 	uint32_t out_numargs;
 	uint32_t flags;
+	uint32_t ret;
 	struct bpf_fuse_arg in_args[FUSE_MAX_ARGS_IN];
 	struct bpf_fuse_arg out_args[FUSE_MAX_ARGS_OUT];
 };
-- 
2.37.3.998.g577e59143f-goog


  parent reply	other threads:[~2022-09-26 23:21 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-26 23:17 [PATCH 00/26] FUSE BPF: A Stacked Filesystem Extension for FUSE Daniel Rosenberg
2022-09-26 23:17 ` [PATCH 01/26] bpf: verifier: Allow for multiple packets Daniel Rosenberg
2022-09-26 23:17 ` [PATCH 02/26] bpf: verifier: Allow single packet invalidation Daniel Rosenberg
2022-09-27  4:49   ` kernel test robot
2022-09-29  4:21   ` kernel test robot
2022-09-26 23:17 ` [PATCH 03/26] fuse-bpf: Update uapi for fuse-bpf Daniel Rosenberg
2022-09-27 18:19   ` Miklos Szeredi
2022-09-30 22:02     ` Paul Lawrence
2022-10-01  7:47       ` Amir Goldstein
2022-09-26 23:18 ` [PATCH 04/26] fuse-bpf: Add BPF supporting functions Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 05/26] fs: Generic function to convert iocb to rw flags Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 06/26] bpf: Export bpf_prog_fops Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 07/26] fuse-bpf: Prepare for fuse-bpf patch Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 08/26] fuse: Add fuse-bpf, a stacked fs extension for FUSE Daniel Rosenberg
2022-09-27 22:45   ` kernel test robot
2022-09-29  5:09   ` kernel test robot
2022-09-26 23:18 ` [PATCH 09/26] fuse-bpf: Don't support export_operations Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 10/26] fuse-bpf: Partially add mapping support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 11/26] fuse-bpf: Add lseek support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 12/26] fuse-bpf: Add support for fallocate Daniel Rosenberg
2022-09-27 22:07   ` Dave Chinner
2022-09-27 23:36     ` Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 13/26] fuse-bpf: Support file/dir open/close Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 14/26] fuse-bpf: Support mknod/unlink/mkdir/rmdir Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 15/26] fuse-bpf: Add support for read/write iter Daniel Rosenberg
2022-10-01  6:53   ` Amir Goldstein
2022-09-26 23:18 ` [PATCH 16/26] fuse-bpf: support FUSE_READDIR Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 17/26] fuse-bpf: Add support for sync operations Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 18/26] fuse-bpf: Add Rename support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 19/26] fuse-bpf: Add attr support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 20/26] fuse-bpf: Add support for FUSE_COPY_FILE_RANGE Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 21/26] fuse-bpf: Add xattr support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 22/26] fuse-bpf: Add symlink/link support Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 23/26] fuse-bpf: allow mounting with no userspace daemon Daniel Rosenberg
2022-09-26 23:18 ` [PATCH 24/26] fuse-bpf: Call bpf for pre/post filters Daniel Rosenberg
2022-09-26 23:18 ` Daniel Rosenberg [this message]
2022-09-26 23:18 ` [PATCH 26/26] fuse-bpf: Add selftests Daniel Rosenberg
2022-09-28  6:41 ` [PATCH 00/26] FUSE BPF: A Stacked Filesystem Extension for FUSE Martin KaFai Lau
2022-09-28 12:31   ` Brian Foster
2022-10-01  0:47     ` Daniel Rosenberg
2022-10-01  0:05   ` Daniel Rosenberg
2022-10-01  0:24     ` Alexei Starovoitov
2022-10-06  1:58     ` Martin KaFai Lau

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220926231822.994383-26-drosen@google.com \
    --to=drosen@google.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=balsini@google.com \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=dvander@google.com \
    --cc=haoluo@google.com \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kernel-team@android.com \
    --cc=kpsingh@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=miklos@szeredi.hu \
    --cc=paullawrence@google.com \
    --cc=sdf@google.com \
    --cc=song@kernel.org \
    --cc=sspatil@google.com \
    --cc=yhs@fb.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.