Skip to content

Mount: don't block startup on auth when cache server is configured - #2034

Merged
tyrielv merged 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/mount-timeout
Jun 29, 2026
Merged

Mount: don't block startup on auth when cache server is configured#2034
tyrielv merged 1 commit into
microsoft:masterfrom
tyrielv:tyrielv/mount-timeout

Conversation

@tyrielv

@tyrielv tyrielv commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

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:

Exit code Name Meaning
9 AuthenticationError Credentials rejected by server
10 CredentialTimeout git credential fill hung for 30s (GCM waiting for interactive auth nobody is answering)
11 RemoteGvfsConfigError /gvfs/config query failed for non-auth reasons (DNS, timeout, 5xx)

Process tracking in MountVerbWaitUntilMounted now 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

  • Credential gateSemaphoreSlim(1,1) in GitAuthentication serializes all git-credential-fill calls. Prevents duplicate GCM prompts when the background auth task and foreground object downloads race to fetch credentials.
  • 30s credential timeout (no-cache-server only)git credential fill is killed after 30 seconds so mount fails fast with exit code 10 instead of hanging indefinitely. The timeout is added to ICredentialStore.TryGetCredential (default infinite, preserving existing behavior for all other callers).
  • Version check is log-only in backgroundValidateGVFSVersion logs but doesn't FailMountAndExit when running as the background auth task, avoiding a race where the process could terminate after mount already reported success.
  • isInitialized on credential failureGitAuthentication marks itself initialized even when credential fetch fails, so TryGetCredentials can retry during later object downloads rather than throwing InvalidOperationException.

@tyrielv
tyrielv force-pushed the tyrielv/mount-timeout branch 2 times, most recently from 223b028 to 95cc5ad Compare June 19, 2026 18:35
@tyrielv
tyrielv marked this pull request as ready for review June 19, 2026 18:39
@tyrielv tyrielv changed the title Fix mount timeout when auth/network is slow Mount: fix timeout and add distinct exit codes for auth/network failures Jun 20, 2026
@tyrielv
tyrielv force-pushed the tyrielv/mount-timeout branch 3 times, most recently from a3289c3 to a0563de Compare June 22, 2026 15:19
@tyrielv tyrielv changed the title Mount: fix timeout and add distinct exit codes for auth/network failures Mount: don't block startup on auth when cache server is configured Jun 22, 2026
@tyrielv
tyrielv force-pushed the tyrielv/mount-timeout branch 4 times, most recently from d1b3d52 to 8419896 Compare June 22, 2026 15:43
Comment thread GVFS/GVFS.Mount/InProcessMount.cs
Comment thread GVFS/GVFS.Common/Git/GitAuthentication.cs Outdated
Comment thread GVFS/GVFS.Mount/InProcessMount.cs
Comment thread GVFS/GVFS.Common/Git/GitAuthentication.cs
@tyrielv
tyrielv force-pushed the tyrielv/mount-timeout branch from 8419896 to 1d5d39b Compare June 22, 2026 18:25
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
tyrielv force-pushed the tyrielv/mount-timeout branch from 1d5d39b to 43ef3e2 Compare June 22, 2026 18:41
@tyrielv
tyrielv merged commit 28135e4 into microsoft:master Jun 29, 2026
35 checks passed
@tyrielv tyrielv mentioned this pull request Jun 30, 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>
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.

2 participants