Skip to content

Some work on FUSE#306

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

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

Conversation

@cgwalters

Copy link
Copy Markdown
Collaborator

See commits for details.

cgwalters added 3 commits June 5, 2026 16:52
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) and expose it through both the command line and
the varlink RPC API, with an integration test exercising the FUSE mount
end to end.

CLI surface:
  - `cfsctl fuse-serve <image> <mountpoint>` serves an EROFS composefs
    image over FUSE from a file on disk.
  - `cfsctl oci mount --fuse[=<opts>]` FUSE-serves an OCI image's EROFS
    instead of doing a kernel composefs mount, so it works without
    fs-verity on the backing store. `--fuse=passthrough` opts into
    kernel-bypass reads (Linux 6.9+). Options are parsed via a small
    FuseOptions FromStr so the surface can grow without new flags.

Varlink surface:
  - `org.composefs.Repository.FuseServe` and `org.composefs.Oci.OciFuseMount`
    let a client drive FUSE mounts over the RPC socket. Both take a
    `wait` parameter: with `wait=true` the call blocks for the session;
    with `wait=false` the FUSE session is detached into a background task
    and the call returns once the mount is registered, so a caller can
    mount and then go on to use the filesystem.

The privileged_fuse_dumpfile_roundtrip integration test spawns
`cfsctl fuse-serve` as a subprocess, polls for mount readiness via st_dev
change, reads external files directly, and compares the dumpfile produced
by `cfsctl create-dumpfile` over the FUSE mount against the expected
output from write_dumpfile, asserting the FUSE implementation reports
every piece of metadata the dumpfile format captures. Uses
similar_asserts for readable diffs on mismatch.

Assisted-by: OpenCode (claude-sonnet-4-6)
Signed-off-by: Colin Walters <walters@verbum.org>
Implement readdirplus (combined readdir + lookup in one round-trip),
no-op forget (inode table is static for session lifetime), and
FOPEN_KEEP_CACHE on open replies.

Serve with one thread per logical CPU using FUSE_DEV_IOC_CLONE
(clone_fd=true) so each worker gets its own /dev/fuse fd, eliminating
per-request channel lock contention. Arc<OwnedFd> allows read() to
clone the handle and drop the mutex before calling pread, so concurrent
reads on the same file don't serialise.

Add FUSE passthrough support (Linux 6.9+): when FuseConfig::passthrough
is true and the kernel advertises FUSE_PASSTHROUGH, external file reads
are routed directly in-kernel to the repository object fds. Opt-in via
FuseConfig because passthrough requires root and a non-tmpfs backing
filesystem.

Assisted-by: OpenCode (claude-sonnet-4-6)
Signed-off-by: Colin Walters <walters@verbum.org>
@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

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