Mounting and lifecycle
Mount a backend, choose platform options, keep the session alive and unmount cleanly.
MountSession turns a backend into a live volume. It owns the mount and the service that
answers the kernel, so the mounted filesystem lasts exactly as long as the session value.
Mount
Every platform exposes the same four constructors:
All of them take the backend by value and return io::Result<MountSession>. The call is
synchronous and returns once the mount exists: after mount(8) succeeds on macOS, after the
FUSE session starts on Linux, and after PrjStartVirtualizing succeeds on Windows.
The session owns the backend; there is no handle back to it. Keep any state you need to reach
from elsewhere in your own Arc, not through the session.
The mount directory
The directory is created if it is missing on all three platforms. It is not removed when the mount stops.
macOS additionally canonicalises the path before mounting, so mount_path() may differ from
what you passed: /tmp/my-volume becomes /private/tmp/my-volume. The canonical path is what
diskutil receives when the session unmounts.
macOS and Linux do not check whether the directory is empty: the session creates the path and
mounts over it, and a busy or invalid path is reported by mount(8) or FUSE. Windows does:
ProjFS requires an empty directory or one already initialized as a virtualization root, and
rejects anything else before the mount starts.
Dropping the session unmounts:
unmount(self) is the explicit form. On macOS it returns io::Result<()>; on Linux and Windows
it returns () because the drop path has no error to report.
Options
Only the fields that change behaviour are listed. Defaults come from MountOptions::default().
macOS:
Linux:
Windows:
MountOptions::read_only and filesystem_name are declared on Windows but are not applied when
the projection starts. A Windows mount is not made read-only by that flag; enforce read-only
through metadata (mode without write bits) and open_file instead. There is also no volume
name or statfs display on Windows.
Threads and shutdown
Mounting is a blocking call, but serving is not: the session starts the threads that answer the kernel and returns. macOS runs an accept loop plus one thread per IPC connection, Linux runs its FUSE dispatchers, and Windows uses the ProjFS pool.
Treat the mount call itself as blocking work. In an async application, call it from
spawn_blocking or a dedicated thread rather than on a runtime worker. The same applies to
fsk::install(), which downloads and verifies FSK.app synchronously.
The session must outlive the mount. A common shape is a dedicated thread that owns the value and waits for a stop flag:
On macOS, call session.unmount()? instead of dropping when you want to see a diskutil
failure. On Linux, stopping waits for in-flight dispatcher calls, so a backend method that never
returns keeps the session alive. Do not block indefinitely inside a trait method.
Mount failures
Most failures happen before your backend is called.
For macOS, read the mount(8) stderr before blaming the backend: a disabled extension and a
mount path already in use produce different messages there. On Linux, the mounting user also
needs permission to use /dev/fuse, which is separate from the crate.
Next
- Network filesystems for
mount_network, local files and leases. - Platform setup for the host-side prerequisites in detail.
- Troubleshooting maps the messages above to fixes.
