Repository navigation
FUSE3: do not clear fuse_config in init - #110
Open
peerbit-org wants to merge 1 commit into
Open
peerbit-org wants to merge 1 commit into
peerbit-org wants to merge 1 commit into
Conversation
hostAsgnCconfig zeroed the struct fuse_config that libfuse 3 passes to init. That struct is the live configuration parsed by fuse_new, so the memset silently reset entry_timeout, attr_timeout and negative_timeout (and any other -o option) to 0 on every FUSE 3 mount. The kernel then sends a LOOKUP per path component and a GETATTR per stat, and -o entry_timeout=/attr_timeout= options have no effect. Keep libfuse's parsed configuration and only set the fields cgofuse owns (direct_io, use_ino). FUSE 2 builds are unaffected (the function is empty there).
peerbit-org
added a commit
to dao-xyz/peerbit-examples
that referenced
this pull request
Sep 29, 2026
* perf(shared-fs): cache Linux mount names for 0.1 s cgofuse v1.6.0's hostAsgnCconfig memsets libfuse 3's live fuse_config at init, so every entry/attr/negative timeout was 0 on Linux and each lstat cost one LOOKUP per path component plus a GETATTR (~0.2 ms each over IPC). - go.mod replaces cgofuse with github.com/dao-xyz/cgofuse v1.6.0-peerbit.1 (v1.6.0 minus the memset line; winfsp/cgofuse#110 is open so the replace can be dropped later). macOS (FUSE 2.8) and Windows (nocgo WinFsp) compile the same code as before. - Linux mounts with -o entry_timeout=0.1,attr_timeout=0,negative_timeout=0: names cached for at most 0.1 s, attributes and missing names never. The fork and the -o land together; the fork alone would give libfuse's 1 s defaults. macOS keeps macFUSE's 1/1/0 defaults, Windows is unchanged. - On Linux, Open maps the daemon's ENOENT to -ESTALE (116), so a create without O_EXCL on a name another peer removed within the name cache window is retried by the kernel with a fresh lookup instead of failing. Getattr (which also answers LOOKUP), Create and every other callback keep ENOENT. Profiles name the result ESTALE and the summarizer counts it as absent. - Native and CLI READMEs document each platform's caching and staleness; changeset for @peerbit/shared-fs-cli (patch). The release script publishes the matching shared-fs-native-v<version> adapter for the new CLI version. Measured on a GitHub Linux runner (runs 36515914255, 36526596414): stat of a 2-component path 3 -> 1 adapter callbacks, git status on 2,000 files 2.91 s -> 1.23 s, git clone 35.6 s -> 27.0 s; other peers' edits, deletes and renames visible with no added delay, a file replaced by a directory can fail once with EIO (next call correct), create right after a remote delete 0/10 failures, no lost appends. A local Linux FUSE container run of this commit reproduced the probe and showed 10/10 create failures at 0.1 s without the ESTALE mapping. * test(shared-fs): guard the Linux kernel cache policy in the profiled smoke When the external native smoke runs on Linux with a mount profile (PEERBIT_SHARED_FS_NATIVE_MOUNT_PROFILE_DIR, the Linux smoke workflow's mount_profile passes), it stats docs/hello.txt twice 20 ms apart after the cached names expired and, after unmount flushes the adapter profile, requires exactly one getattr callback inside the second stat's window. 3 means the -o timeouts did not reach the kernel (a cgofuse that clears libfuse's config again); 0 means attributes are cached. Unprofiled runs and macOS are unchanged. The Linux mounted benchmark also records the -o mount options it runs with. Checked on a local Linux FUSE 3.14 container (Docker, kernel 6.12): the guard passes on this branch, and fails with 3 on stock cgofuse and with 0 on the fork without the -o. * docs(shared-fs): scope the Linux name-cache staleness and stat-cost claims The native README and the changeset said a file/directory swap by another peer makes one operation fail with EIO and the next call succeed, and that a two-component stat costs one adapter callback instead of three. Both held only for what the probes measured. - Type changes: only a stat (GETATTR type mismatch) marks the inode bad, so it fails once with EIO and the next call is correct (measured, file -> directory). Opening the stale name (OPEN/OPENDIR answer EISDIR, ENOTDIR or EINVAL), following a stale symlink (readlink EINVAL) and walking a path through it (link_path_walk ENOTDIR) leave the dentry cached and can fail on every try for up to 0.1 s. Symlink swaps are now covered too. Marked as not measured. No errno mapping beyond ENOENT -> ESTALE. - Cost: one callback instead of three only for a stat repeated within 0.1 s of the path's last lookup; after the names expire the next stat again costs one per component plus one. git status/clone figures unchanged. Docs only; prettier --check passes. --------- Co-authored-by: peerbit-org <273107789+peerbit-org@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On FUSE 3,
hostAsgnCconfigzeroes thestruct fuse_configthat libfuse passes to theinitcallback:In libfuse 3 the high-level
initreceives&f->conf, the live configuration thatfuse_newalready filled from defaults and-ooptions. Clearing it setsentry_timeout,attr_timeoutandnegative_timeoutto 0 for the whole mount, so-o entry_timeout=…,attr_timeout=…are silently ignored on FUSE 3. The kernel then issues aLOOKUPfor every path component on every path syscall, and aGETATTRfor every stat.This PR removes the
memsetand keeps setting only the fields cgofuse owns (direct_io,use_ino). FUSE 2 builds are unaffected, because the function is empty there.Measured on Linux (Ubuntu 24.04, libfuse 3.14, kernel 6.17) with a cgofuse-based filesystem, counting filesystem
Getattrcallbacks:-o entry_timeout=0.1,attr_timeout=0,negative_timeout=0statof a 2-component pathgit statuson 2,000 files-ooptions to the stock build leaves the counts unchanged, which shows they were being wiped.One behaviour change for FUSE 3 users: without explicit
-ooptions they now get libfuse's defaults (entry and attr timeouts of 1 s) instead of 0. That matches FUSE 2 and macFUSE, and filesystems that need uncached attributes can pass-o attr_timeout=0.