diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 527f20bb455d..50784f39cba8 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -544,6 +544,7 @@ struct fuse_fs_context { bool no_force_umount:1; bool legacy_opts_show:1; bool dax:1; + bool no_daemon:1; unsigned int max_read; unsigned int blksize; const char *subtype; @@ -792,6 +793,9 @@ struct fuse_conn { /** Passthrough mode for read/write IO */ unsigned int passthrough: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 099dc19c9018..e529fe0e147f 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -598,6 +598,7 @@ enum { OPT_BLKSIZE, OPT_ROOT_BPF, OPT_ROOT_DIR, + OPT_NO_DAEMON, OPT_ERR }; @@ -614,6 +615,7 @@ static const struct fs_parameter_spec fuse_fs_parameters[] = { fsparam_string ("subtype", OPT_SUBTYPE), fsparam_u32 ("root_bpf", OPT_ROOT_BPF), fsparam_u32 ("root_dir", OPT_ROOT_DIR), + fsparam_flag ("no_daemon", OPT_NO_DAEMON), {} }; @@ -712,6 +714,11 @@ static int fuse_parse_param(struct fs_context *fc, struct fs_parameter *param) return invalfc(fc, "Unable to open root directory"); break; + case OPT_NO_DAEMON: + ctx->no_daemon = true; + ctx->fd_present = true; + break; + default: return -EINVAL; } @@ -1267,7 +1274,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); @@ -1513,6 +1520,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_bpf, @@ -1564,18 +1572,20 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) struct fuse_mount *fm; err = -EINVAL; - file = fget(ctx->fd); - if (!file) - goto err; + if (!ctx->no_daemon) { + file = fget(ctx->fd); + if (!file) + goto err; - /* - * Require mount to happen from the same user namespace which - * opened /dev/fuse to prevent potential attacks. - */ - if ((file->f_op != &fuse_dev_operations) || - (file->f_cred->user_ns != sb->s_user_ns)) - goto err_fput; - ctx->fudptr = &file->private_data; + /* + * Require mount to happen from the same user namespace which + * opened /dev/fuse to prevent potential attacks. + */ + if ((file->f_op != &fuse_dev_operations) || + (file->f_cred->user_ns != sb->s_user_ns)) + goto err_fput; + ctx->fudptr = &file->private_data; + } fc = kmalloc(sizeof(*fc), GFP_KERNEL); err = -ENOMEM; @@ -1601,7 +1611,8 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) * memory barrier for file->private_data to be visible on all * CPUs after this */ - fput(file); + if (!ctx->no_daemon) + fput(file); fuse_send_init(get_fuse_mount_super(sb)); return 0; @@ -1609,7 +1620,8 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc) fuse_mount_put(fm); sb->s_fs_info = NULL; err_fput: - fput(file); + if (!ctx->no_daemon) + fput(file); err: return err; }