From 04b12032dc042f6d04e753f289ee599ba9f83745 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Tue, 18 Aug 2026 17:27:22 +0800 Subject: [PATCH 01/13] Check if the cached lun is stale before using --- src/windows/service/exe/WslCoreVm.cpp | 39 ++++++++++++++++++++++++--- src/windows/service/exe/WslCoreVm.h | 1 + 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/windows/service/exe/WslCoreVm.cpp b/src/windows/service/exe/WslCoreVm.cpp index e60a2daf56..89596de963 100644 --- a/src/windows/service/exe/WslCoreVm.cpp +++ b/src/windows/service/exe/WslCoreVm.cpp @@ -73,6 +73,21 @@ RequiredExtraMmioSpaceForPmemFileInMb(_In_ PCWSTR FilePath) // Convert from bytes to megabytes. Ensure that we don't truncate a 512kb file to 0mb. return std::max(fileSizeBytes.QuadPart / static_cast(_1MB), 1i64); } + +wil::unique_hfile OpenVhdBackingFile(_In_ PCWSTR Path) +{ + wil::unique_hfile file{CreateFileW( + Path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr)}; + THROW_LAST_ERROR_IF(!file); + + return file; +} + +bool IsBackingVolumeMounted(_In_ HANDLE File) +{ + DWORD bytesReturned{}; + return DeviceIoControl(File, FSCTL_IS_VOLUME_MOUNTED, nullptr, 0, nullptr, 0, &bytesReturned, nullptr); +} } // namespace WslCoreVm::WslCoreVm(_In_ wsl::core::Config&& VmConfig) : @@ -990,6 +1005,7 @@ ULONG WslCoreVm::AttachDiskLockHeld( // Set a scope exit variable to perform cleanup if attaching the disk fails. DiskStateFlags diskFlags{}; + wil::unique_hfile backingFile; auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] { FreeLun(Lun.value()); if (WI_IsFlagSet(diskFlags, DiskStateFlags::AccessGranted)) @@ -1047,9 +1063,25 @@ ULONG WslCoreVm::AttachDiskLockHeld( // Prevent user from launching a distro vhd after manually mounting it; otherwise, return the LUN of the mounted disk. THROW_HR_IF(WSL_E_USER_VHD_ALREADY_ATTACHED, found->first.User); - return found->second.Lun; + // Check if the lun is still valid. It could be stale if the backing volume is reattached. + if (IsBackingVolumeMounted(found->second.BackingFile.get())) + { + return found->second.Lun; + } + + const auto staleLun = found->second.Lun; + wsl::windows::common::hcs::RemoveScsiDisk(m_system.get(), staleLun); + if (WI_IsFlagSet(found->second.Flags, DiskStateFlags::AccessGranted)) + { + wsl::windows::common::hcs::RevokeVmAccess(m_machineId.c_str(), found->first.Path.c_str()); + } + + m_attachedDisks.erase(found); + FreeLun(staleLun); } + backingFile = OpenVhdBackingFile(Disk); + auto grantDiskAccess = [&]() { auto runAsUser = wil::impersonate_token(UserToken); wsl::windows::common::hcs::GrantVmAccess(m_machineId.c_str(), Disk); @@ -1084,7 +1116,7 @@ ULONG WslCoreVm::AttachDiskLockHeld( result, Localization::MessageFailedToAttachDisk(Disk, wsl::windows::common::wslutil::GetSystemErrorString(result))); } - m_attachedDisks.emplace(AttachedDisk{Type, Disk, IsUserDisk}, DiskState{Lun.value(), {}, diskFlags}); + m_attachedDisks.emplace(AttachedDisk{Type, Disk, IsUserDisk}, DiskState{Lun.value(), {}, diskFlags, std::move(backingFile)}); cleanup.release(); return Lun.value(); @@ -1744,6 +1776,7 @@ std::wstring WslCoreVm::GenerateConfigJson() // inherited ACLs; otherwise StartComputeSystem will surface E_ACCESSDENIED. auto attachDisk = [&](PCWSTR path, bool grantVmAccess) { auto lun = ReserveLun(); + auto backingFile = OpenVhdBackingFile(path); hcs::Attachment disk{}; disk.Type = hcs::AttachmentType::VirtualDisk; disk.Path = path; @@ -1765,7 +1798,7 @@ std::wstring WslCoreVm::GenerateConfigJson() CATCH_LOG() } - m_attachedDisks.emplace(AttachedDisk{DiskType::VHD, path, false}, DiskState{lun, {}, diskFlags}); + m_attachedDisks.emplace(AttachedDisk{DiskType::VHD, path, false}, DiskState{lun, {}, diskFlags, std::move(backingFile)}); return lun; }; diff --git a/src/windows/service/exe/WslCoreVm.h b/src/windows/service/exe/WslCoreVm.h index eb9e2e73a4..8c4d00d1cc 100644 --- a/src/windows/service/exe/WslCoreVm.h +++ b/src/windows/service/exe/WslCoreVm.h @@ -160,6 +160,7 @@ class WslCoreVm ULONG Lun; std::map Mounts; DiskStateFlags Flags; + wil::unique_hfile BackingFile; }; struct VirtioFsShare From d36ba132b7c4f92981626b63b25fb79c977573dc Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Tue, 18 Aug 2026 18:22:07 +0800 Subject: [PATCH 02/13] add unit test --- test/windows/Common.cpp | 75 +++++++++++++++++++++++++++++++++++++ test/windows/Common.h | 8 ++++ test/windows/DrvFsTests.cpp | 65 ++++---------------------------- test/windows/UnitTests.cpp | 59 +++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 57 deletions(-) diff --git a/test/windows/Common.cpp b/test/windows/Common.cpp index e0b7577f98..7388c881c2 100644 --- a/test/windows/Common.cpp +++ b/test/windows/Common.cpp @@ -3149,3 +3149,78 @@ void ValidateCOMErrorMessageContains(const std::wstring& ExpectedSubstring) VERIFY_FAIL(); } } + +static void RunDiskpartScript(std::wstring_view Script) +{ + const auto scriptFileName = wsl::windows::common::filesystem::GetTempFilename(); + std::wofstream scriptFile(scriptFileName); + THROW_LAST_ERROR_IF(!scriptFile); + + auto cleanup = wil::scope_exit([&] { DeleteFileW(scriptFileName.c_str()); }); + scriptFile << Script; + scriptFile.close(); + + std::wstring commandLine = L"diskpart.exe /s "; + commandLine += scriptFileName.c_str(); + THROW_HR_IF(E_FAIL, wsl::windows::common::helpers::RunProcess(commandLine) != 0); +} + +void AttachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) +{ + RunDiskpartScript( + std::format( + L"select vdisk file=\"{}\"\n" + L"attach vdisk\n" + L"select partition 1\n" + L"assign mount=\"{}\"\n", + VhdPath.wstring(), + MountPoint.wstring())); +} + +void CreateTestVolume(_In_ PCWSTR FileSystem, _In_ ULONG MaxSizeInMb, const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) +{ + THROW_LAST_ERROR_IF(!CreateDirectoryW(MountPoint.c_str(), nullptr)); + + RunDiskpartScript( + std::format( + L"create vdisk file=\"{}\" maximum={} type=expandable\n" + L"select vdisk file=\"{}\"\n" + L"attach vdisk\n" + L"create partition primary\n" + L"select partition 1\n" + L"online volume\n" + L"format fs={} quick\n" + L"assign mount=\"{}\"\n", + VhdPath.wstring(), + MaxSizeInMb, + VhdPath.wstring(), + FileSystem, + MountPoint.wstring())); +} + +void DeleteTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) +{ + RunDiskpartScript( + std::format( + L"select vdisk file=\"{}\"\n" + L"attach vdisk noerr\n" + L"select partition 1\n" + L"remove all noerr\n" + L"detach vdisk noerr\n", + VhdPath.wstring())); + + RemoveDirectoryW(MountPoint.c_str()); + DeleteFileW(VhdPath.c_str()); +} + +void DetachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) +{ + RunDiskpartScript( + std::format( + L"select vdisk file=\"{}\"\n" + L"select partition 1\n" + L"remove mount=\"{}\"\n" + L"detach vdisk\n", + VhdPath.wstring(), + MountPoint.wstring())); +} diff --git a/test/windows/Common.h b/test/windows/Common.h index 599ac069b2..a3bb44075f 100644 --- a/test/windows/Common.h +++ b/test/windows/Common.h @@ -723,3 +723,11 @@ void WriteSocket(SOCKET Socket, const void* data, size_t size); void ValidateCOMErrorMessage(const std::optional& Expected, const std::source_location& Source = std::source_location::current()); void ValidateCOMErrorMessageContains(const std::wstring& ExpectedSubstring); + +void AttachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath); + +void CreateTestVolume(_In_ PCWSTR FileSystem, _In_ ULONG MaxSizeInMb, const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath); + +void DeleteTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath); + +void DetachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath); diff --git a/test/windows/DrvFsTests.cpp b/test/windows/DrvFsTests.cpp index 5e8b69c64e..ec8d7383b0 100644 --- a/test/windows/DrvFsTests.cpp +++ b/test/windows/DrvFsTests.cpp @@ -224,11 +224,11 @@ class DrvFsTests { SKIP_TEST_ARM64(); - constexpr auto MountPoint = "C:\\lxss_fat"; - constexpr auto VhdPath = "C:\\lxss_fat.vhdx"; - auto Cleanup = wil::scope_exit([MountPoint, VhdPath] { DeleteVolume(MountPoint, VhdPath); }); + constexpr auto MountPoint = L"C:\\lxss_fat"; + constexpr auto VhdPath = L"C:\\lxss_fat.vhdx"; + auto Cleanup = wil::scope_exit([MountPoint, VhdPath] { DeleteTestVolume(MountPoint, VhdPath); }); - VERIFY_NO_THROW(CreateVolume("fat32", 100, MountPoint, VhdPath)); + VERIFY_NO_THROW(CreateTestVolume(L"fat32", 100, MountPoint, VhdPath)); VERIFY_NO_THROW( LxsstuRunTest((L"bash -c '" + SkipUnstableTestEnvVar + L" /data/test/wsl_unit_tests drvfs -m 3'").c_str(), L"drvfs3")); } @@ -338,11 +338,11 @@ class DrvFsTests SKIP_TEST_ARM64(); WSL_TEST_VERSION_REQUIRED(wsl::windows::common::helpers::WindowsBuildNumbers::Germanium); - constexpr auto MountPoint = "C:\\lxss_refs"; - constexpr auto VhdPath = "C:\\lxss_refs.vhdx"; - auto Cleanup = wil::scope_exit([MountPoint, VhdPath] { DeleteVolume(MountPoint, VhdPath); }); + constexpr auto MountPoint = L"C:\\lxss_refs"; + constexpr auto VhdPath = L"C:\\lxss_refs.vhdx"; + auto Cleanup = wil::scope_exit([MountPoint, VhdPath] { DeleteTestVolume(MountPoint, VhdPath); }); - VERIFY_NO_THROW(CreateVolume("refs", 50000, MountPoint, VhdPath)); + VERIFY_NO_THROW(CreateTestVolume(L"refs", 50000, MountPoint, VhdPath)); VERIFY_NO_THROW( LxsstuRunTest((L"bash -c '" + SkipUnstableTestEnvVar + L" /data/test/wsl_unit_tests drvfs -m 6'").c_str(), L"drvfs6")); } @@ -1012,55 +1012,6 @@ class DrvFsTests return File; } - static VOID CreateVolume(LPCSTR FileSystem, ULONG MaxSizeInMb, LPCSTR MountPoint, LPCSTR VhdPath) - { - THROW_LAST_ERROR_IF(!CreateDirectoryA(MountPoint, NULL)); - - const auto CreateScript = std::vformat( - "create vdisk file={} maximum={} type=expandable\n" - "select vdisk file={}\n" - "attach vdisk\n" - "create partition primary\n" - "select partition 1\n" - "online volume\n" - "format fs={} quick\n" - "assign mount={}\n", - std::make_format_args(VhdPath, MaxSizeInMb, VhdPath, FileSystem, MountPoint)); - - RunDiskpartScript(CreateScript.c_str()); - } - - static VOID RunDiskpartScript(LPCSTR Script) - { - const std::wstring ScriptFileName = wsl::windows::common::filesystem::GetTempFilename(); - - std::ofstream ScriptFile(ScriptFileName); - THROW_LAST_ERROR_IF(!ScriptFile); - - auto Cleanup = wil::scope_exit([&] { DeleteFileW(ScriptFileName.c_str()); }); - - ScriptFile << Script; - ScriptFile.close(); - - std::wstring CommandLine = L"diskpart.exe /s " + ScriptFileName; - THROW_HR_IF(E_FAIL, ((wsl::windows::common::helpers::RunProcess(CommandLine)) != 0)); - } - - static VOID DeleteVolume(LPCSTR MountPoint, LPCSTR VhdPath) - { - const auto CleanupScript = std::vformat( - "select vdisk file={}\n" - "select partition 1\n" - "remove all\n" - "detach vdisk\n", - std::make_format_args(VhdPath)); - - RunDiskpartScript(CleanupScript.c_str()); - - RemoveDirectoryA(MountPoint); - DeleteFileA(VhdPath); - } - static void ValidateDrvfsMounts(DWORD CreateProcessFlags, DrvFsMode Mode) { auto validate = [CreateProcessFlags](const std::wstring& expectedType, HANDLE token) { diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 035323b75a..a8490a1cd4 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -7910,5 +7910,64 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", VERIFY_ARE_EQUAL(baselineCodePage, GetConsoleOutputCP(), L"Destruction restores the code page saved on the first call"); } + WSL2_TEST_METHOD(CachedVhdIsReattachedAfterBackingVolumeRemount) + { + const auto testName = std::format(L"cached-vhd-remount-{}-{}", GetCurrentProcessId(), GetTickCount64()); + const auto testRoot = std::filesystem::temp_directory_path() / testName; + const auto outerVhd = testRoot / L"outer.vhdx"; + const auto mountPath = testRoot / L"mount"; + const auto installPath = mountPath / L"distro"; + bool imported = false; + bool volumeAttached = false; + + auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() { + if (imported) + { + if (!volumeAttached) + { + try + { + AttachTestVolume(mountPath, outerVhd); + volumeAttached = true; + } + CATCH_LOG() + } + + LxsstuLaunchWsl(std::format(L"--unregister {}", testName)); + } + + WslShutdown(); + try + { + DeleteTestVolume(mountPath, outerVhd); + } + CATCH_LOG() + + std::error_code error; + std::filesystem::remove_all(testRoot, error); + }); + + std::filesystem::create_directories(testRoot); + CreateTestVolume(L"ntfs", 4096, mountPath, outerVhd); + volumeAttached = true; + + WslKeepAlive keepAlive; + const auto importResult = + LxsstuLaunchWsl(std::format(L"--import {} \"{}\" \"{}\" --version 2", testName, installPath.c_str(), g_testDistroPath)); + imported = (importResult == 0); + VERIFY_ARE_EQUAL(importResult, 0L); + + VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} /bin/true", testName)), 0L); + VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"--terminate {}", testName)), 0L); + + DetachTestVolume(mountPath, outerVhd); + volumeAttached = false; + VERIFY_IS_FALSE(std::filesystem::exists(installPath / LXSS_VM_MODE_VHD_NAME)); + + AttachTestVolume(mountPath, outerVhd); + volumeAttached = true; + VERIFY_IS_TRUE(std::filesystem::exists(installPath / LXSS_VM_MODE_VHD_NAME)); + VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} /bin/true", testName)), 0L); + } }; // namespace UnitTests } // namespace UnitTests From 7e57c1f729a7000d6c501dd9445da9a4069a89a7 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Wed, 19 Aug 2026 12:21:28 +0800 Subject: [PATCH 03/13] format code --- test/windows/Common.cpp | 74 +++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/test/windows/Common.cpp b/test/windows/Common.cpp index 7388c881c2..a87369eab0 100644 --- a/test/windows/Common.cpp +++ b/test/windows/Common.cpp @@ -3167,47 +3167,44 @@ static void RunDiskpartScript(std::wstring_view Script) void AttachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) { - RunDiskpartScript( - std::format( - L"select vdisk file=\"{}\"\n" - L"attach vdisk\n" - L"select partition 1\n" - L"assign mount=\"{}\"\n", - VhdPath.wstring(), - MountPoint.wstring())); + RunDiskpartScript(std::format( + L"select vdisk file=\"{}\"\n" + L"attach vdisk\n" + L"select partition 1\n" + L"assign mount=\"{}\"\n", + VhdPath.wstring(), + MountPoint.wstring())); } void CreateTestVolume(_In_ PCWSTR FileSystem, _In_ ULONG MaxSizeInMb, const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) { THROW_LAST_ERROR_IF(!CreateDirectoryW(MountPoint.c_str(), nullptr)); - RunDiskpartScript( - std::format( - L"create vdisk file=\"{}\" maximum={} type=expandable\n" - L"select vdisk file=\"{}\"\n" - L"attach vdisk\n" - L"create partition primary\n" - L"select partition 1\n" - L"online volume\n" - L"format fs={} quick\n" - L"assign mount=\"{}\"\n", - VhdPath.wstring(), - MaxSizeInMb, - VhdPath.wstring(), - FileSystem, - MountPoint.wstring())); + RunDiskpartScript(std::format( + L"create vdisk file=\"{}\" maximum={} type=expandable\n" + L"select vdisk file=\"{}\"\n" + L"attach vdisk\n" + L"create partition primary\n" + L"select partition 1\n" + L"online volume\n" + L"format fs={} quick\n" + L"assign mount=\"{}\"\n", + VhdPath.wstring(), + MaxSizeInMb, + VhdPath.wstring(), + FileSystem, + MountPoint.wstring())); } void DeleteTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) { - RunDiskpartScript( - std::format( - L"select vdisk file=\"{}\"\n" - L"attach vdisk noerr\n" - L"select partition 1\n" - L"remove all noerr\n" - L"detach vdisk noerr\n", - VhdPath.wstring())); + RunDiskpartScript(std::format( + L"select vdisk file=\"{}\"\n" + L"attach vdisk noerr\n" + L"select partition 1\n" + L"remove all noerr\n" + L"detach vdisk noerr\n", + VhdPath.wstring())); RemoveDirectoryW(MountPoint.c_str()); DeleteFileW(VhdPath.c_str()); @@ -3215,12 +3212,11 @@ void DeleteTestVolume(const std::filesystem::path& MountPoint, const std::filesy void DetachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) { - RunDiskpartScript( - std::format( - L"select vdisk file=\"{}\"\n" - L"select partition 1\n" - L"remove mount=\"{}\"\n" - L"detach vdisk\n", - VhdPath.wstring(), - MountPoint.wstring())); + RunDiskpartScript(std::format( + L"select vdisk file=\"{}\"\n" + L"select partition 1\n" + L"remove mount=\"{}\"\n" + L"detach vdisk\n", + VhdPath.wstring(), + MountPoint.wstring())); } From 1dde87dcaea40400acaed5204b9453794483d7bf Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Wed, 19 Aug 2026 12:36:34 +0800 Subject: [PATCH 04/13] resolve comments --- test/windows/Common.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/windows/Common.cpp b/test/windows/Common.cpp index a87369eab0..fa5f300888 100644 --- a/test/windows/Common.cpp +++ b/test/windows/Common.cpp @@ -3154,14 +3154,13 @@ static void RunDiskpartScript(std::wstring_view Script) { const auto scriptFileName = wsl::windows::common::filesystem::GetTempFilename(); std::wofstream scriptFile(scriptFileName); - THROW_LAST_ERROR_IF(!scriptFile); + THROW_HR_IF(E_FAIL, !scriptFile.is_open()); auto cleanup = wil::scope_exit([&] { DeleteFileW(scriptFileName.c_str()); }); scriptFile << Script; scriptFile.close(); - std::wstring commandLine = L"diskpart.exe /s "; - commandLine += scriptFileName.c_str(); + auto commandLine = std::format(L"diskpart.exe /s \"{}\"", scriptFileName); THROW_HR_IF(E_FAIL, wsl::windows::common::helpers::RunProcess(commandLine) != 0); } From 35595db1802142affd30d4cc2286e4af332707f7 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Wed, 19 Aug 2026 15:43:36 +0800 Subject: [PATCH 05/13] Fix --terminate introduced flakiness --- test/windows/UnitTests.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index a8490a1cd4..b2f873faae 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -6686,13 +6686,13 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", } } - static LxssDistributionState GetDistroState() + static LxssDistributionState GetDistroState(LPCWSTR DistroName = LXSS_DISTRO_NAME_TEST_L) { wsl::windows::common::SvcComm service; for (const auto& e : service.EnumerateDistributions()) { - if (wsl::shared::string::IsEqual(e.DistroName, LXSS_DISTRO_NAME_TEST_L)) + if (wsl::shared::string::IsEqual(e.DistroName, DistroName)) { return e.State; } @@ -7959,6 +7959,12 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} /bin/true", testName)), 0L); VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"--terminate {}", testName)), 0L); + VERIFY_NO_THROW(wsl::shared::retry::RetryWithTimeout( + [&]() { + THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_RETRY), GetDistroState(testName.c_str()) == LxssDistributionStateRunning); + }, + std::chrono::seconds(1), + std::chrono::seconds(30))); DetachTestVolume(mountPath, outerVhd); volumeAttached = false; From 2fd2255d277e95766f153d637721a545a1647c12 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Wed, 19 Aug 2026 15:50:24 +0800 Subject: [PATCH 06/13] update error message test error context --- test/windows/UnitTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index b2f873faae..5f74ff6569 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -1503,7 +1503,7 @@ class UnitTests L"-d DummyBrokenDistro", L"Failed to attach disk 'C:\\DoesNotExit\\ext4.vhdx' to WSL2: The system cannot find the path " L"specified. ", - L"Wsl/Service/CreateInstance/MountDisk/HCS/ERROR_PATH_NOT_FOUND"); + L"Wsl/Service/CreateInstance/MountDisk/ERROR_PATH_NOT_FOUND"); // Purposefully set an incorrect value type to validate registry error handling. wsl::windows::common::registry::WriteString(distroKey.get(), nullptr, L"Version", L"Broken"); From b561755ca9ec2c411f536126a9210c93cdd8c06a Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Wed, 19 Aug 2026 16:07:37 +0800 Subject: [PATCH 07/13] retry the detach instead of pulling distro state --- test/windows/Common.cpp | 2 +- test/windows/UnitTests.cpp | 12 +++--------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/test/windows/Common.cpp b/test/windows/Common.cpp index fa5f300888..be2108ddd6 100644 --- a/test/windows/Common.cpp +++ b/test/windows/Common.cpp @@ -3214,7 +3214,7 @@ void DetachTestVolume(const std::filesystem::path& MountPoint, const std::filesy RunDiskpartScript(std::format( L"select vdisk file=\"{}\"\n" L"select partition 1\n" - L"remove mount=\"{}\"\n" + L"remove mount=\"{}\" noerr\n" L"detach vdisk\n", VhdPath.wstring(), MountPoint.wstring())); diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 5f74ff6569..78a56fa529 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -6686,13 +6686,13 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", } } - static LxssDistributionState GetDistroState(LPCWSTR DistroName = LXSS_DISTRO_NAME_TEST_L) + static LxssDistributionState GetDistroState() { wsl::windows::common::SvcComm service; for (const auto& e : service.EnumerateDistributions()) { - if (wsl::shared::string::IsEqual(e.DistroName, DistroName)) + if (wsl::shared::string::IsEqual(e.DistroName, LXSS_DISTRO_NAME_TEST_L)) { return e.State; } @@ -7960,13 +7960,7 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} /bin/true", testName)), 0L); VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"--terminate {}", testName)), 0L); VERIFY_NO_THROW(wsl::shared::retry::RetryWithTimeout( - [&]() { - THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_RETRY), GetDistroState(testName.c_str()) == LxssDistributionStateRunning); - }, - std::chrono::seconds(1), - std::chrono::seconds(30))); - - DetachTestVolume(mountPath, outerVhd); + [&]() { DetachTestVolume(mountPath, outerVhd); }, std::chrono::seconds(1), std::chrono::seconds(30))); volumeAttached = false; VERIFY_IS_FALSE(std::filesystem::exists(installPath / LXSS_VM_MODE_VHD_NAME)); From ad6d303b96196c87a7479fb4b382deb1e820d6e7 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Thu, 20 Aug 2026 10:52:24 +0800 Subject: [PATCH 08/13] [wip] investigate pipeline test failure --- .pipelines/build-job.yml | 6 +++++- .pipelines/build-stage.yml | 6 ++++++ .pipelines/wsl-build-pr-onebranch.yml | 2 ++ .pipelines/wsl-build-pr.yml | 2 ++ cloudtest/CMakeLists.txt | 6 ++++++ cloudtest/TestGroup.xml.in | 2 +- test/windows/Common.cpp | 14 +++++++++++++- test/windows/UnitTests.cpp | 3 +-- 8 files changed, 36 insertions(+), 5 deletions(-) diff --git a/.pipelines/build-job.yml b/.pipelines/build-job.yml index 41060a8c6e..c19ddd9149 100644 --- a/.pipelines/build-job.yml +++ b/.pipelines/build-job.yml @@ -34,6 +34,10 @@ parameters: - name: artifactSuffix type: string + - name: cloudTestName + type: string + default: '' + - name: esrp type: object @@ -124,7 +128,7 @@ jobs: displayName: "CMake ${{ parameters.platform }}" inputs: workingDirectory: "." - cmakeArgs: . --fresh -A ${{ parameters.platform }} -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION=10.0.26100.0 -DPACKAGE_VERSION=$(version.WSL_PACKAGE_VERSION) -DWSL_NUGET_PACKAGE_VERSION=$(version.WSL_NUGET_PACKAGE_VERSION) -DSKIP_PACKAGE_SIGNING=${{ parameters.isRelease }} -DOFFICIAL_BUILD=${{ parameters.isRelease }} -DINCLUDE_PACKAGE_STAGE=${{ or(parameters.isRelease, parameters.isNightly) }} -DPIPELINE_BUILD_ID=$(Build.BuildId) -DVSO_ORG=${{ parameters.vsoOrg }} -DVSO_PROJECT=${{ parameters.vsoProject }} -DWSL_BUILD_WSL_SETTINGS=true -DWSL_INCLUDE_SDK_CSHARP=true -DWSL_UNITY_BATCH_SIZE=4 $(packageInputDirArg)\${{ parameters.platform }} + cmakeArgs: . --fresh -A ${{ parameters.platform }} -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION=10.0.26100.0 -DPACKAGE_VERSION=$(version.WSL_PACKAGE_VERSION) -DWSL_NUGET_PACKAGE_VERSION=$(version.WSL_NUGET_PACKAGE_VERSION) -DSKIP_PACKAGE_SIGNING=${{ parameters.isRelease }} -DOFFICIAL_BUILD=${{ parameters.isRelease }} -DINCLUDE_PACKAGE_STAGE=${{ or(parameters.isRelease, parameters.isNightly) }} -DPIPELINE_BUILD_ID=$(Build.BuildId) -DVSO_ORG=${{ parameters.vsoOrg }} -DVSO_PROJECT=${{ parameters.vsoProject }} -DCLOUDTEST_TEST_NAME=${{ parameters.cloudTestName }} -DWSL_BUILD_WSL_SETTINGS=true -DWSL_INCLUDE_SDK_CSHARP=true -DWSL_UNITY_BATCH_SIZE=4 $(packageInputDirArg)\${{ parameters.platform }} # Workaround for WSL Settings NuGet restore authentication issue - script: _deps\nuget.exe restore -NonInteractive diff --git a/.pipelines/build-stage.yml b/.pipelines/build-stage.yml index a10c08c110..ea6b18d1b5 100644 --- a/.pipelines/build-stage.yml +++ b/.pipelines/build-stage.yml @@ -19,6 +19,10 @@ parameters: type: string default: '' + - name: cloudTestName + type: string + default: '' + - name: nugetPackages type: object default: @@ -78,6 +82,7 @@ stages: isNightly: ${{ parameters.isNightly }} packageVersion: ${{ parameters.packageVersion }} traceLoggingConfig: ${{ parameters.traceLoggingConfig }} + cloudTestName: ${{ parameters.cloudTestName }} targets: ${{ parameters.targets }} pool: ${{ parameters.pool }} vsoOrg: ${{ parameters.vsoOrg }} @@ -138,6 +143,7 @@ stages: isNightly: ${{ parameters.isNightly }} packageVersion: ${{ parameters.packageVersion }} traceLoggingConfig: ${{ parameters.traceLoggingConfig }} + cloudTestName: ${{ parameters.cloudTestName }} targets: ${{ parameters.targets }} pool: ${{ parameters.pool }} vsoOrg: ${{ parameters.vsoOrg }} diff --git a/.pipelines/wsl-build-pr-onebranch.yml b/.pipelines/wsl-build-pr-onebranch.yml index 92a8a4cbd8..c3887e611f 100644 --- a/.pipelines/wsl-build-pr-onebranch.yml +++ b/.pipelines/wsl-build-pr-onebranch.yml @@ -46,8 +46,10 @@ extends: - template: build-stage.yml@self parameters: isRelease: false + cloudTestName: 'UnitTests::UnitTests::CachedVhdIsReattachedAfterBackingVolumeRemount' - template: test-stage.yml@self parameters: includePackageStage: false rs_prerelease_only: true + versions: [wsl2] diff --git a/.pipelines/wsl-build-pr.yml b/.pipelines/wsl-build-pr.yml index 4a7e2d9128..56303a1759 100644 --- a/.pipelines/wsl-build-pr.yml +++ b/.pipelines/wsl-build-pr.yml @@ -8,6 +8,7 @@ stages: - template: build-stage.yml@self parameters: isRelease: false + cloudTestName: 'UnitTests::UnitTests::CachedVhdIsReattachedAfterBackingVolumeRemount' pool: 'wsl-build' vsoOrg: shine-oss vsoProject: wsl @@ -16,4 +17,5 @@ stages: parameters: includePackageStage: false rs_prerelease_only: true + versions: [wsl2] pool: server diff --git a/cloudtest/CMakeLists.txt b/cloudtest/CMakeLists.txt index 643a069d1c..bf2eadfde1 100644 --- a/cloudtest/CMakeLists.txt +++ b/cloudtest/CMakeLists.txt @@ -47,6 +47,12 @@ function(add_test_group image version suffix filter) set(DIR ${OUT}/${image}-${suffix}) file(MAKE_DIRECTORY ${DIR}) + if(CLOUDTEST_TEST_NAME AND "${suffix}" STREQUAL "wsl2") + set(test_args "/name:${CLOUDTEST_TEST_NAME}") + else() + set(test_args "/select:"${filter}"") + endif() + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TestMap.xml.in ${DIR}/TestMap.xml) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TestGroup.xml.in ${DIR}/TestGroup.xml) endfunction() diff --git a/cloudtest/TestGroup.xml.in b/cloudtest/TestGroup.xml.in index 81c4a6c5f7..6b7444bcbd 100644 --- a/cloudtest/TestGroup.xml.in +++ b/cloudtest/TestGroup.xml.in @@ -22,6 +22,6 @@ - + diff --git a/test/windows/Common.cpp b/test/windows/Common.cpp index be2108ddd6..949e309918 100644 --- a/test/windows/Common.cpp +++ b/test/windows/Common.cpp @@ -3161,7 +3161,19 @@ static void RunDiskpartScript(std::wstring_view Script) scriptFile.close(); auto commandLine = std::format(L"diskpart.exe /s \"{}\"", scriptFileName); - THROW_HR_IF(E_FAIL, wsl::windows::common::helpers::RunProcess(commandLine) != 0); + wsl::windows::common::SubProcess process(nullptr, commandLine.c_str()); + const auto output = process.RunAndCaptureOutput(); + if (output.ExitCode != 0) + { + LogError( + "diskpart failed with exit code %lu. Script:\n%.*ls\nStdout:\n%ls\nStderr:\n%ls", + output.ExitCode, + static_cast(Script.size()), + Script.data(), + output.Stdout.c_str(), + output.Stderr.c_str()); + THROW_HR(E_FAIL); + } } void AttachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 78a56fa529..a2a7d17572 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -7959,8 +7959,7 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} /bin/true", testName)), 0L); VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"--terminate {}", testName)), 0L); - VERIFY_NO_THROW(wsl::shared::retry::RetryWithTimeout( - [&]() { DetachTestVolume(mountPath, outerVhd); }, std::chrono::seconds(1), std::chrono::seconds(30))); + DetachTestVolume(mountPath, outerVhd); volumeAttached = false; VERIFY_IS_FALSE(std::filesystem::exists(installPath / LXSS_VM_MODE_VHD_NAME)); From 418accd5eee82cce70b553f1c7b20c0aee619886 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Thu, 20 Aug 2026 12:19:32 +0800 Subject: [PATCH 09/13] [wip] test test failure --- test/windows/Common.cpp | 58 +-------------------------------- test/windows/Common.h | 8 +---- test/windows/DrvFsTests.cpp | 65 ++++++++++++++++++++++++++++++++----- test/windows/UnitTests.cpp | 46 +++++++++++++++++++++++--- 4 files changed, 100 insertions(+), 77 deletions(-) diff --git a/test/windows/Common.cpp b/test/windows/Common.cpp index 949e309918..54a18f1364 100644 --- a/test/windows/Common.cpp +++ b/test/windows/Common.cpp @@ -3150,7 +3150,7 @@ void ValidateCOMErrorMessageContains(const std::wstring& ExpectedSubstring) } } -static void RunDiskpartScript(std::wstring_view Script) +void RunDiskpartScript(std::wstring_view Script) { const auto scriptFileName = wsl::windows::common::filesystem::GetTempFilename(); std::wofstream scriptFile(scriptFileName); @@ -3175,59 +3175,3 @@ static void RunDiskpartScript(std::wstring_view Script) THROW_HR(E_FAIL); } } - -void AttachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) -{ - RunDiskpartScript(std::format( - L"select vdisk file=\"{}\"\n" - L"attach vdisk\n" - L"select partition 1\n" - L"assign mount=\"{}\"\n", - VhdPath.wstring(), - MountPoint.wstring())); -} - -void CreateTestVolume(_In_ PCWSTR FileSystem, _In_ ULONG MaxSizeInMb, const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) -{ - THROW_LAST_ERROR_IF(!CreateDirectoryW(MountPoint.c_str(), nullptr)); - - RunDiskpartScript(std::format( - L"create vdisk file=\"{}\" maximum={} type=expandable\n" - L"select vdisk file=\"{}\"\n" - L"attach vdisk\n" - L"create partition primary\n" - L"select partition 1\n" - L"online volume\n" - L"format fs={} quick\n" - L"assign mount=\"{}\"\n", - VhdPath.wstring(), - MaxSizeInMb, - VhdPath.wstring(), - FileSystem, - MountPoint.wstring())); -} - -void DeleteTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) -{ - RunDiskpartScript(std::format( - L"select vdisk file=\"{}\"\n" - L"attach vdisk noerr\n" - L"select partition 1\n" - L"remove all noerr\n" - L"detach vdisk noerr\n", - VhdPath.wstring())); - - RemoveDirectoryW(MountPoint.c_str()); - DeleteFileW(VhdPath.c_str()); -} - -void DetachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath) -{ - RunDiskpartScript(std::format( - L"select vdisk file=\"{}\"\n" - L"select partition 1\n" - L"remove mount=\"{}\" noerr\n" - L"detach vdisk\n", - VhdPath.wstring(), - MountPoint.wstring())); -} diff --git a/test/windows/Common.h b/test/windows/Common.h index a3bb44075f..9f172a54b0 100644 --- a/test/windows/Common.h +++ b/test/windows/Common.h @@ -724,10 +724,4 @@ void ValidateCOMErrorMessage(const std::optional& Expected, const void ValidateCOMErrorMessageContains(const std::wstring& ExpectedSubstring); -void AttachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath); - -void CreateTestVolume(_In_ PCWSTR FileSystem, _In_ ULONG MaxSizeInMb, const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath); - -void DeleteTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath); - -void DetachTestVolume(const std::filesystem::path& MountPoint, const std::filesystem::path& VhdPath); +void RunDiskpartScript(std::wstring_view Script); diff --git a/test/windows/DrvFsTests.cpp b/test/windows/DrvFsTests.cpp index ec8d7383b0..5e8b69c64e 100644 --- a/test/windows/DrvFsTests.cpp +++ b/test/windows/DrvFsTests.cpp @@ -224,11 +224,11 @@ class DrvFsTests { SKIP_TEST_ARM64(); - constexpr auto MountPoint = L"C:\\lxss_fat"; - constexpr auto VhdPath = L"C:\\lxss_fat.vhdx"; - auto Cleanup = wil::scope_exit([MountPoint, VhdPath] { DeleteTestVolume(MountPoint, VhdPath); }); + constexpr auto MountPoint = "C:\\lxss_fat"; + constexpr auto VhdPath = "C:\\lxss_fat.vhdx"; + auto Cleanup = wil::scope_exit([MountPoint, VhdPath] { DeleteVolume(MountPoint, VhdPath); }); - VERIFY_NO_THROW(CreateTestVolume(L"fat32", 100, MountPoint, VhdPath)); + VERIFY_NO_THROW(CreateVolume("fat32", 100, MountPoint, VhdPath)); VERIFY_NO_THROW( LxsstuRunTest((L"bash -c '" + SkipUnstableTestEnvVar + L" /data/test/wsl_unit_tests drvfs -m 3'").c_str(), L"drvfs3")); } @@ -338,11 +338,11 @@ class DrvFsTests SKIP_TEST_ARM64(); WSL_TEST_VERSION_REQUIRED(wsl::windows::common::helpers::WindowsBuildNumbers::Germanium); - constexpr auto MountPoint = L"C:\\lxss_refs"; - constexpr auto VhdPath = L"C:\\lxss_refs.vhdx"; - auto Cleanup = wil::scope_exit([MountPoint, VhdPath] { DeleteTestVolume(MountPoint, VhdPath); }); + constexpr auto MountPoint = "C:\\lxss_refs"; + constexpr auto VhdPath = "C:\\lxss_refs.vhdx"; + auto Cleanup = wil::scope_exit([MountPoint, VhdPath] { DeleteVolume(MountPoint, VhdPath); }); - VERIFY_NO_THROW(CreateTestVolume(L"refs", 50000, MountPoint, VhdPath)); + VERIFY_NO_THROW(CreateVolume("refs", 50000, MountPoint, VhdPath)); VERIFY_NO_THROW( LxsstuRunTest((L"bash -c '" + SkipUnstableTestEnvVar + L" /data/test/wsl_unit_tests drvfs -m 6'").c_str(), L"drvfs6")); } @@ -1012,6 +1012,55 @@ class DrvFsTests return File; } + static VOID CreateVolume(LPCSTR FileSystem, ULONG MaxSizeInMb, LPCSTR MountPoint, LPCSTR VhdPath) + { + THROW_LAST_ERROR_IF(!CreateDirectoryA(MountPoint, NULL)); + + const auto CreateScript = std::vformat( + "create vdisk file={} maximum={} type=expandable\n" + "select vdisk file={}\n" + "attach vdisk\n" + "create partition primary\n" + "select partition 1\n" + "online volume\n" + "format fs={} quick\n" + "assign mount={}\n", + std::make_format_args(VhdPath, MaxSizeInMb, VhdPath, FileSystem, MountPoint)); + + RunDiskpartScript(CreateScript.c_str()); + } + + static VOID RunDiskpartScript(LPCSTR Script) + { + const std::wstring ScriptFileName = wsl::windows::common::filesystem::GetTempFilename(); + + std::ofstream ScriptFile(ScriptFileName); + THROW_LAST_ERROR_IF(!ScriptFile); + + auto Cleanup = wil::scope_exit([&] { DeleteFileW(ScriptFileName.c_str()); }); + + ScriptFile << Script; + ScriptFile.close(); + + std::wstring CommandLine = L"diskpart.exe /s " + ScriptFileName; + THROW_HR_IF(E_FAIL, ((wsl::windows::common::helpers::RunProcess(CommandLine)) != 0)); + } + + static VOID DeleteVolume(LPCSTR MountPoint, LPCSTR VhdPath) + { + const auto CleanupScript = std::vformat( + "select vdisk file={}\n" + "select partition 1\n" + "remove all\n" + "detach vdisk\n", + std::make_format_args(VhdPath)); + + RunDiskpartScript(CleanupScript.c_str()); + + RemoveDirectoryA(MountPoint); + DeleteFileA(VhdPath); + } + static void ValidateDrvfsMounts(DWORD CreateProcessFlags, DrvFsMode Mode) { auto validate = [CreateProcessFlags](const std::wstring& expectedType, HANDLE token) { diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index a2a7d17572..2753efc513 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -7920,6 +7920,22 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", bool imported = false; bool volumeAttached = false; + auto attachVolume = [&]() { + RunDiskpartScript( + std::format( + L"select vdisk file=\"{}\"\n" + L"attach vdisk\n", + outerVhd.wstring())); + }; + + auto detachVolume = [&]() { + RunDiskpartScript( + std::format( + L"select vdisk file=\"{}\"\n" + L"detach vdisk\n", + outerVhd.wstring())); + }; + auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() { if (imported) { @@ -7927,7 +7943,7 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", { try { - AttachTestVolume(mountPath, outerVhd); + attachVolume(); volumeAttached = true; } CATCH_LOG() @@ -7939,7 +7955,14 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", WslShutdown(); try { - DeleteTestVolume(mountPath, outerVhd); + RunDiskpartScript( + std::format( + L"select vdisk file=\"{}\"\n" + L"attach vdisk noerr\n" + L"select partition 1\n" + L"remove all noerr\n" + L"detach vdisk noerr\n", + outerVhd.wstring())); } CATCH_LOG() @@ -7948,7 +7971,20 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", }); std::filesystem::create_directories(testRoot); - CreateTestVolume(L"ntfs", 4096, mountPath, outerVhd); + std::filesystem::create_directories(mountPath); + RunDiskpartScript( + std::format( + L"create vdisk file=\"{}\" maximum=4096 type=expandable\n" + L"select vdisk file=\"{}\"\n" + L"attach vdisk\n" + L"create partition primary\n" + L"select partition 1\n" + L"online volume\n" + L"format fs=ntfs quick\n" + L"assign mount=\"{}\"\n", + outerVhd.wstring(), + outerVhd.wstring(), + mountPath.wstring())); volumeAttached = true; WslKeepAlive keepAlive; @@ -7959,11 +7995,11 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} /bin/true", testName)), 0L); VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"--terminate {}", testName)), 0L); - DetachTestVolume(mountPath, outerVhd); + detachVolume(); volumeAttached = false; VERIFY_IS_FALSE(std::filesystem::exists(installPath / LXSS_VM_MODE_VHD_NAME)); - AttachTestVolume(mountPath, outerVhd); + attachVolume(); volumeAttached = true; VERIFY_IS_TRUE(std::filesystem::exists(installPath / LXSS_VM_MODE_VHD_NAME)); VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} /bin/true", testName)), 0L); From 8292b02e3750e7bb8e7411972ece3a37ead40566 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Thu, 20 Aug 2026 12:24:53 +0800 Subject: [PATCH 10/13] format code --- test/windows/UnitTests.cpp | 58 ++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 2753efc513..1e587b5023 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -7921,19 +7921,17 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", bool volumeAttached = false; auto attachVolume = [&]() { - RunDiskpartScript( - std::format( - L"select vdisk file=\"{}\"\n" - L"attach vdisk\n", - outerVhd.wstring())); + RunDiskpartScript(std::format( + L"select vdisk file=\"{}\"\n" + L"attach vdisk\n", + outerVhd.wstring())); }; auto detachVolume = [&]() { - RunDiskpartScript( - std::format( - L"select vdisk file=\"{}\"\n" - L"detach vdisk\n", - outerVhd.wstring())); + RunDiskpartScript(std::format( + L"select vdisk file=\"{}\"\n" + L"detach vdisk\n", + outerVhd.wstring())); }; auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() { @@ -7955,14 +7953,13 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", WslShutdown(); try { - RunDiskpartScript( - std::format( - L"select vdisk file=\"{}\"\n" - L"attach vdisk noerr\n" - L"select partition 1\n" - L"remove all noerr\n" - L"detach vdisk noerr\n", - outerVhd.wstring())); + RunDiskpartScript(std::format( + L"select vdisk file=\"{}\"\n" + L"attach vdisk noerr\n" + L"select partition 1\n" + L"remove all noerr\n" + L"detach vdisk noerr\n", + outerVhd.wstring())); } CATCH_LOG() @@ -7972,19 +7969,18 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", std::filesystem::create_directories(testRoot); std::filesystem::create_directories(mountPath); - RunDiskpartScript( - std::format( - L"create vdisk file=\"{}\" maximum=4096 type=expandable\n" - L"select vdisk file=\"{}\"\n" - L"attach vdisk\n" - L"create partition primary\n" - L"select partition 1\n" - L"online volume\n" - L"format fs=ntfs quick\n" - L"assign mount=\"{}\"\n", - outerVhd.wstring(), - outerVhd.wstring(), - mountPath.wstring())); + RunDiskpartScript(std::format( + L"create vdisk file=\"{}\" maximum=4096 type=expandable\n" + L"select vdisk file=\"{}\"\n" + L"attach vdisk\n" + L"create partition primary\n" + L"select partition 1\n" + L"online volume\n" + L"format fs=ntfs quick\n" + L"assign mount=\"{}\"\n", + outerVhd.wstring(), + outerVhd.wstring(), + mountPath.wstring())); volumeAttached = true; WslKeepAlive keepAlive; From 5243de20efca00bc989906f1e70dfb765da38a02 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Thu, 20 Aug 2026 12:57:57 +0800 Subject: [PATCH 11/13] revert test pipeline changes and remove the regression test --- .pipelines/build-job.yml | 6 +- .pipelines/build-stage.yml | 6 -- .pipelines/wsl-build-pr-onebranch.yml | 2 - .pipelines/wsl-build-pr.yml | 2 - cloudtest/CMakeLists.txt | 6 -- cloudtest/TestGroup.xml.in | 2 +- test/windows/Common.cpp | 26 -------- test/windows/Common.h | 2 - test/windows/UnitTests.cpp | 90 --------------------------- 9 files changed, 2 insertions(+), 140 deletions(-) diff --git a/.pipelines/build-job.yml b/.pipelines/build-job.yml index c19ddd9149..41060a8c6e 100644 --- a/.pipelines/build-job.yml +++ b/.pipelines/build-job.yml @@ -34,10 +34,6 @@ parameters: - name: artifactSuffix type: string - - name: cloudTestName - type: string - default: '' - - name: esrp type: object @@ -128,7 +124,7 @@ jobs: displayName: "CMake ${{ parameters.platform }}" inputs: workingDirectory: "." - cmakeArgs: . --fresh -A ${{ parameters.platform }} -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION=10.0.26100.0 -DPACKAGE_VERSION=$(version.WSL_PACKAGE_VERSION) -DWSL_NUGET_PACKAGE_VERSION=$(version.WSL_NUGET_PACKAGE_VERSION) -DSKIP_PACKAGE_SIGNING=${{ parameters.isRelease }} -DOFFICIAL_BUILD=${{ parameters.isRelease }} -DINCLUDE_PACKAGE_STAGE=${{ or(parameters.isRelease, parameters.isNightly) }} -DPIPELINE_BUILD_ID=$(Build.BuildId) -DVSO_ORG=${{ parameters.vsoOrg }} -DVSO_PROJECT=${{ parameters.vsoProject }} -DCLOUDTEST_TEST_NAME=${{ parameters.cloudTestName }} -DWSL_BUILD_WSL_SETTINGS=true -DWSL_INCLUDE_SDK_CSHARP=true -DWSL_UNITY_BATCH_SIZE=4 $(packageInputDirArg)\${{ parameters.platform }} + cmakeArgs: . --fresh -A ${{ parameters.platform }} -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION=10.0.26100.0 -DPACKAGE_VERSION=$(version.WSL_PACKAGE_VERSION) -DWSL_NUGET_PACKAGE_VERSION=$(version.WSL_NUGET_PACKAGE_VERSION) -DSKIP_PACKAGE_SIGNING=${{ parameters.isRelease }} -DOFFICIAL_BUILD=${{ parameters.isRelease }} -DINCLUDE_PACKAGE_STAGE=${{ or(parameters.isRelease, parameters.isNightly) }} -DPIPELINE_BUILD_ID=$(Build.BuildId) -DVSO_ORG=${{ parameters.vsoOrg }} -DVSO_PROJECT=${{ parameters.vsoProject }} -DWSL_BUILD_WSL_SETTINGS=true -DWSL_INCLUDE_SDK_CSHARP=true -DWSL_UNITY_BATCH_SIZE=4 $(packageInputDirArg)\${{ parameters.platform }} # Workaround for WSL Settings NuGet restore authentication issue - script: _deps\nuget.exe restore -NonInteractive diff --git a/.pipelines/build-stage.yml b/.pipelines/build-stage.yml index ea6b18d1b5..a10c08c110 100644 --- a/.pipelines/build-stage.yml +++ b/.pipelines/build-stage.yml @@ -19,10 +19,6 @@ parameters: type: string default: '' - - name: cloudTestName - type: string - default: '' - - name: nugetPackages type: object default: @@ -82,7 +78,6 @@ stages: isNightly: ${{ parameters.isNightly }} packageVersion: ${{ parameters.packageVersion }} traceLoggingConfig: ${{ parameters.traceLoggingConfig }} - cloudTestName: ${{ parameters.cloudTestName }} targets: ${{ parameters.targets }} pool: ${{ parameters.pool }} vsoOrg: ${{ parameters.vsoOrg }} @@ -143,7 +138,6 @@ stages: isNightly: ${{ parameters.isNightly }} packageVersion: ${{ parameters.packageVersion }} traceLoggingConfig: ${{ parameters.traceLoggingConfig }} - cloudTestName: ${{ parameters.cloudTestName }} targets: ${{ parameters.targets }} pool: ${{ parameters.pool }} vsoOrg: ${{ parameters.vsoOrg }} diff --git a/.pipelines/wsl-build-pr-onebranch.yml b/.pipelines/wsl-build-pr-onebranch.yml index c3887e611f..92a8a4cbd8 100644 --- a/.pipelines/wsl-build-pr-onebranch.yml +++ b/.pipelines/wsl-build-pr-onebranch.yml @@ -46,10 +46,8 @@ extends: - template: build-stage.yml@self parameters: isRelease: false - cloudTestName: 'UnitTests::UnitTests::CachedVhdIsReattachedAfterBackingVolumeRemount' - template: test-stage.yml@self parameters: includePackageStage: false rs_prerelease_only: true - versions: [wsl2] diff --git a/.pipelines/wsl-build-pr.yml b/.pipelines/wsl-build-pr.yml index 56303a1759..4a7e2d9128 100644 --- a/.pipelines/wsl-build-pr.yml +++ b/.pipelines/wsl-build-pr.yml @@ -8,7 +8,6 @@ stages: - template: build-stage.yml@self parameters: isRelease: false - cloudTestName: 'UnitTests::UnitTests::CachedVhdIsReattachedAfterBackingVolumeRemount' pool: 'wsl-build' vsoOrg: shine-oss vsoProject: wsl @@ -17,5 +16,4 @@ stages: parameters: includePackageStage: false rs_prerelease_only: true - versions: [wsl2] pool: server diff --git a/cloudtest/CMakeLists.txt b/cloudtest/CMakeLists.txt index bf2eadfde1..643a069d1c 100644 --- a/cloudtest/CMakeLists.txt +++ b/cloudtest/CMakeLists.txt @@ -47,12 +47,6 @@ function(add_test_group image version suffix filter) set(DIR ${OUT}/${image}-${suffix}) file(MAKE_DIRECTORY ${DIR}) - if(CLOUDTEST_TEST_NAME AND "${suffix}" STREQUAL "wsl2") - set(test_args "/name:${CLOUDTEST_TEST_NAME}") - else() - set(test_args "/select:"${filter}"") - endif() - configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TestMap.xml.in ${DIR}/TestMap.xml) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TestGroup.xml.in ${DIR}/TestGroup.xml) endfunction() diff --git a/cloudtest/TestGroup.xml.in b/cloudtest/TestGroup.xml.in index 6b7444bcbd..81c4a6c5f7 100644 --- a/cloudtest/TestGroup.xml.in +++ b/cloudtest/TestGroup.xml.in @@ -22,6 +22,6 @@ - + diff --git a/test/windows/Common.cpp b/test/windows/Common.cpp index 54a18f1364..e0b7577f98 100644 --- a/test/windows/Common.cpp +++ b/test/windows/Common.cpp @@ -3149,29 +3149,3 @@ void ValidateCOMErrorMessageContains(const std::wstring& ExpectedSubstring) VERIFY_FAIL(); } } - -void RunDiskpartScript(std::wstring_view Script) -{ - const auto scriptFileName = wsl::windows::common::filesystem::GetTempFilename(); - std::wofstream scriptFile(scriptFileName); - THROW_HR_IF(E_FAIL, !scriptFile.is_open()); - - auto cleanup = wil::scope_exit([&] { DeleteFileW(scriptFileName.c_str()); }); - scriptFile << Script; - scriptFile.close(); - - auto commandLine = std::format(L"diskpart.exe /s \"{}\"", scriptFileName); - wsl::windows::common::SubProcess process(nullptr, commandLine.c_str()); - const auto output = process.RunAndCaptureOutput(); - if (output.ExitCode != 0) - { - LogError( - "diskpart failed with exit code %lu. Script:\n%.*ls\nStdout:\n%ls\nStderr:\n%ls", - output.ExitCode, - static_cast(Script.size()), - Script.data(), - output.Stdout.c_str(), - output.Stderr.c_str()); - THROW_HR(E_FAIL); - } -} diff --git a/test/windows/Common.h b/test/windows/Common.h index 9f172a54b0..599ac069b2 100644 --- a/test/windows/Common.h +++ b/test/windows/Common.h @@ -723,5 +723,3 @@ void WriteSocket(SOCKET Socket, const void* data, size_t size); void ValidateCOMErrorMessage(const std::optional& Expected, const std::source_location& Source = std::source_location::current()); void ValidateCOMErrorMessageContains(const std::wstring& ExpectedSubstring); - -void RunDiskpartScript(std::wstring_view Script); diff --git a/test/windows/UnitTests.cpp b/test/windows/UnitTests.cpp index 1e587b5023..a4b062abbb 100644 --- a/test/windows/UnitTests.cpp +++ b/test/windows/UnitTests.cpp @@ -7910,95 +7910,5 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n", VERIFY_ARE_EQUAL(baselineCodePage, GetConsoleOutputCP(), L"Destruction restores the code page saved on the first call"); } - WSL2_TEST_METHOD(CachedVhdIsReattachedAfterBackingVolumeRemount) - { - const auto testName = std::format(L"cached-vhd-remount-{}-{}", GetCurrentProcessId(), GetTickCount64()); - const auto testRoot = std::filesystem::temp_directory_path() / testName; - const auto outerVhd = testRoot / L"outer.vhdx"; - const auto mountPath = testRoot / L"mount"; - const auto installPath = mountPath / L"distro"; - bool imported = false; - bool volumeAttached = false; - - auto attachVolume = [&]() { - RunDiskpartScript(std::format( - L"select vdisk file=\"{}\"\n" - L"attach vdisk\n", - outerVhd.wstring())); - }; - - auto detachVolume = [&]() { - RunDiskpartScript(std::format( - L"select vdisk file=\"{}\"\n" - L"detach vdisk\n", - outerVhd.wstring())); - }; - - auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() { - if (imported) - { - if (!volumeAttached) - { - try - { - attachVolume(); - volumeAttached = true; - } - CATCH_LOG() - } - - LxsstuLaunchWsl(std::format(L"--unregister {}", testName)); - } - - WslShutdown(); - try - { - RunDiskpartScript(std::format( - L"select vdisk file=\"{}\"\n" - L"attach vdisk noerr\n" - L"select partition 1\n" - L"remove all noerr\n" - L"detach vdisk noerr\n", - outerVhd.wstring())); - } - CATCH_LOG() - - std::error_code error; - std::filesystem::remove_all(testRoot, error); - }); - - std::filesystem::create_directories(testRoot); - std::filesystem::create_directories(mountPath); - RunDiskpartScript(std::format( - L"create vdisk file=\"{}\" maximum=4096 type=expandable\n" - L"select vdisk file=\"{}\"\n" - L"attach vdisk\n" - L"create partition primary\n" - L"select partition 1\n" - L"online volume\n" - L"format fs=ntfs quick\n" - L"assign mount=\"{}\"\n", - outerVhd.wstring(), - outerVhd.wstring(), - mountPath.wstring())); - volumeAttached = true; - - WslKeepAlive keepAlive; - const auto importResult = - LxsstuLaunchWsl(std::format(L"--import {} \"{}\" \"{}\" --version 2", testName, installPath.c_str(), g_testDistroPath)); - imported = (importResult == 0); - VERIFY_ARE_EQUAL(importResult, 0L); - - VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} /bin/true", testName)), 0L); - VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"--terminate {}", testName)), 0L); - detachVolume(); - volumeAttached = false; - VERIFY_IS_FALSE(std::filesystem::exists(installPath / LXSS_VM_MODE_VHD_NAME)); - - attachVolume(); - volumeAttached = true; - VERIFY_IS_TRUE(std::filesystem::exists(installPath / LXSS_VM_MODE_VHD_NAME)); - VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} /bin/true", testName)), 0L); - } }; // namespace UnitTests } // namespace UnitTests From db52d50fa20e881a80f7a0f1fe503a3803a16697 Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Thu, 20 Aug 2026 13:57:23 +0800 Subject: [PATCH 12/13] trigger pipeline --- src/windows/service/exe/WslCoreVm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/windows/service/exe/WslCoreVm.h b/src/windows/service/exe/WslCoreVm.h index 8c4d00d1cc..3dd31ba10f 100644 --- a/src/windows/service/exe/WslCoreVm.h +++ b/src/windows/service/exe/WslCoreVm.h @@ -161,6 +161,7 @@ class WslCoreVm std::map Mounts; DiskStateFlags Flags; wil::unique_hfile BackingFile; + }; struct VirtioFsShare From c61d61c3a22e0a1fe71690558001cf6e31dca38a Mon Sep 17 00:00:00 2001 From: Feng Wang Date: Thu, 20 Aug 2026 13:57:29 +0800 Subject: [PATCH 13/13] trigger pipeline --- src/windows/service/exe/WslCoreVm.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/windows/service/exe/WslCoreVm.h b/src/windows/service/exe/WslCoreVm.h index 3dd31ba10f..8c4d00d1cc 100644 --- a/src/windows/service/exe/WslCoreVm.h +++ b/src/windows/service/exe/WslCoreVm.h @@ -161,7 +161,6 @@ class WslCoreVm std::map Mounts; DiskStateFlags Flags; wil::unique_hfile BackingFile; - }; struct VirtioFsShare