What is FUSE?
FUSE (Filesystem in Userspace) is a Linux kernel interface that lets a userspace program implement filesystem operations. The kernel exposes a special device, /dev/fuse. A userspace daemon reads filesystem requests from this device, executes them, and writes responses back. From a calling application's perspective, the mount behaves like any other filesystem.
This boundary moves the implementation out of the kernel: filesystem code runs as an ordinary process, in any language with FUSE bindings (C, Python, Go, Rust, and more). The trade-off is performance—every operation makes extra trips across the kernel/userspace boundary.
Why Userspace?
Writing a kernel filesystem is expensive in time and risk. A bug can panic the system; iteration requires a reboot or module reload; only C is practical; and only root can load the module.
A FUSE filesystem inverts these constraints. The implementation is a normal process:
- A crash terminates the daemon, not the kernel. The mount goes stale and can be unmounted and restarted.
- Iteration is a process restart, not a reboot.
- Any language that can read and write the FUSE protocol over
/dev/fuseworks. Bindings exist for C, Python, Go, Rust, and others. - A non-root user can mount a FUSE filesystem without sudo because
fusermountis setuid-root.
The cost is performance, which the rest of this page measures.
The Kernel/Userspace Boundary
This is THE key insight to understanding FUSE. Every Unix system has two worlds: kernel space (privileged, dangerous) and userspace (safe, restricted). FUSE bridges them.
A FUSE filesystem lives entirely on the userspace side of this boundary. The kernel-side participation is bounded to the FUSE module and /dev/fuse.
Request Flow
When an application reads a file on a FUSE mount, the request passes through the VFS layer, into the FUSE kernel module, out to the userspace daemon, and back. The diagram below walks through each step.
Each step of the path is:
- The application makes a syscall (
open,read,write). - The VFS layer receives the call and routes it.
- The FUSE kernel module intercepts requests for FUSE mounts and queues them on
/dev/fuse. libfuse, running in userspace, reads from the queue.- The user-written filesystem handler executes.
- The response travels back through the same path.
Notice the four kernel/userspace crossings—twice the round-trip cost of a native filesystem call.
# The key components: # 1. FUSE kernel module - handles kernel-side communication lsmod | grep fuse # 2. /dev/fuse - the bridge between kernel and userspace ls -l /dev/fuse # 3. Your FUSE daemon - runs in userspace, handles requests ps aux | grep myfs
The Performance Cost
The boundary crossings have a measurable cost. The demo below shows how syscall latency changes as the userspace handler's own work scales.
A native filesystem call crosses the kernel/userspace boundary twice (in and out). A FUSE call crosses four times:
- App → Kernel (syscall)
- Kernel → FUSE daemon (via /dev/fuse)
- FUSE daemon → Kernel (response)
- Kernel → App (return)
Compare to native filesystems: only two crossings (syscall in, return out).
FUSE in Practice
Several widely-used filesystems are built on FUSE. The gallery below shows the categories and representative implementations.
Implementing a FUSE Filesystem
A minimal FUSE filesystem needs to answer a handful of operations. The checklist below covers the required and commonly-overridden ones.
A Minimal Python Example
The following is a complete read-only FUSE filesystem that exposes a single file, /hello.txt.
#!/usr/bin/env python3 from fuse import FUSE, Operations import stat import errno class HelloFS(Operations): def getattr(self, path, fh=None): if path == '/': return {'st_mode': stat.S_IFDIR | 0o755, 'st_nlink': 2} if path == '/hello.txt': content = b'Hello from FUSE!\n' return { 'st_mode': stat.S_IFREG | 0o444, 'st_nlink': 1, 'st_size': len(content) } raise OSError(errno.ENOENT) def readdir(self, path, fh): return ['.', '..', 'hello.txt'] def open(self, path, flags): return 0 def read(self, path, length, offset, fh): if path == '/hello.txt': content = b'Hello from FUSE!\n' return content[offset:offset + length] raise OSError(errno.ENOENT) if __name__ == '__main__': import sys FUSE(HelloFS(), sys.argv[1], foreground=True)
Mount it:
pip install fusepy mkdir /tmp/hello python hello_fs.py /tmp/hello
Use it from another terminal:
ls /tmp/hello # hello.txt cat /tmp/hello/hello.txt # Hello from FUSE! fusermount -u /tmp/hello # unmount when done
That's the entire filesystem. Around thirty lines of Python is enough to expose a file in a mountable view.
Performance Optimization
Kernel Caching
FUSE can cache data in the kernel to reduce round-trips:
# Enable kernel page cache (default) ./myfs /mountpoint -o kernel_cache # Enable attribute caching ./myfs /mountpoint -o attr_timeout=60 # Disable caching for always-fresh data ./myfs /mountpoint -o direct_io
Batch Operations
For better throughput:
# Increase max read/write size ./myfs /mountpoint -o max_read=131072 -o max_write=131072 # Enable multi-threading ./myfs /mountpoint -o max_threads=16
Common Mount Options
# Allow other users to access the mount mount -o allow_other /dev/fuse /mountpoint # Set ownership mount -o uid=1000,gid=1000 ... # Read-only mount mount -o ro ... # Debug mode (foreground with verbose output) ./myfs -f -d /mountpoint
Debugging FUSE Filesystems
Verbose Logging
import logging logging.basicConfig(level=logging.DEBUG) def read(self, path, length, offset, fh): logging.debug(f"READ: {path}, len={length}, off={offset}") # ... implementation
Strace the FUSE Process
# Trace all system calls strace -p $(pidof myfs) -f # Just file operations strace -e open,read,write,close -p $(pidof myfs)
Common Issues
"Transport endpoint is not connected"
# FUSE daemon crashed - unmount and restart fusermount -u /mountpoint ./myfs /mountpoint
"Permission denied"
# Check /etc/fuse.conf has: user_allow_other # And mount with: -o allow_other
When to Use FUSE (and When Not To)
- Prototyping new filesystem ideas
- Network and cloud storage (SSHFS, rclone)
- Encryption layers (EncFS, gocryptfs)
- Format conversion (NTFS-3G)
- Archive mounting (archivemount)
- Database-as-filesystem experiments
- Boot and root filesystems
- High-performance databases
- Real-time applications
- Heavy concurrent workloads
- Systems requiring kernel-level reliability
The Future of FUSE
FUSE 3.x
The latest FUSE version brings:
- Better performance through improved caching
- Enhanced security model
- Splice support for zero-copy I/O
virtiofs
For virtual machines, virtiofs combines FUSE with virtio for near-native performance:
# Inside a VM, mount host directory mount -t virtiofs myfs /mnt/host
io_uring Integration
Future versions may use io_uring for:
- Reduced context switches via batching
- Better async I/O performance
FUSE made filesystem development practical outside the kernel. Before FUSE, a new filesystem meant kernel hacking; with FUSE, a working prototype is an afternoon's work. SSHFS, NTFS-3G, rclone, and many archive- and encryption-mounting tools all rely on this interface.
Further Reading
- libfuse - reference userspace library, including protocol documentation
- Linux Kernel: Filesystem in Userspace - kernel-side documentation
- virtio-fs - FUSE-style sharing for virtual machines
Related concepts
Learn the Btrfs filesystem with built-in snapshots, RAID, and compression. Explore copy-on-write, subvolumes, and self-healing on Linux.
Understand Copy-on-Write (CoW) in Btrfs and ZFS. Learn how CoW enables instant snapshots, atomic writes, and data integrity.
Explore ext4, the default Linux filesystem with journaling, extents, and proven reliability. Learn how ext4 protects your data.
Learn FAT32 and exFAT filesystems for cross-platform USB drives and SD cards. Understand file size limits and compatibility.
Learn how filesystem journaling prevents data loss during crashes. Explore write-ahead logging and recovery in ext4 and XFS.
Explore Linux filesystems through interactive visuals. Learn VFS, compare ext4 vs Btrfs vs ZFS, and understand file operations.
