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>
185 lines
5.7 KiB
Plaintext
185 lines
5.7 KiB
Plaintext
FUSE Synchronous vs Asynchronous FUSE_INIT
|
|
============================================
|
|
|
|
This document explains the difference between asynchronous and synchronous
|
|
FUSE_INIT processing, and when each mode is used.
|
|
|
|
|
|
Overview
|
|
--------
|
|
|
|
FUSE_INIT is the initial handshake between the kernel FUSE module and the
|
|
userspace filesystem daemon. During this handshake, the kernel and daemon
|
|
negotiate capabilities, protocol version, and various feature flags.
|
|
|
|
Asynchronous FUSE_INIT (Traditional Behavior)
|
|
----------------------------------------------
|
|
|
|
In the traditional asynchronous mode:
|
|
|
|
1. mount() syscall completes and returns to caller
|
|
2. Filesystem appears mounted to the system
|
|
3. FUSE daemon starts worker threads
|
|
4. Worker threads process FUSE_INIT request
|
|
5. Filesystem becomes fully operational
|
|
|
|
Timeline:
|
|
mount() -----> returns
|
|
|
|
|
v
|
|
FUSE_INIT sent
|
|
|
|
|
v
|
|
daemon processes FUSE_INIT
|
|
|
|
|
v
|
|
filesystem ready
|
|
|
|
Limitations:
|
|
|
|
1. **No early requests**: The kernel cannot send requests (like getxattr)
|
|
during the mount() syscall. This breaks SELinux, which needs to query
|
|
extended attributes on the root inode immediately upon mounting.
|
|
|
|
2. **Daemonization timing**: With the old fuse_daemonize() API, the daemon
|
|
must call it AFTER mount, because there's no way to report mount failures
|
|
to the parent process if daemonization happens first.
|
|
|
|
3. **No custom root inode**: The root inode ID is hardcoded to FUSE_ROOT_ID (1)
|
|
because FUSE_INIT hasn't been processed yet when the mount completes.
|
|
|
|
4. **Thread startup after mount**: io_uring threads and other worker threads
|
|
can only start after mount() returns, not before.
|
|
|
|
|
|
Synchronous FUSE_INIT (New Behavior)
|
|
-------------------------------------
|
|
|
|
Kernel support: Linux kernel commit dfb84c330794 (v6.18+)
|
|
libfuse support: libfuse 3.19+
|
|
|
|
In synchronous mode:
|
|
|
|
1. FUSE daemon opens /dev/fuse
|
|
2. Daemon calls ioctl(fd, FUSE_DEV_IOC_SYNC_INIT)
|
|
3. Daemon starts worker thread
|
|
4. Daemon calls mount() syscall
|
|
5. Kernel sends FUSE_INIT during mount() - mount() blocks
|
|
6. Worker thread processes FUSE_INIT while mount() is blocked
|
|
7. Worker thread may process additional requests (getxattr, etc.)
|
|
8. mount() syscall completes and returns
|
|
9. Filesystem is fully operational
|
|
|
|
Timeline:
|
|
open /dev/fuse
|
|
|
|
|
v
|
|
ioctl(FUSE_DEV_IOC_SYNC_INIT)
|
|
|
|
|
v
|
|
start worker thread
|
|
|
|
|
v
|
|
mount() -----> blocks
|
|
| |
|
|
| v
|
|
| FUSE_INIT sent
|
|
| |
|
|
| v
|
|
| worker processes FUSE_INIT
|
|
| |
|
|
| v
|
|
| (possible getxattr, etc.)
|
|
| |
|
|
+-------> returns
|
|
|
|
|
v
|
|
filesystem ready
|
|
|
|
Advantages:
|
|
|
|
1. **SELinux support**: The kernel can send getxattr requests during mount()
|
|
to query security labels on the root inode.
|
|
|
|
2. **Early daemonization**: The daemon can fork BEFORE mount using the new
|
|
fuse_daemonize_start()/signal() API, and report mount failures to the
|
|
parent process.
|
|
|
|
3. **Custom root inode**: The daemon can specify a custom root inode ID
|
|
during FUSE_INIT, before mount() completes.
|
|
|
|
4. **Thread startup before mount**: io_uring threads and worker threads
|
|
start before mount(), ensuring they're ready to handle requests.
|
|
|
|
5. **Better error reporting**: Mount failures and initialization errors
|
|
can be properly reported to the parent process when using the new
|
|
daemonization API.
|
|
|
|
|
|
When Synchronous FUSE_INIT is Used
|
|
-----------------------------------
|
|
|
|
libfuse automatically enables synchronous FUSE_INIT when:
|
|
|
|
1. The application calls fuse_session_want_sync_init(), OR
|
|
2. The new daemonization API is used (fuse_daemonize_start() was called)
|
|
|
|
Synchronous FUSE_INIT requires:
|
|
- Kernel support (commit dfb84c330794 or later)
|
|
- Worker thread started before mount()
|
|
- ioctl(FUSE_DEV_IOC_SYNC_INIT) succeeds
|
|
|
|
If the kernel doesn't support synchronous FUSE_INIT, libfuse automatically
|
|
falls back to asynchronous mode.
|
|
|
|
|
|
Implementation Details
|
|
----------------------
|
|
|
|
The synchronous FUSE_INIT implementation uses a worker thread:
|
|
|
|
- **session_sync_init_worker()**: Thread function that polls /dev/fuse
|
|
and processes FUSE_INIT and any subsequent requests until mount completes.
|
|
|
|
- **session_start_sync_init()**: Creates the worker thread before mount().
|
|
Calls ioctl(FUSE_DEV_IOC_SYNC_INIT) to enable kernel support.
|
|
|
|
- **session_wait_sync_init_completion()**: Waits for the worker thread
|
|
to complete after mount() returns. Checks for errors.
|
|
|
|
The worker thread processes requests in a loop until se->terminate_mount_worker
|
|
is set, which happens after mount() completes successfully.
|
|
|
|
|
|
Compatibility
|
|
-------------
|
|
|
|
Synchronous FUSE_INIT is fully backward compatible:
|
|
|
|
- Old kernels: ioctl returns ENOTTY, libfuse falls back to async mode
|
|
- Old applications: Continue to work with async FUSE_INIT
|
|
- New applications on old kernels: Graceful fallback to async mode
|
|
- New applications on new kernels: Automatic sync mode when appropriate
|
|
|
|
|
|
Example: Enabling Synchronous FUSE_INIT
|
|
----------------------------------------
|
|
|
|
Explicit request:
|
|
struct fuse_session *se = fuse_session_new(...);
|
|
fuse_session_want_sync_init(se);
|
|
fuse_session_mount(se, mountpoint);
|
|
|
|
Automatic (with new daemonization API):
|
|
fuse_daemonize_start(0); // Triggers sync init automatically
|
|
fuse_session_mount(se, mountpoint);
|
|
|
|
|
|
See Also
|
|
--------
|
|
|
|
- doc/README.daemonize - New daemonization API documentation
|
|
- doc/README.fusermount - Synchronous FUSE_INIT protocol with fusermount3
|
|
- doc/README.mount - Mount implementation details
|
|
|