mirror of
https://github.com/libfuse/libfuse.git
synced 2026-07-07 14:47:41 +08:00
8a4834952c
These are useful to Signed-off-by: Bernd Schubert <bernd@bsbernd.com>
165 lines
5.1 KiB
Plaintext
165 lines
5.1 KiB
Plaintext
FUSE Daemonization API
|
|
======================
|
|
|
|
This document describes the FUSE daemonization APIs, including the legacy
|
|
fuse_daemonize() function and the newfuse_daemonize_early_start()/signal() API
|
|
introduced in libfuse 3.19.
|
|
|
|
|
|
Overview
|
|
--------
|
|
|
|
FUSE filesystems often need to run as background daemons. Daemonization
|
|
involves forking the process, creating a new session, and redirecting
|
|
standard file descriptors. The challenge is properly reporting initialization
|
|
failures to the parent process.
|
|
|
|
|
|
Old API: fuse_daemonize()
|
|
--------------------------
|
|
|
|
Function signature:
|
|
int fuse_daemonize(int foreground);
|
|
|
|
Location: lib/helper.c
|
|
|
|
This is the legacy daemonization API, primarily used with the high-level
|
|
fuse_main() interface.
|
|
|
|
Behavior:
|
|
- If foreground=0: forks the process, creates a new Unix session,
|
|
redirects stdio
|
|
- If foreground=1: only changes directory to "/"
|
|
- Parent waits for a single byte on a pipe before exiting
|
|
- Child writes completion byte immediately after redirecting stdio
|
|
- Always changes directory to "/"
|
|
|
|
Limitations:
|
|
1. No failure reporting: The parent receives notification immediately after
|
|
fork/setsid, before any meaningful initialization (like mounting the
|
|
filesystem or starting threads).
|
|
|
|
2. Timing constraint: Must be called AFTER fuse_session_mount() in existing
|
|
examples, because there's no way to report mount failures to the parent.
|
|
|
|
3. Thread initialization: Cannot report failures from complex initialization
|
|
steps like:
|
|
- Starting worker threads
|
|
- Network connection setup
|
|
- RDMA memory registration
|
|
- Resource allocation
|
|
|
|
4. FUSE_SYNC_INIT incompatibility: With the FUSE_SYNC_INIT feature, FUSE_INIT
|
|
happens at mount time and may start io_uring threads. This requires
|
|
daemonization BEFORE mount, which the old API cannot handle properly.
|
|
|
|
Example usage (old API):
|
|
fuse = fuse_new(...);
|
|
fuse_mount(fuse, mountpoint);
|
|
fuse_daemonize(opts.foreground); // After mount, can't report mount failure
|
|
fuse_set_signal_handlers(se);
|
|
fuse_session_loop(se);
|
|
|
|
|
|
New API: fuse_daemonize_early_start() /fuse_daemonize_early_success() /fuse_daemonize_early_fail()
|
|
--------------------------------------------------------------------------------------------------
|
|
|
|
Functions:
|
|
int fuse_daemonize_early_start(unsigned int flags);
|
|
void fuse_daemonize_early_success(void);
|
|
void fuse_daemonize_early_fail(void);
|
|
bool fuse_daemonize_early_active(void);
|
|
|
|
Location: lib/fuse_daemonize.c, include/fuse_daemonize.h
|
|
Available since: libfuse 3.19
|
|
|
|
This new API solves the limitations of fuse_daemonize() by splitting
|
|
daemonization into two phases:
|
|
|
|
1. fuse_daemonize_early_start() - Fork and setup, but parent waits
|
|
2.1. fuse_daemonize_early_fail() - Signal failure to parent
|
|
2.2 fuse_daemonize_early_success() - Signal startup to success to the parent
|
|
See below for an important detail.
|
|
|
|
|
|
fuse_daemonize_early_start()
|
|
----------------------------
|
|
|
|
Flags:
|
|
- FUSE_DAEMONIZE_NO_CHDIR: Don't change directory to "/"
|
|
- FUSE_DAEMONIZE_NO_BACKGROUND: Don't fork (foreground mode)
|
|
|
|
Behavior:
|
|
- Unless NO_BACKGROUND: forks the process
|
|
- Parent waits for status signal from child
|
|
- Child creates new session and continues
|
|
- Unless NO_CHDIR: changes directory to "/"
|
|
- Closes stdin immediately in child
|
|
- Starts a watcher thread to detect parent death
|
|
- Returns 0 in child on success, negative errno on error
|
|
|
|
Parent death detection:
|
|
- Uses a "death pipe" - parent keeps write end open
|
|
- Child's watcher thread polls the read end
|
|
- If parent dies, pipe gets POLLHUP and child exits
|
|
- Prevents orphaned daemons if parent is killed
|
|
|
|
Child death detection:
|
|
- The parent will detect a pipe failure for the
|
|
read(signal_pipe[0], ...) and exit with an error.
|
|
|
|
fuse_daemonize_early_fail(int err)
|
|
----------------------------------
|
|
|
|
Behavior:
|
|
- Signals the parent about the provided error
|
|
- Parent will exit with that error
|
|
|
|
fuse_daemonize_early_success()
|
|
-------------------------------
|
|
- Signals the parent process with success
|
|
- On success: redirects stdout/stderr to /dev/null
|
|
- Stops the parent watcher thread
|
|
- Cleans up pipes and internal state
|
|
- Safe to call multiple times
|
|
- Safe to call even if fuse_daemonize_early_start() failed
|
|
- Needs to be called after successful mount
|
|
|
|
Example usage (new API):
|
|
-------------------------
|
|
|
|
// Start daemonization BEFORE mount
|
|
unsigned int daemon_flags = 0;
|
|
if (foreground)
|
|
daemon_flags |= FUSE_DAEMONIZE_NO_BACKGROUND;
|
|
|
|
if (fuse_daemonize_start(daemon_flags) != 0)
|
|
goto error;
|
|
|
|
// Complex initialization can fail and be reported
|
|
if (setup_threads() != 0)
|
|
goto error_signal;
|
|
|
|
if (setup_network() != 0)
|
|
goto error_signal;
|
|
// Mount can now fail and be reported to parent
|
|
if (fuse_session_mount(se, mountpoint) != 0)
|
|
goto error_signal;
|
|
|
|
// Signal success - parent exits with EXIT_SUCCESS
|
|
// This is typically done in the init() callback after FUSE_INIT
|
|
fuse_daemonize_early_signal(FUSE_DAEMONIZE_SUCCESS);
|
|
|
|
// Run main loop
|
|
fuse_session_loop(se);
|
|
|
|
return 0;
|
|
|
|
error_signal:
|
|
// Signal failure - parent exits with EXIT_FAILURE
|
|
fuse_daemonize_early_signal(FUSE_DAEMONIZE_FAILURE);
|
|
error:
|
|
return 1;
|
|
|
|
|