Skip to content

Some work on FUSE#306

Draft
cgwalters wants to merge 2 commits into
composefs:mainfrom
cgwalters:fuse-lowlevel
Draft

Some work on FUSE#306
cgwalters wants to merge 2 commits into
composefs:mainfrom
cgwalters:fuse-lowlevel

Conversation

@cgwalters

Copy link
Copy Markdown
Collaborator

See commits for details.

@cgwalters cgwalters force-pushed the fuse-lowlevel branch 2 times, most recently from c0bac64 to fee56ca Compare June 5, 2026 21:02
@cgwalters

Copy link
Copy Markdown
Collaborator Author

I wanted to experiment with exporting my session transcripts, here's the main one for this https://gist.github.com/cgwalters/36736a05e572a80f208af8f8cb9b0822

fuser 0.17 is needed to support multithreaded FUSE sessions: the new
API requires `Filesystem: Send + Sync + 'static`, which forces proper
Arc-based ownership of the filesystem state and makes it possible to
safely hand the implementation to multiple worker threads.

The breaking API changes and how they are addressed:

- `&self` instead of `&mut self` on all trait methods: the only mutable
  state (open file handles) is now protected by a Mutex.
- New newtypes (INodeNo, FileHandle, LockOwner, Generation) and bitflags
  (OpenFlags, FopenFlags) — updated at call sites.
- readdir/read offsets changed from i64 to u64.
- Session::from_fd now takes SessionACL + Config separately.
- Session::run() is no longer public; replaced by spawn().join().
- reply.error() takes fuser::Errno instead of raw i32.

To satisfy the `'static` bound, serve_tree_fuse() now takes
`Arc<FileSystem>` and `Arc<Repository>`. A pre-built flat Vec<InodeData>
(indexed by ino-1) replaces the old HashMap<Ino, InodeRef<'a>>, removing
the lifetime that was incompatible with `'static`. An InodeLookup index
(path→ino for dirs, LeafId→ino for leaves) handles child ino resolution
without raw pointers.

Assisted-by: OpenCode (claude-sonnet-4-6)
Signed-off-by: Colin Walters <walters@verbum.org>
Wire the composefs-fuse crate into cfsctl behind a new `fuse` cargo
feature (on by default). The FUSE implementation supports readdirplus,
multithreaded serving via FUSE_DEV_IOC_CLONE, FOPEN_KEEP_CACHE, and
optional passthrough (Linux 6.9+, root only) for kernel-bypass reads on
external object files.

CLI surface:
  - `cfsctl mount --fuse[=passthrough] [--raw-image]` serves an image
    over FUSE instead of doing a kernel composefs mount. `--raw-image`
    reads a bare EROFS file from disk rather than looking up a repo image.
    This replaces the old `fuse-serve` subcommand; all mount paths now
    live under `mount`.
  - `cfsctl oci mount --fuse[=passthrough]` likewise for OCI images.

Varlink surface — the single `Mount`/`OciMount` methods now always
return a detached mount fd via SCM_RIGHTS, for both kernel and FUSE
backends. A new `MountPath`/`OciMountPath` pair handles the attach-to-
a-path case server-side (blocking until the FUSE session ends unless
`wait=false`). This makes FUSE mounts a proper first-class path: the
caller gets the fd and can move_mount it wherever it likes, with the
FUSE server running in the background for as long as the fd is held.

Also adds `erofs_fd_to_filesystem` in composefs-fuse to replace the
open-coded open_image → read_to_end → erofs_to_filesystem pattern that
appeared at every call site.

The privileged_fuse_dumpfile_roundtrip integration test spawns
`cfsctl mount --raw-image --fuse`, polls for mount readiness via st_dev
change, and compares the dumpfile produced over the FUSE mount against
the expected output from write_dumpfile.

Assisted-by: OpenCode (claude-sonnet-4-6)
Signed-off-by: Colin Walters <walters@verbum.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant