Split ServiceVerb repo-state check into intent-specific predicates - #2058
Merged
tyrielv merged 1 commit intoJul 14, 2026
Merged
Conversation
`gvfs service --unmount-all` intermittently failed with exit code 3 and "Already unmounting, please wait" when the service registry still listed a repo whose GVFS.Mount process was in the transient Unmounting state (a concurrent or prior unmount still shutting it down). The single IsRepoMounted helper returned true whenever the mount pipe merely answered a GetStatus request, regardless of the actual MountState, so --unmount-all would attempt to unmount a repo already on its way out and treat that transient state as a hard failure. Replace IsRepoMounted with three intent-specific predicates built on a TryGetRepoMountStatus primitive that reads the actual MountState: - IsRepoReady (Ready) -> --list-mounted - IsRepoAvailableToMount (no live process) -> --mount-all - IsRepoAvailableToUnmount (Ready|MountFailed) -> --unmount-all --unmount-all now skips repos that are Unmounting (already reaching the desired state) or Mounting (an unmount request would be rejected anyway), eliminating the spurious failure. --list-mounted now reports only fully-Ready repos. --mount-all behavior is unchanged (it still mounts only when no live mount process is answering). StatusVerb exposes the "Mount status: " output prefix as a shared constant so ServiceVerb recovers the MountState without re-implementing the pipe protocol. Fixes the flaky GVFS.FunctionalTests.Tests.MultiEnlistmentTests.ServiceVerbTests.ServiceCommandsWithNoRepos. Assisted-by: Claude Opus 4.8 Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
tyrielv
marked this pull request as ready for review
July 10, 2026 17:26
tyrielv
enabled auto-merge
July 10, 2026 17:26
Keith Klein (KeithIsSleeping)
approved these changes
Jul 14, 2026
Merged
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.
Problem
gvfs service --unmount-allintermittently fails with exit code 3 andAlready unmounting, please wait, surfacing as the flaky functional testGVFS.FunctionalTests.Tests.MultiEnlistmentTests.ServiceVerbTests.ServiceCommandsWithNoRepos.Root cause
The service verbs (
--list-mounted,--mount-all,--unmount-all) iterate the service's global repo registry and used a singleIsRepoMounted(repoRoot)helper. That helper returnedtruewhenever the mount named pipe merely answered aGetStatusrequest — regardless of the actualMountState.StatusVerbreports success as long as it can connect, so aGVFS.Mountprocess in the transientUnmountingstate (a concurrent or prior unmount still shutting it down) counts as "mounted."--unmount-alltherefore attempts to unmount a repo that is already on its way out, gets the transientAlready unmountingresponse from the mount process, and treats it as a hard failure — even though the desired end state (repo unmounted) is already being reached.Fix
Replace
IsRepoMountedwith three intent-specific predicates, all built on aTryGetRepoMountStatusprimitive that reads the actualMountState:IsRepoReadyMountState == Ready--list-mountedIsRepoAvailableToMount--mount-allIsRepoAvailableToUnmountMountState ∈ {Ready, MountFailed}--unmount-all--unmount-allnow skips repos that areUnmounting(already reaching the desired state) orMounting(an unmount request would be rejected anyway), eliminating the spurious failure.StatusVerbexposes the"Mount status: "output prefix as a shared constant soServiceVerbrecovers theMountStatewithout re-implementing the pipe protocol (and without changingStatusVerb's worktree/enlistment resolution, so there's no behavior regression for worktree mounts).Behavior changes
--unmount-all: skips repos inUnmounting/Mountinginstead of failing on them. (The fix.)--list-mounted: now reports only fully-Readyrepos (previously also listedMounting/Unmounting/MountFailedprocesses that happened to answer the pipe).--mount-all: unchanged — still mounts only when no live mount process is answering.Testing
dotnet build GVFS\GVFS\GVFS.csproj -c Debug, 0 warnings).ServiceVerbTestsfunctional suite (ServiceCommandsWithNoRepos,ServiceCommandsWithMultipleRepos,ServiceCommandsWithMountAndUnmount), whose expectations remain consistent with the new state-aware behavior. There is no unit-test seam for the service verbs (they require a live service pipe).Related
This is the first of a set of fixes for the same flaky test. Two follow-ups are tracked separately: closing the mount-process lifecycle gap (a repo committed to unmounting still presents as a normal mounted repo to concurrent callers), and scoping the functional-test service registry so the global
--mount-all/--unmount-allverbs can't reach across parallel fixtures.