Skip to content
Open
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
23 changes: 23 additions & 0 deletions src/linux/init/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,11 @@ int GenerateSystemdUnits(int Argc, char** Argv)
File.reset();
}

if (automountRoot.empty() || automountRoot.back() != '/')
{
automountRoot += '/';
}

// Mask systemd-networkd-wait-online.service since WSL always ensures that networking is configured during boot.
// That unit can cause systemd boot timeouts since WSL's network interface is unmanaged by systemd.
THROW_LAST_ERROR_IF(symlink("/dev/null", std::format("{}/systemd-networkd-wait-online.service", installPath).c_str()) < 0);
Expand All @@ -355,6 +360,24 @@ int GenerateSystemdUnits(int Argc, char** Argv)
// When multiple distros are running, the second distro's getty fails because the tty is already held.
THROW_LAST_ERROR_IF(symlink("/dev/null", std::format("{}/console-getty.service", installPath).c_str()) < 0);

const auto sharedMountPath = automountRoot + "wsl";
const auto mountGuardUnitContent = std::format(
R"(# Note: This file is generated by WSL to prevent shutdown unmounts from propagating to other distributions.

[Unit]
Description=WSL Cross-Distribution Mount Guard
After=local-fs.target remote-fs.target
ConditionPathIsMountPoint={}

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/true
ExecStop=-/bin/mount --make-rslave {})",
sharedMountPath,
sharedMountPath);
InstallSystemdUnit(installPath, "wsl-mnt-guard", mountGuardUnitContent.c_str());

// Only create the wslg unit if both enabled in wsl.conf, and if the wslg folder actually exists.
if (enableGuiApps && access("/mnt/wslg/runtime-dir", F_OK) == 0)
{
Expand Down
43 changes: 43 additions & 0 deletions test/windows/UnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,49 @@ class UnitTests
}
}

WSL2_TEST_METHOD(SharedMountSurvivesDistroTermination)
{
constexpr auto peerDistroName = L"mount-guard-peer-test";

auto validate = [&](const std::string& automountRoot) {
const auto extraConfig = automountRoot.empty() ? "" : std::format("[automount]\nroot={}\n", automountRoot);
const auto effectiveAutomountRoot = automountRoot.empty() ? "/mnt" : automountRoot;
const auto mountPoint = std::format(L"{}/wsl/mount-guard-test", wsl::shared::string::MultiByteToWide(effectiveAutomountRoot));

auto cleanupVm = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, []() { WslShutdown(); });
auto cleanupSystemd = EnableSystemd(extraConfig);

LxsstuLaunchWsl(std::format(L"--unregister {}", peerDistroName));
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"--import {} . \"{}\" --version 2", peerDistroName, g_testDistroPath)), 0L);
auto cleanupPeer = wil::scope_exit_log(
WI_DIAGNOSTICS_INFO, [&]() { LxsstuLaunchWsl(std::format(L"--unregister {}", peerDistroName)); });

auto cleanupPeerSystemd = EnableSystemd(extraConfig, peerDistroName);

VERIFY_ARE_EQUAL(
LxsstuLaunchWsl(std::format(L"-d {} -- sh -c \"systemctl is-system-running | grep -Eq 'running|degraded'\"", peerDistroName)), 0L);

VERIFY_ARE_EQUAL(
LxsstuLaunchWsl(std::format(
L"sh -c 'mkdir -p {0} && mount -t tmpfs -o size=4M mount-guard-test {0} && echo survived > {0}/marker'", mountPoint)),
0L);
auto cleanupMount = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
LxsstuLaunchWsl(std::format(L"sh -c 'umount {0} 2>/dev/null || true; rmdir {0} 2>/dev/null || true'", mountPoint));
});

VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} -- findmnt -n {}", peerDistroName, mountPoint)), 0L);
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"-d {} -- grep -qx survived {}/marker", peerDistroName, mountPoint)), 0L);

TerminateDistribution(peerDistroName);

VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"findmnt -n {}", mountPoint)), 0L);
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(std::format(L"grep -qx survived {}/marker", mountPoint)), 0L);
};

validate("");
validate("/wsl-test-mount");
}

WSL2_TEST_METHOD(ConfigUpdateLanguage)
{
// Validates that init populates $LANG from the distro locale configuration file.
Expand Down