[RFC PATCH v2 21/21] fuse-bpf: allow mounting with no userspace daemon

Daniel Rosenberg
2022-11-22T02:20:46Z

When using fuse-bpf in pure passthrough mode, we don't explicitly need a
userspace daemon. This allows simple testing of the backing operations.

Signed-off-by: Daniel Rosenberg <drosen@google.com>
Signed-off-by: Paul Lawrence <paullawrence@google.com>
---
fs/fuse/fuse_i.h | 4 ++++
fs/fuse/inode.c | 25 +++++++++++++++++++------
2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 99c9231ec98b..402d80d35958 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -564,6 +564,7 @@ struct fuse_fs_context {
bool no_control:1;
bool no_force_umount:1;
bool legacy_opts_show:1;
+ bool no_daemon:1;
enum fuse_dax_mode dax_mode;
unsigned int max_read;
unsigned int blksize;
@@ -842,6 +843,9 @@ struct fuse_conn {
/* Is tmpfile not implemented by fs? */
unsigned int no_tmpfile:1;

+ /** BPF Only, no Daemon running */
+ unsigned int no_daemon:1;
+
/** The number of requests waiting for completion */
atomic_t num_waiting;

diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 1e7d45977144..4820edcc242a 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -749,6 +749,7 @@ enum {
OPT_MAX_READ,
OPT_BLKSIZE,
OPT_ROOT_DIR,
+ OPT_NO_DAEMON,
OPT_ERR
};

@@ -764,6 +765,7 @@ static const struct fs_parameter_spec fuse_fs_parameters[] = {
fsparam_u32 ("blksize", OPT_BLKSIZE),
fsparam_string ("subtype", OPT_SUBTYPE),
fsparam_u32 ("root_dir", OPT_ROOT_DIR),
+ fsparam_flag ("no_daemon", OPT_NO_DAEMON),
{}
};

@@ -853,6 +855,11 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param)
return invalfc(fsc, "Unable to open root directory");
break;

+ case OPT_NO_DAEMON:
+ ctx->no_daemon = true;
+ ctx->fd_present = true;
+ break;
+
default:
return -EINVAL;
}
@@ -1411,7 +1418,7 @@ void fuse_send_init(struct fuse_mount *fm)
ia->args.nocreds = true;
ia->args.end = process_init_reply;

- if (fuse_simple_background(fm, &ia->args, GFP_KERNEL) != 0)
+ if (unlikely(fm->fc->no_daemon) || fuse_simple_background(fm, &ia->args, GFP_KERNEL) != 0)
process_init_reply(fm, &ia->args, -ENOTCONN);
}
EXPORT_SYMBOL_GPL(fuse_send_init);
@@ -1693,6 +1700,7 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
fc->destroy = ctx->destroy;
fc->no_control = ctx->no_control;
fc->no_force_umount = ctx->no_force_umount;
+ fc->no_daemon = ctx->no_daemon;

err = -ENOMEM;
root = fuse_get_root_inode(sb, ctx->rootmode, ctx->root_dir);
@@ -1739,7 +1747,7 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
struct fuse_fs_context *ctx = fsc->fs_private;
int err;

- if (!ctx->file || !ctx->rootmode_present ||
+ if (!!ctx->file == ctx->no_daemon || !ctx->rootmode_present ||
!ctx->user_id_present || !ctx->group_id_present)
return -EINVAL;

@@ -1747,10 +1755,12 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
* Require mount to happen from the same user namespace which
* opened /dev/fuse to prevent potential attacks.
*/
- if ((ctx->file->f_op != &fuse_dev_operations) ||
- (ctx->file->f_cred->user_ns != sb->s_user_ns))
- return -EINVAL;
- ctx->fudptr = &ctx->file->private_data;
+ if (ctx->file) {
+ if ((ctx->file->f_op != &fuse_dev_operations) ||
+ (ctx->file->f_cred->user_ns != sb->s_user_ns))
+ return -EINVAL;
+ ctx->fudptr = &ctx->file->private_data;
+ }

err = fuse_fill_super_common(sb, ctx);
if (err)
@@ -1800,6 +1810,9 @@ static int fuse_get_tree(struct fs_context *fsc)

fsc->s_fs_info = fm;

+ if (ctx->no_daemon)
+ return get_tree_nodev(fsc, fuse_fill_super);
+
if (ctx->fd_present)
ctx->file = fget(ctx->fd);

--
2.38.1.584.g0f3c55d4c2-goog