Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/upgrade-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
- double-staging
- staging-then-clean
- mount-safety-deferral
- unmount-all-triggers-upgrade
fail-fast: false

steps:
Expand Down Expand Up @@ -274,6 +275,35 @@ jobs:
Write-Host "PASS: Mount safety deferral works correctly"
}

"unmount-all-triggers-upgrade" {
Write-Host "=== Scenario: unmount-all triggers staged upgrade ==="
# Install LKG, mount, staging upgrade, then unmount via
# 'gvfs service --unmount-all' instead of 'gvfs unmount'.
# --unmount-all skips the unregister message, so without the
# PendingUpgradeCheckRequest fix the upgrade would never apply.
Install-GVFS $lkgInstaller
Assert-ServiceRunning
$mountPid = Mount-TestRepo

Install-GVFS $newInstaller @("/STAGEIFMOUNTED=true")
Assert-MountAlive $mountPid
Assert-PendingUpgrade $true

# Unmount via --unmount-all (not per-repo unmount)
& "$installDir\gvfs.exe" service --unmount-all 2>&1 | Write-Host
if ($LASTEXITCODE -ne 0) { throw "unmount-all failed" }

# The deferred upgrade timer fires after ~5 seconds.
# Wait for it to complete.
$deadline = (Get-Date).AddSeconds(30)
while ((Test-Path "$installDir\PendingUpgrade") -and (Get-Date) -lt $deadline) {
Start-Sleep -Seconds 2
}

Assert-PendingUpgrade $false
Write-Host "PASS: unmount-all triggers staged upgrade"
}

default {
throw "Unknown scenario: ${{ matrix.scenario }}"
}
Expand Down
23 changes: 23 additions & 0 deletions GVFS/GVFS.Common/NamedPipes/NamedPipeMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,29 @@ public static Response FromMessage(Message message)
}
}

public class PendingUpgradeCheckRequest
{
public const string Header = nameof(PendingUpgradeCheckRequest);

public static PendingUpgradeCheckRequest FromMessage(Message message)
{
return GVFSJsonOptions.Deserialize<PendingUpgradeCheckRequest>(message.Body);
}

public Message ToMessage()
{
return new Message(Header, GVFSJsonOptions.Serialize(this));
}

public class Response : BaseResponse<PendingUpgradeCheckRequest>
{
public static Response FromMessage(Message message)
{
return GVFSJsonOptions.Deserialize<Response>(message.Body);
}
}
}

public class GetActiveRepoListRequest
{
public const string Header = nameof(GetActiveRepoListRequest);
Expand Down
12 changes: 12 additions & 0 deletions GVFS/GVFS.Service/Handlers/RequestHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,18 @@ protected virtual void HandleMessage(

break;

case NamedPipeMessages.PendingUpgradeCheckRequest.Header:
this.requestDescription = "pending upgrade check";

this.TryDeferredPendingUpgradeCheck(this.tracer);

NamedPipeMessages.PendingUpgradeCheckRequest.Response upgradeCheckResponse =
new NamedPipeMessages.PendingUpgradeCheckRequest.Response();
upgradeCheckResponse.State = NamedPipeMessages.CompletionState.Success;
this.TrySendResponse(tracer, upgradeCheckResponse.ToMessage().ToString(), connection);

break;

case NamedPipeMessages.GetActiveRepoListRequest.Header:
this.requestDescription = RepoListRequestDescription;
NamedPipeMessages.GetActiveRepoListRequest repoListRequest = NamedPipeMessages.GetActiveRepoListRequest.FromMessage(message);
Expand Down
47 changes: 47 additions & 0 deletions GVFS/GVFS/CommandLine/ServiceVerb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ public override void Execute()
}
}

// Notify the service so it can check for a pending staged
// upgrade. Individual unmounts skip unregister (to preserve
// automount registration), so the service's normal unmount
// trigger never fires during --unmount-all.
this.TryNotifyPendingUpgradeCheck();

if (failedRepoRoots.Count() > 0)
{
string errorString = $"The following repos failed to unmount:{Environment.NewLine}{string.Join(Environment.NewLine, failedRepoRoots.ToArray())}";
Expand Down Expand Up @@ -217,5 +223,46 @@ private bool IsRepoMounted(string repoRoot)

return false;
}

private void TryNotifyPendingUpgradeCheck()
{
NamedPipeMessages.PendingUpgradeCheckRequest request = new NamedPipeMessages.PendingUpgradeCheckRequest();

try
{
using (NamedPipeClient client = new NamedPipeClient(this.ServicePipeName))
{
if (!client.Connect())
{
this.Output.WriteLine(" WARNING: Could not notify GVFS.Service to check for pending upgrade (service not responding).");
return;
}

client.SendRequest(request.ToMessage());
NamedPipeMessages.Message response = client.ReadResponse();
if (response.Header == NamedPipeMessages.PendingUpgradeCheckRequest.Response.Header)
{
NamedPipeMessages.PendingUpgradeCheckRequest.Response typedResponse =
NamedPipeMessages.PendingUpgradeCheckRequest.Response.FromMessage(response);
if (typedResponse.State != NamedPipeMessages.CompletionState.Success)
{
this.Output.WriteLine(" WARNING: Pending upgrade check failed: " + typedResponse.ErrorMessage);
}
}
else
{
this.Output.WriteLine(" WARNING: GVFS.Service responded with unexpected message: " + response.Header);
}
}
}
catch (BrokenPipeException)
{
this.Output.WriteLine(" WARNING: Could not notify GVFS.Service to check for pending upgrade.");
}
catch (Exception ex)
{
this.Output.WriteLine(" WARNING: Error notifying GVFS.Service to check for pending upgrade: " + ex.Message);
}
}
}
}
Loading