Repository navigation
mount: explore FUSE passthrough over the persistent on-disk cache (stock WSL2 kernel already has CONFIG_FUSE_PASSTHROUGH) #93
Description
Activity
The sequencing note on #118 turned out to be wrong, in this issue's favour
I suggested on #118 that landing this first would make the inotify bridge substantially smaller, and
that the event path wanted the same mount infrastructure as the data path. Neither held up. #119
merged without touching passthrough, without a newer libfuse, and without a persistent on-disk cache:
the bridge raises events by replaying each far-side change as an ordinary syscall against the mount,
so the only thing it needs from the mount is that the mount exists.Two consequences worth recording here.
This issue is not blocking anything. It was filed as exploratory and the reason to defer it —
that it should be scoped only after the persistent on-disk cache exists, and after the cheap wins
land — is unchanged. Nothing now waits on it.One assumption in the sketch needs re-checking against what #119 established. The sketch has
reads bypassing wsldrive entirely once a file is registered as a backing id. The change-notification
path now depends on the mount seeing operations:op_getattranswers the bridge's own lookups, and
op_create/op_unlink/op_renamerecognise its pokes. Those are metadata operations, so
passthrough ofread/writeshould not disturb them — but it is worth confirming rather than
assuming, because a passthrough handle that also servicedopenwould take the bridge's create poke
out of the daemon's view, and the failure mode there is silent (the poke gets forwarded to the agent
instead of recognised, which is how #119 briefly destroyed file content on the served side before CI
caught it).Also relevant to the "is passthrough worth the dependency" question: the boundary is no longer the
only thing Direction B is competing on. Change notification is a capability virtiofs does not have,
and it costs nothing on the data path.🤖 Generated with Claude Code
Both prerequisites are now satisfied on a stock distro — the libfuse blocker is gone
This issue records that
FUSE_CAP_PASSTHROUGH/backing_idwere absent from the installed libfuse
3.14.0, landed in 3.17, and would therefore mean "bundling or requiring a newer libfuse". That is no
longer true here. Ubuntu 26.04's stocklibfuse3-dev:libfuse: 3.18.2 kernel: 6.18.33.2-microsoft-standard-WSL2 /usr/include/fuse3/fuse_common.h:500: #define FUSE_CAP_PASSTHROUGH (1UL << 29) /usr/include/fuse3/fuse_common.h:119: int32_t backing_id; /usr/include/fuse3/fuse_lowlevel.h:1455: int fuse_passthrough_open(fuse_req_t req, int fd); /usr/include/fuse3/fuse_lowlevel.h:1456: int fuse_passthrough_close(fuse_req_t req, int backing_id);Kernel side unchanged from what this issue verified:
CONFIG_FUSE_PASSTHROUGH=y. So requirement 2
costs nothing on a current distro, and only matters for the release binaries, which are built against
GCC 12 / Ubuntu 22.04 for compatibility — that is where the version floor would still bite, not on
the development machine.Three things the headers add to the sketch:
fuse_passthrough_openis offered onopen,opendirandcreate, and returns a backing id
to put infi->backing_id. Requirement 1 in this issue — that it needs a real file to point at —
is confirmed by the API shape rather than inferred.- One backing id per node, per the doc comment ("Currently there should be only one backing id
per node / backing file"), which constrains how the cache would have to key registrations. - Stacking depth is capped at 1 backing file, because the kernel's
FILESYSTEM_MAX_STACK_DEPTHof 2 counts the passthrough layer itself. A cache file on an ordinary
ext4 is fine; a cache file that itself lived on another stacked filesystem would not be.
Unrelated but worth recording while I was in there
The same kernel now reports
CONFIG_FUSE_IO_URING=y, which was not in this issue's original
capability dump. That is a different lever on the same floor — it cuts per-request overhead for the
whole FUSE path rather than bypassing it for reads only — and unlike passthrough it needs no backing
file, so it does not depend on the persistent on-disk cache existing first. Might be the cheaper
experiment of the two. Not filing it separately unless you want it as its own issue.Status unchanged
Still exploratory, still correctly deferred behind the persistent on-disk cache. This only removes
one of the two stated obstacles and sharpens the sketch; nothing here argues for scoping it now.🤖 Generated with Claude Code
Idea
FUSE passthrough lets the kernel service
read()andwrite()on a FUSE file directly againsta backing file descriptor, with the userspace daemon out of the data path entirely. Reads then
run at native filesystem speed with zero upcalls.
This is the one kernel-level mechanism that could actually lower the Direction B serving floor
past what userspace tuning reaches, and it needs no custom kernel and no out-of-tree module.
It is compiled into the stock WSL2 kernel already. Verified on this machine:
What it requires
this only pays off once cached file content is materialized on disk inside the VM. That makes
it a natural rider on the already-planned persistent on-disk cache follow-up rather than a
standalone change.
FUSE_CAP_PASSTHROUGH/backing_idAPI is not in the installedlibfuse 3.14.0 (no matches in
/usr/include/fuse3/); it landed in libfuse 3.17. So this meansbundling or requiring a newer libfuse, and keeping a non-passthrough fallback path.
Sketch
as a backing id and return the passthrough handle. Reads bypass wsldrive completely.
it, so the write-through path needs a different mechanism (or passthrough stays read-only).
Status
Exploratory. Filed to record the finding and the verified kernel support. Should be scoped
only after the persistent on-disk cache exists, and after the cheap wins land, since those may
move the floor far enough that this is not worth the dependency on a bundled libfuse.
Context
Came out of an assessment of whether a custom WSL2 kernel module would speed up the boundary.
Conclusion was no: Direction A never touches the Linux kernel on its fast path, and virtiofs is
the in-kernel path yet measures ~20x slower here than wsldrive's userspace FUSE mount
(7686 ms vs 383 ms reading 3000 files). Passthrough is the exception worth keeping on the list
because it is a stock-kernel feature, not a module.