fix(fuse): drain pipe on splice failure and handle ECONNABORTED#1299
Merged
szbr9486 merged 1 commit intoJul 25, 2026
Merged
Conversation
Harden the FUSE receive path against partial/failed splice frames and connection-abort errno: - splice(): on short splice, read_buf error, or read/write length mismatch, drain the pipe before returning so a poisoned pipe never leaks stale bytes into the next request frame. On the recoverable read_buf-error path this is load-bearing; on the two fatal-exit paths the drain is defensive (documented inline) in case they later become recoverable. - Add drain_pipe() helper (relies on the non-blocking fuse pipe: an empty pipe returns EAGAIN and stops the loop) and prepare_receive_buf() to centralize buffer reset/reserve/set_len. - Treat ECONNABORTED like ENODEV in the receive loop (graceful break), add its errno label, and cover it in receive_error_labels/tests. Log an info! line on both graceful-exit arms to distinguish a normal teardown from a hang in the field. - Fold short-read/short-splice/length-mismatch detail into the returned err_box! (logged once, at error level, when it propagates to fuse_session::start) instead of an extra error! at the site. Co-Authored-By: Claude <noreply@anthropic.com>
szbr9486
approved these changes
Jul 25, 2026
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.
What
Hardens the FUSE splice receive path against partial/failed frames and connection-abort errno.
splice()— on short splice,read_buferror, or read/write length mismatch, drain the pipe before returning so stale bytes never poison the next request frame.read_buf-error path (the returnederrcarries a real OS errno, so the receive loop maycontinue) the drain is load-bearing.err_box!carries no OS errno, so the loop hits_ => return Errand the receiver exits — there is no "next frame". The drain there is defensive (documented inline) in case those paths later become recoverable.drain_pipe()helper — relies on the non-blocking fuse pipe (PipeFd::new(_, false, false)): an empty pipe returnsEAGAIN(notEINTR), which stops the loop, so it cannot hang. Retries onlyEINTR.prepare_receive_buf()helper — centralizes bufferclear()/reserve()/set_len(). The addedclear()makes the buffer length deterministic before the unsafeset_len, a small correctness improvement over the previous in-placeset_len.ECONNABORTED— treated likeENODEVin the receive loop (gracefulbreak), with a matching errno label andreceive_error_labelstest coverage. Both graceful-exit arms now log aninfo!line to distinguish a normal teardown from a hang in the field.err_box!(logged once, at error level, when it propagates tofuse_session::start) rather than an extraerror!at the site.Testing
cargo fmt -p curvine-fuse -- --checkcargo clippy -p curvine-fuse --lib(clean)cargo test -p curvine-fuse --lib—fuse_receiver::+fuse_error::all pass🤖 Generated with Claude Code