Add logic to force terminate the VM if the session lock can't be acquired for 30 seconds when the service stops (#13493)

This commit is contained in:
Blue 2025-09-24 21:46:28 +00:00 committed by GitHub
parent c8cd16a169
commit 4bba074bd2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 9 deletions

View File

@ -510,7 +510,7 @@ try
const auto session = m_session.lock();
RETURN_HR_IF(RPC_E_DISCONNECTED, !session);
return session->Shutdown(false, Force);
return session->Shutdown(false, Force ? ShutdownBehavior::Force : ShutdownBehavior::Wait);
}
CATCH_RETURN()
@ -2052,13 +2052,11 @@ HRESULT LxssUserSessionImpl::SetVersion(_In_ LPCGUID DistroGuid, _In_ ULONG Vers
return result;
}
HRESULT LxssUserSessionImpl::Shutdown(_In_ bool PreventNewInstances, bool ForceTerminate)
HRESULT LxssUserSessionImpl::Shutdown(_In_ bool PreventNewInstances, ShutdownBehavior Behavior)
{
try
{
// If the user asks for a forced termination, kill the VM
if (ForceTerminate)
{
auto forceTerminate = [this]() {
auto vmId = m_vmId.load();
if (!IsEqualGUID(vmId, GUID_NULL))
{
@ -2071,11 +2069,43 @@ HRESULT LxssUserSessionImpl::Shutdown(_In_ bool PreventNewInstances, bool ForceT
WSL_LOG("ForceTerminateVm", TraceLoggingValue(result, "Result"));
}
};
// If the user asks for a forced termination, kill the VM
if (Behavior == ShutdownBehavior::Force)
{
forceTerminate();
}
{
bool locked = false;
auto unlock = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [this, &locked]() {
if (locked)
{
m_instanceLock.unlock();
}
});
if (Behavior == ShutdownBehavior::ForceAfter30Seconds)
{
if (m_instanceLock.try_lock_for(std::chrono::seconds(30)))
{
locked = true;
}
else
{
WSL_LOG("VmShutdownLockTimedOut");
forceTerminate();
}
}
if (!locked)
{
m_instanceLock.lock();
locked = true;
}
// Stop each instance with the lock held.
std::lock_guard lock(m_instanceLock);
while (!m_runningInstances.empty())
{
_TerminateInstanceInternal(&m_runningInstances.begin()->first, false);

View File

@ -54,6 +54,13 @@ typedef struct _LXSS_VM_MODE_SETUP_CONTEXT
std::shared_ptr<LxssRunningInstance> instance;
} LXSS_VM_MODE_SETUP_CONTEXT, *PLXSS_VM_MODE_SETUP_CONTEXT;
enum class ShutdownBehavior
{
Wait,
Force,
ForceAfter30Seconds
};
/// <summary>
/// Each COM client gets a unique LxssUserSession object which contains a std::weak_ptr to a LxssUserSessionImpl for that user.
/// </summary>
@ -491,7 +498,7 @@ public:
/// <summary>
/// Terminates all running instances and the Linux utility vm.
/// </summary>
HRESULT Shutdown(_In_ bool PreventNewInstances = false, _In_ bool ForceTerminate = false);
HRESULT Shutdown(_In_ bool PreventNewInstances = false, ShutdownBehavior Behavior = ShutdownBehavior::Wait);
/// <summary>
/// Worker thread for logging telemetry about processes running inside of WSL.
@ -784,7 +791,7 @@ private:
/// <summary>
/// Lock for protecting various lists.
/// </summary>
std::recursive_mutex m_instanceLock;
std::recursive_timed_mutex m_instanceLock;
/// <summary>
/// Contains the currently running utility VM's.

View File

@ -49,7 +49,7 @@ void ClearSessionsAndBlockNewInstancesLockHeld(std::optional<std::vector<std::sh
// since that could lead to a deadlock if FindSessionByCookie is called since that would try to lock g_sessionLock
// while holding the session inner lock
session->Shutdown(true);
session->Shutdown(true, ShutdownBehavior::ForceAfter30Seconds);
}
sessions.reset();