Skip to content

fix(fuse): handle shutdown run_all errors (#1082)#1175

Merged
yangcx000 merged 2 commits into
CurvineIO:mainfrom
ligeng8848:fix/1082-handle-run-all-errors
Jul 17, 2026
Merged

fix(fuse): handle shutdown run_all errors (#1082)#1175
yangcx000 merged 2 commits into
CurvineIO:mainfrom
ligeng8848:fix/1082-handle-run-all-errors

Conversation

@ligeng8848

Copy link
Copy Markdown
Contributor

Summary

Inspect both result layers when awaiting the spawned run_all task during signal shutdown. Termination shutdown now logs receiver/sender failures, while SIGUSR1 refuses to persist state after a failed shutdown.

Issue Describe / Design

Closes #1082

Root cause: the TERM and SIGUSR1 branches only checked the outer Tokio JoinError and silently ignored an inner Ok(Err(...)) returned by run_all.

Fix approach: flatten the nested join result in one helper and use it in both signal branches. TERM records the failure and continues normal unmount; SIGUSR1 returns the failure without persisting potentially unreliable state.

Changes

Module / File Change Impact on existing behavior
curvine-fuse/src/session/fuse_session.rs Inspect both layers of the run_all result and add regression tests Fatal shutdown errors are no longer silently ignored

Test verified

Test case Result Notes
cargo test -p curvine-fuse --lib run_all_shutdown_result_tests -- --nocapture PASS 3 passed
cargo test -p curvine-fuse --lib session::fuse_session -- --nocapture PASS 10 passed
cargo clippy -p curvine-fuse --lib --tests -- -D warnings PASS No warnings
make format PASS Repository pre-commit checks
Real /dev/fuse mount and SIGTERM smoke test PASS Read/write succeeded; process exited and mount was removed

Dependencies

@ligeng8848
ligeng8848 marked this pull request as ready for review July 17, 2026 08:29
Comment thread curvine-fuse/src/session/fuse_session.rs Outdated
@yangcx000
yangcx000 self-requested a review July 17, 2026 15:11

@yangcx000 yangcx000 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — nicely scoped fix for a real bug, verified against the code.

Root cause confirmed. run_all returns CommonResult<()> and is tokio::spawn-ed, so run_all_handle.await is Result<CommonResult<()>, JoinError> — genuinely double-layered. The old if let Err(e) = run_all_handle.await in both signal arms matched only the outer JoinError and silently dropped an inner Ok(Err(..)). Good that the tokio::select! first arm already destructures all three cases, so scoping the fix to the two re-await sites (and leaving that arm untouched, since it needs the distinct RUN_ALL_ERROR/RUN_ALL_PANIC metrics) is exactly right.

The two arms diverge correctly. TERM logs and continues to unmount, while SIGUSR1 refuses to persist and returns — the safe split: a hot-upgrade persist should not serialize potentially-inconsistent state, and falling back to a clean unmount via the mnts drop is the right default. I verified the auto_unmount timing the comment describes: FuseMnt::auto_unmount defaults to true and is only flipped to false inside persist_inner, so the return Err path drops mnts with auto-unmount still on (mounts torn down), while a persist error happens after that flag is cleared (mounts stay). RunCleanupGuard's early-return Drop is correct too. err.into() resolves cleanly to CommonError (JoinError: Error + Send + Sync), and the three unit tests cover all three branches.

One optional, non-blocking nit: the helper's doc-comment says the flatten guards against "a clean task join [hiding] a real receiver/sender error." Looking at run_all, the functional receiver/sender errors (start().await returning Err) are already logged-and-swallowed inside the spawned closures, which return (). The only way run_all yields an inner Err is handle.await? propagating a child accept/send task that panicked or was aborted — so the wording is slightly off; consider "so a clean join of the run_all task cannot hide a panic in one of its child accept/send tasks." The fix's value (surfacing those panics at shutdown) is real regardless. Also join_error_is_preserved's contains("cancelled") softly couples to tokio's Display wording — fine to keep, or relax to is_err(). Neither is blocking.

@yangcx000
yangcx000 merged commit 43165a3 into CurvineIO:main Jul 17, 2026
4 of 5 checks passed
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.

[FEATURE] fuse: handle run_all Ok(Err) in signal shutdown branches (by LiAuto)

3 participants