Skip to content

macOS: reply-error resilience, mount option joining, reply-drop log demotion#1

Open
dlicudi wants to merge 19 commits into
samsoir:masterfrom
dlicudi:feat/macos-mount-options
Open

macOS: reply-error resilience, mount option joining, reply-drop log demotion#1
dlicudi wants to merge 19 commits into
samsoir:masterfrom
dlicudi:feat/macos-mount-options

Conversation

@dlicudi

@dlicudi dlicudi commented Jul 10, 2026

Copy link
Copy Markdown

Carries the three macOS patches that XEarthLayer's macOS port (feat/macos-port-clean) depends on, based cleanly on current upstream master. Offered here per the review discussion, so XEarthLayer does not have to pin a personal fork.

Commits

  1. 849e84c fix(macos): don't kill the session on a transient reply error — macFUSE can drop replies transiently; without this the whole FUSE session dies mid-flight. Also pending upstream as fix(macos): don't kill the session on a transient reply error Sherlock-Holo/fuse3#137.
  2. 43b2ee0 fix(macos): comma-join mount options so all -o flags apply — macFUSE only honors the first -o flag unless options are comma-joined; without this, mount options past the first were silently ignored.
  3. 74abf55 fix(macos): log recoverable reply drops at debug, not warn — recoverable per-syscall reply drops flooded logs at warn level.

Notes

  • This repo's master is currently 16 commits behind upstream — after a "Sync fork" on master, this PR shrinks to exactly the 3 commits above.
  • XEarthLayer's feat/macos-port-clean currently pins dlicudi/fuse3 rev 74abf55 (the head of this branch); once this is merged, the pin will be repointed to this repo.
  • Patches 2 and 3 are also candidates for upstreaming to Sherlock-Holo/fuse3 alongside fix(macos): don't kill the session on a transient reply error Sherlock-Holo/fuse3#137, which would shrink the fork delta over time.

🤖 Generated with Claude Code

antialize and others added 19 commits March 3, 2026 10:15
Move the sending of responses from the mount task into the the responding tasks.
This allows us to borrow references to the constructed structs so that we
do not need to allocate vectors to send around.

Add a new notify instance, to stop the mount task in case of a write error
Use zerocopy to get rid of many allocations.
* ci: move to github ci

the cirrus compute credits is too few

* ci: update freebsd version
Fix the docs build with Rust nightly 1.92.0 and later
ci: remove ca_root_nss workaround for FreeBSD
handle_getxattr was sending `error: libc::ERANGE` (positive 34) in the
fuse_out_header when returning ReplyXAttr::Size. The FUSE protocol
requires negative errno values for errors and 0 for success. The Linux
kernel rejects positive error codes:

    if (oh->error <= -512 || oh->error > 0) {
        req->out.h.error = -EIO;

This caused all getxattr size queries (size=0) to fail.

The fix matches handle_listxattr, which already correctly uses error: 0
for the same Size reply path, and matches libfuse's fuse_reply_xattr
which uses send_reply_ok (error=0).

Fixes Sherlock-Holo#130
fix: use error=0 for getxattr Size reply instead of ERANGE
…to ReplyInit

Allow filesystems to override the kernel's default FUSE background request
limits during init. The kernel defaults (max_background=12,
congestion_threshold=9) are too low for high-concurrency workloads where
many parallel reads are expected.

Adds two optional fields to both `raw::ReplyInit` and `path::ReplyInit`:
- `max_background: Option<u16>` - max pending background requests
- `congestion_threshold: Option<u16>` - throttling threshold

When `None`, the kernel defaults are preserved (backward compatible).

Both `ReplyInit` structs are marked `#[non_exhaustive]` with a `new()`
constructor so future fields can be added without breaking downstream code.
…ound

feat(init): add configurable max_background and congestion_threshold to ReplyInit
macFUSE can transiently reject a reply write to /dev/macfuse with EINVAL
(or EAGAIN/EINTR) under heavy concurrent load — e.g. while Spotlight
crawls the mount. The session loop treated ANY non-NotFound reply-send
failure as fatal (send_failed.notify -> session returns Err), so a single
transient failure tore down the whole mount and left it wedged (every
later op ENXIO).

Route send1/send2/send3's error handling through a shared
handle_send_error that treats transient, per-request errors (ENOENT,
EINVAL, EAGAIN, EINTR) as recoverable — drop that one reply and keep
serving — while connection-gone errors (ENODEV/EBADF on unmount) stay
fatal so a clean unmount still stops the session. Policy extracted to a
pure is_recoverable_reply_error fn with unit tests.
macOS build() emitted repeated space-separated -o flags as a single mount-
helper argument, so every option after the first (allow_root, allow_other, or
caller custom_options like nobrowse) was silently dropped. Join with commas
under one -o, matching the Linux builder.
A recoverable reply-send failure (interrupted/cancelled request) is the
expected, harmless case the resilience patch exists to absorb. macOS file
browsers crawl the mount and routinely interrupt their own requests, so these
occur tens of times per second under normal use — logging each at WARN floods
the log. Demote to debug; the session-continues handling is unchanged.
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.

7 participants