Re: [PATCH 12/13] example/service: create a sample systemd service for a high-level fuse server

Darrick J. Wong
2026-04-27T15:13:30Z

On Sun, Apr 26, 2026 at 11:21:21PM +0200, Bernd Schubert wrote:
>
>
> On 4/23/26 01:22, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> >
> > Create a simple high-level fuse server that can be run as a systemd
> > service.
> >
> > Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
> > ---
> > example/single_file.h | 38 ++++++
> > example/meson.build | 6 +
> > example/service_hl.c | 224 +++++++++++++++++++++++++++++++++++
> > example/service_hl.socket.in | 15 ++
> > example/service_hl@.service | 102 ++++++++++++++++
> > example/service_ll.c | 1
> > example/single_file.c | 271 +++++++++++++++++++++++++++++++++++++++---
> > 7 files changed, 640 insertions(+), 17 deletions(-)
> > create mode 100644 example/service_hl.c
> > create mode 100644 example/service_hl.socket.in
> > create mode 100644 example/service_hl@.service
> >
> >
> > diff --git a/example/single_file.h b/example/single_file.h
> > index d8a91adbf875ef..86edb51afb3384 100644
> > --- a/example/single_file.h
> > +++ b/example/single_file.h
> > @@ -124,6 +124,7 @@ ssize_t single_file_pread(char *buf, size_t count, off_t pos);
> >
> > /* low-level fuse operation handlers */
> >
> > +#ifdef USE_SINGLE_FILE_LL_API
> > bool is_single_file_child(fuse_ino_t parent, const char *name);
> > bool is_single_file_ino(fuse_ino_t ino);
> >
> > @@ -149,5 +150,42 @@ void single_file_ll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
> >
> > int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
> > off_t off, size_t maxsize);
> > +#endif
> > +
> > +/* high-level fuse operation handlers */
> > +
> > +#ifdef USE_SINGLE_FILE_HL_API
> > +bool is_single_open_file_path(const struct fuse_file_info *fi, const char *name);
> > +
> > +int single_file_hl_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
> > + off_t offset, struct fuse_file_info *fi,
> > + enum fuse_readdir_flags flags);
> > +
> > +int single_file_hl_statfs(const char *path, struct statvfs *buf);
> > +
> > +int single_file_hl_statx(const char *path, int statx_flags, int statx_mask,
> > + struct statx *stx, struct fuse_file_info *fi);
> > +
> > +int single_file_hl_getattr(const char *path, struct stat *stbuf,
> > + struct fuse_file_info *fi);
> > +int single_file_hl_chmod(const char *path, mode_t mode,
> > + struct fuse_file_info *fi);
> > +int single_file_hl_utimens(const char *path, const struct timespec ctv[2],
> > + struct fuse_file_info *fi);
> > +int single_file_hl_chown(const char *path, uid_t owner, gid_t group,
> > + struct fuse_file_info *fi);
> > +int single_file_hl_truncate(const char *path, off_t len,
> > + struct fuse_file_info *fi);
> > +
> > +int single_file_hl_opendir(const char *path, struct fuse_file_info *fi);
> > +int single_file_hl_open(const char *path, struct fuse_file_info *fi);
> > +
> > +int single_file_hl_fsync(const char *path, int datasync,
> > + struct fuse_file_info *fi);
> > +#endif
> > +
> > +#if !defined(USE_SINGLE_FILE_LL_API) && !defined(USE_SINGLE_FILE_HL_API)
> > +# warning USE_SINGLE_FILE_[HL]L_API not defined!
> > +#endif
> >
> > #endif /* FUSE_SINGLE_FILE_H_ */
> > diff --git a/example/meson.build b/example/meson.build
> > index e948f6ba74fdfa..19a383f7cd2c74 100644
> > --- a/example/meson.build
> > +++ b/example/meson.build
> > @@ -19,6 +19,12 @@ if platform.endswith('linux')
> > configure_file(input: 'service_ll.socket.in',
> > output: 'service_ll.socket',
> > configuration: private_cfg)
> > +
> > + single_file_examples += [ 'service_hl' ]
> > + configure_file(input: 'service_hl.socket.in',
> > + output: 'service_hl.socket',
> > + configuration: private_cfg)
> > +
> > endif
> >
> > threaded_examples = [ 'notify_inval_inode',
> > diff --git a/example/service_hl.c b/example/service_hl.c
> > new file mode 100644
> > index 00000000000000..9c4f3ae7a6cf3c
> > --- /dev/null
> > +++ b/example/service_hl.c
> > @@ -0,0 +1,224 @@
> > +/*
> > + * FUSE: Filesystem in Userspace
> > + * Copyright (C) 2026 Oracle.
> > + *
> > + * This program can be distributed under the terms of the GNU GPLv2.
> > + * See the file GPL2.txt.
> > + */
> > +
> > +/** @file
> > + *
> > + * minimal example filesystem using high-level API and systemd service api
>
> Could you add a bit more context?
>
> - Shows how to build a high level FUSE filesystems that can be managed
> by systemd
> - Enables on-demand filesystem mounting via socket activation
> - Allows running FUSE servers with minimal privileges (unlike
> traditional FUSE which needs mount permissions)

I will do that for both service_[hl]l.c files. Currently I have for the
lowlevel example:

* Minimal example filesystem using low-level API and systemd service API.
*
* - Shows how to build a low level FUSE filesystem server that can be managed
* by systemd
* - Enables on-demand filesystem mounting via socket activation
* - Demonstrates requesting resources from the mount-caller's environment
* - Allows running FUSE servers with minimal privileges; isolated mount,
* network, and pid namespaces; and a separate uid/gid (unlike traditional
* FUSE which needs mount permissions and runs in the caller's environment)
*
* Compile with:
*
* gcc -Wall single_file.c service_ll.c `pkg-config fuse3 --cflags --libs` -o service_ll
*
* Note: If the pkg-config command fails due to the absence of the fuse3.pc
* file, you should configure the path to the fuse3.pc file in the
* PKG_CONFIG_PATH variable.
*
* Change the ExecStart line in service_ll@.service:
*
* ExecStart=/path/to/service_ll
*
* to point to the actual path of the service_ll binary.
*
* Finally, install the service_ll@.service and service_ll.socket files to the
* systemd service directory, usually /run/systemd/system. Run these commands
* to activate:
*
* systemctl daemon-reload
* systemctl start service_ll.socket
*
* Then mount with:
*
* mount -t fuse.service_ll /dev/sda /mnt

and similar for service_hl.c.

--D

>
> Thanks,
> Bernd
>