Mount: don't block startup on auth when cache server is configured - #2034
Merged
Conversation
tyrielv
force-pushed
the
tyrielv/mount-timeout
branch
2 times, most recently
from
June 19, 2026 18:35
223b028 to
95cc5ad
Compare
tyrielv
marked this pull request as ready for review
June 19, 2026 18:39
tyrielv
force-pushed
the
tyrielv/mount-timeout
branch
3 times, most recently
from
June 22, 2026 15:19
a3289c3 to
a0563de
Compare
tyrielv
force-pushed
the
tyrielv/mount-timeout
branch
4 times, most recently
from
June 22, 2026 15:43
d1b3d52 to
8419896
Compare
tyrielv
force-pushed
the
tyrielv/mount-timeout
branch
from
June 22, 2026 18:25
8419896 to
1d5d39b
Compare
When a cache server URL is already in local git config, mount no longer waits for /gvfs/config authentication to complete before proceeding. Auth runs as a fire-and-forget background task so GCM can pop up a renewal prompt for stale tokens without delaying mount. Changes: 1. Background auth with cache server — InProcessMount only awaits the network task when there is NO cache server. With a cache server, mount proceeds immediately after local validations. 2. Credential gate — A SemaphoreSlim in GitAuthentication serializes all git-credential-fill calls so a background auth task and a foreground object download never spawn duplicate GCM prompts. 3. Process tracking in MountVerb — WaitUntilMounted now uses short- interval (500ms) connect retries with process liveness checks instead of a single 60-second blocking connect. If GVFS.Mount exits early (e.g., crash), MountVerb detects it within 500ms. 4. Auth/network retry progress — ConfigHttpRequestor reports retry failures into the mount progress message so users see live status instead of a frozen spinner. 5. Skip config retries with cache server — TryInitializeAndQueryGVFS Config uses maxRetries:0 (single attempt) when a cache server is configured. No point retrying when the result would be discarded. 6. Distinct exit codes for mount startup failures: - CredentialTimeout (10): git-credential-fill hung for 30s - RemoteGvfsConfigError (11): /gvfs/config query failed (non-auth) - AuthenticationError (9): credentials rejected by server 7. 30s credential timeout during mount — When no cache server is configured, git-credential-fill has a 30-second timeout so mount fails fast with exit code 10 instead of hanging indefinitely. With a cache server, no timeout (GCM can take as long as needed). 8. ICredentialStore gains timeoutMs parameter — allows callers to bound credential fetch duration without changing the interface contract for existing callers (default: infinite). Signed-off-by: Tyrie Vella <tyrielv@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
tyrielv
force-pushed
the
tyrielv/mount-timeout
branch
from
June 22, 2026 18:41
1d5d39b to
43ef3e2
Compare
Keith Klein (KeithIsSleeping)
approved these changes
Jun 23, 2026
Merged
This was referenced Jul 13, 2026
tyrielv
added a commit
that referenced
this pull request
Jul 13, 2026
…-auth PR #2034 changed mount so that, when a cache server URL is already configured in local git config, authentication and the /gvfs/config query run as a fire-and-forget background task instead of blocking mount startup. As part of GVFS 2.0 stabilization we want that behavioral change to be off by default and opt-in, while keeping the associated diagnostic/reliability improvements (the distinct startup exit codes, the bounded credential timeout, and the cache-server fallback) always on. This adds a git-config flag, gvfs.background-cache-auth (default false), that gates only the fire-and-forget behavior: - Flag off (default): mount blocks on auth + /gvfs/config synchronously before starting virtualization, even when a cache server is configured. Because the network task is awaited, the fetched config is used and a synchronous (Default) credential timeout applies. - Flag on: the #2034 background behavior — mount proceeds without waiting on auth, using the local cache server URL, with the longer background credential timeout. The gate is a single derived condition, useBackgroundAuth = hasCacheServer && flag, applied to the wait decision, the credential-timeout selection, and the source of serverGVFSConfig. The pre-existing cache-server fallback, the startup exit codes, and ValidateGVFSVersion leniency remain keyed on hasCacheServer and are unchanged. The flag is read via libgit2 in-process (a short-lived LibGit2Repo, since the GVFSContext is not created until later in mount), defaulting to off on any failure. Isolated to GVFSConstants.cs and InProcessMount.cs; does not touch GitAuthentication.cs, so it does not conflict with the separate fix that hardens TryGetCredentials against being called before initialization completes. Assisted-by: Claude Opus 4.8 Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
tyrielv
added a commit
that referenced
this pull request
Jul 14, 2026
When a cache server is configured locally, mount starts virtualization without waiting for the background auth/config query (PR #2034). During that window, TryInitializeAndQueryGVFSConfig has already published IsAnonymous=false but has not yet set isInitialized (the credential fetch runs in between). A directory enumeration that arrives in this window flows through HttpRequestor.SendRequest -> GitAuthentication.TryGetCredentials, which threw InvalidOperationException("must be initialized"). Thrown into the ProjFS StartDirectoryEnumerationAsyncHandler callback, this crashed the mount process: StartDirectoryEnumerationAsyncHandler caught unhandled exception, exiting process Fix: instead of throwing when called before initialization, TryGetCredentials now waits (bounded by InitializationWaitTimeoutMs, defaulting to the background credential timeout) for initialization to complete, then proceeds normally. If initialization never completes within the timeout it returns a retryable failure rather than crashing. All initialization terminal paths signal a ManualResetEventSlim via a new MarkInitialized() helper. This is isolated to GitAuthentication.cs so it can land independently of the separate change that will gate the background cache-auth behavior behind a config flag. Adds deterministic unit tests that reproduce the race: reintroducing the throw fails them; the fix makes them pass. Assisted-by: Claude Opus 4.8 Signed-off-by: Tyrie Vella <tyrielv@gmail.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.
Problem
A user reported 'Unable to mount because the GVFS.Mount process is not responding' when GCM was blocked waiting for interactive auth on a headless server. The mount process was alive but stuck in
git credential fill, and MountVerb's 60-second pipe connect expired with a misleading error.More broadly: when a cache server URL is already in local git config, there's no reason for mount to block on authentication. The enlistment can serve objects from the local cache immediately, and knows the cache server to use when not available locally. If a cache server has not been configured already though (or explicitly set to not use cache server) then the mount should try to configure one upon startup.
Fix
Background auth with cache server — When a cache server URL is configured locally, the auth + config query runs as a fire-and-forget background task. Mount proceeds immediately after local validations complete. GCM still gets a chance to pop up a renewal prompt so the token is fresh for subsequent object downloads, but it cannot delay mount.
Without a cache server — auth remains synchronous and blocking (as before), but with better diagnostics:
AuthenticationErrorCredentialTimeoutgit credential fillhung for 30s (GCM waiting for interactive auth nobody is answering)RemoteGvfsConfigError/gvfs/configquery failed for non-auth reasons (DNS, timeout, 5xx)Process tracking in MountVerb —
WaitUntilMountednow uses short-interval (500ms) connect retries with process liveness checks instead of a single blocking 60s connect. If GVFS.Mount exits early, MountVerb detects it within 500ms.Implementation details
SemaphoreSlim(1,1)inGitAuthenticationserializes allgit-credential-fillcalls. Prevents duplicate GCM prompts when the background auth task and foreground object downloads race to fetch credentials.git credential fillis killed after 30 seconds so mount fails fast with exit code 10 instead of hanging indefinitely. The timeout is added toICredentialStore.TryGetCredential(default infinite, preserving existing behavior for all other callers).ValidateGVFSVersionlogs but doesn'tFailMountAndExitwhen running as the background auth task, avoiding a race where the process could terminate after mount already reported success.GitAuthenticationmarks itself initialized even when credential fetch fails, soTryGetCredentialscan retry during later object downloads rather than throwingInvalidOperationException.