mirror of
https://github.com/microsoft/WSL.git
synced 2025-12-10 00:44:55 -06:00
Introduce a new wsl.conf config value to allow distributions to opt-in to cgroupv1 mounts (#13546)
* Introduce a new wsl.conf config value to allow distributions to opt-in to cgroupv1 mounts * Add test coverage * Fix tmpfs on wsl1 --------- Co-authored-by: Ben Hillis <benhillis@gmail.com>
This commit is contained in:
parent
98f4960118
commit
65eea7b31c
@ -28,6 +28,7 @@ WslDistributionConfig::WslDistributionConfig(const char* configFilePath)
|
|||||||
ConfigKey("automount.options", DrvFsOptions),
|
ConfigKey("automount.options", DrvFsOptions),
|
||||||
ConfigKey(c_ConfigMountFsTabOption, MountFsTab),
|
ConfigKey(c_ConfigMountFsTabOption, MountFsTab),
|
||||||
ConfigKey(c_ConfigLinkOsLibsOption, LinkOsLibs),
|
ConfigKey(c_ConfigLinkOsLibsOption, LinkOsLibs),
|
||||||
|
ConfigKey("automount.cgroups", {{"v1", CGroupVersion::v1}, {"v2", CGroupVersion::v2}}, CGroup, nullptr),
|
||||||
|
|
||||||
ConfigKey("filesystem.umask", Umask),
|
ConfigKey("filesystem.umask", Umask),
|
||||||
|
|
||||||
|
|||||||
@ -48,6 +48,12 @@ struct WslDistributionConfig
|
|||||||
WslDistributionConfig(WslDistributionConfig&&) = default;
|
WslDistributionConfig(WslDistributionConfig&&) = default;
|
||||||
WslDistributionConfig& operator=(WslDistributionConfig&&) = default;
|
WslDistributionConfig& operator=(WslDistributionConfig&&) = default;
|
||||||
|
|
||||||
|
enum class CGroupVersion
|
||||||
|
{
|
||||||
|
v1 = 0,
|
||||||
|
v2 = 1
|
||||||
|
};
|
||||||
|
|
||||||
bool AutoMount = true;
|
bool AutoMount = true;
|
||||||
bool AutoUpdateTimezone = true;
|
bool AutoUpdateTimezone = true;
|
||||||
std::optional<std::string> BootCommand;
|
std::optional<std::string> BootCommand;
|
||||||
@ -71,6 +77,7 @@ struct WslDistributionConfig
|
|||||||
bool AppendGpuLibPath = true;
|
bool AppendGpuLibPath = true;
|
||||||
bool GpuEnabled = true;
|
bool GpuEnabled = true;
|
||||||
bool LinkOsLibs = true;
|
bool LinkOsLibs = true;
|
||||||
|
CGroupVersion CGroup = CGroupVersion::v2;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Values not set by /etc/wsl.conf.
|
// Values not set by /etc/wsl.conf.
|
||||||
|
|||||||
@ -73,6 +73,8 @@ Abstract:
|
|||||||
#define MOUNTS_DEVICE_FIELD 0
|
#define MOUNTS_DEVICE_FIELD 0
|
||||||
#define MOUNTS_FSTYPE_FIELD 2
|
#define MOUNTS_FSTYPE_FIELD 2
|
||||||
|
|
||||||
|
using wsl::linux::WslDistributionConfig;
|
||||||
|
|
||||||
static void ConfigApplyWindowsLibPath(const wsl::linux::WslDistributionConfig& Config);
|
static void ConfigApplyWindowsLibPath(const wsl::linux::WslDistributionConfig& Config);
|
||||||
|
|
||||||
static bool CreateLoginSession(const wsl::linux::WslDistributionConfig& Config, const char* Username, uid_t Uid);
|
static bool CreateLoginSession(const wsl::linux::WslDistributionConfig& Config, const char* Username, uid_t Uid);
|
||||||
@ -567,7 +569,7 @@ Return Value:
|
|||||||
// Initialize cgroups based on what the kernel supports.
|
// Initialize cgroups based on what the kernel supports.
|
||||||
//
|
//
|
||||||
|
|
||||||
ConfigInitializeCgroups();
|
ConfigInitializeCgroups(Config);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Attempt to register the NT interop binfmt extension.
|
// Attempt to register the NT interop binfmt extension.
|
||||||
@ -1783,7 +1785,7 @@ Return Value:
|
|||||||
{LX_WSL2_GUI_APP_SUPPORT_ENV, "1"}};
|
{LX_WSL2_GUI_APP_SUPPORT_ENV, "1"}};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigInitializeCgroups(void)
|
void ConfigInitializeCgroups(wsl::linux::WslDistributionConfig& Config)
|
||||||
|
|
||||||
/*++
|
/*++
|
||||||
|
|
||||||
@ -1795,7 +1797,7 @@ Routine Description:
|
|||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
None.
|
Config - Supplies the distribution configuration.
|
||||||
|
|
||||||
Return Value:
|
Return Value:
|
||||||
|
|
||||||
@ -1805,50 +1807,82 @@ Return Value:
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> DisabledControllers;
|
||||||
//
|
|
||||||
// For WSL2 mount cgroup v2.
|
|
||||||
//
|
|
||||||
// N.B. Cgroup v2 is not implemented for WSL1.
|
|
||||||
//
|
|
||||||
|
|
||||||
if (UtilIsUtilityVm())
|
if (UtilIsUtilityVm())
|
||||||
{
|
{
|
||||||
const auto Target = CGROUP_MOUNTPOINT;
|
if (Config.CGroup == WslDistributionConfig::CGroupVersion::v1)
|
||||||
|
{
|
||||||
|
auto commandLine = UtilReadFileContent("/proc/cmdline");
|
||||||
|
auto position = commandLine.find(CGROUPS_NO_V1);
|
||||||
|
if (position != std::string::npos)
|
||||||
|
{
|
||||||
|
auto list = commandLine.substr(position + sizeof(CGROUPS_NO_V1) - 1);
|
||||||
|
auto end = list.find_first_of(" \n");
|
||||||
|
if (end != std::string::npos)
|
||||||
|
{
|
||||||
|
list = list.substr(0, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list == "all")
|
||||||
|
{
|
||||||
|
LOG_WARNING("Distribution has cgroupv1 enabled, but kernel command line has {}all. Falling back to cgroupv2", CGROUPS_NO_V1);
|
||||||
|
Config.CGroup = WslDistributionConfig::CGroupVersion::v2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DisabledControllers = wsl::shared::string::Split(list, ',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.CGroup == WslDistributionConfig::CGroupVersion::v1)
|
||||||
|
{
|
||||||
|
THROW_LAST_ERROR_IF(mount("tmpfs", CGROUP_MOUNTPOINT, "tmpfs", (MS_NOSUID | MS_NODEV | MS_NOEXEC), "mode=755") < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto Target = Config.CGroup == WslDistributionConfig::CGroupVersion::v1 ? CGROUP_MOUNTPOINT "/unified" : CGROUP_MOUNTPOINT;
|
||||||
THROW_LAST_ERROR_IF(
|
THROW_LAST_ERROR_IF(
|
||||||
UtilMount(CGROUP2_DEVICE, Target, CGROUP2_DEVICE, (MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME), "nsdelegate") < 0);
|
UtilMount(CGROUP2_DEVICE, Target, CGROUP2_DEVICE, (MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME), "nsdelegate") < 0);
|
||||||
|
|
||||||
|
if (Config.CGroup == WslDistributionConfig::CGroupVersion::v2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//
|
|
||||||
// Mount cgroup v1 when running in WSL1 mode.
|
|
||||||
//
|
|
||||||
// Open the /proc/cgroups file and parse each line, ignoring malformed
|
|
||||||
// lines and disabled controllers.
|
|
||||||
//
|
|
||||||
|
|
||||||
THROW_LAST_ERROR_IF(mount("tmpfs", CGROUP_MOUNTPOINT, "tmpfs", (MS_NOSUID | MS_NODEV | MS_NOEXEC), "mode=755") < 0);
|
THROW_LAST_ERROR_IF(mount("tmpfs", CGROUP_MOUNTPOINT, "tmpfs", (MS_NOSUID | MS_NODEV | MS_NOEXEC), "mode=755") < 0);
|
||||||
|
}
|
||||||
|
|
||||||
wil::unique_file Cgroups{fopen(CGROUPS_FILE, "r")};
|
//
|
||||||
THROW_LAST_ERROR_IF(!Cgroups);
|
// Mount cgroup v1 when running in WSL1 mode or when a WSL2 distro has automount.cgroups=v1 specified.
|
||||||
|
//
|
||||||
|
// Open the /proc/cgroups file and parse each line, ignoring malformed
|
||||||
|
// lines and disabled controllers.
|
||||||
|
//
|
||||||
|
|
||||||
|
wil::unique_file Cgroups{fopen(CGROUPS_FILE, "r")};
|
||||||
|
THROW_LAST_ERROR_IF(!Cgroups);
|
||||||
|
|
||||||
|
ssize_t BytesRead;
|
||||||
|
char* Line = nullptr;
|
||||||
|
auto LineCleanup = wil::scope_exit([&]() { free(Line); });
|
||||||
|
size_t LineLength = 0;
|
||||||
|
while ((BytesRead = getline(&Line, &LineLength, Cgroups.get())) != -1)
|
||||||
|
{
|
||||||
|
char* Subsystem = nullptr;
|
||||||
|
bool Enabled = false;
|
||||||
|
if ((UtilParseCgroupsLine(Line, &Subsystem, &Enabled) < 0) || (Enabled == false) ||
|
||||||
|
std::find(DisabledControllers.begin(), DisabledControllers.end(), Subsystem) != DisabledControllers.end())
|
||||||
|
|
||||||
ssize_t BytesRead;
|
|
||||||
char* Line = nullptr;
|
|
||||||
auto LineCleanup = wil::scope_exit([&]() { free(Line); });
|
|
||||||
size_t LineLength = 0;
|
|
||||||
while ((BytesRead = getline(&Line, &LineLength, Cgroups.get())) != -1)
|
|
||||||
{
|
{
|
||||||
char* Subsystem = nullptr;
|
continue;
|
||||||
bool Enabled = false;
|
|
||||||
if ((UtilParseCgroupsLine(Line, &Subsystem, &Enabled) < 0) || (Enabled == false))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Target = std::format("{}/{}", CGROUP_MOUNTPOINT, Subsystem);
|
|
||||||
THROW_LAST_ERROR_IF(
|
|
||||||
UtilMount(CGROUP_DEVICE, Target.c_str(), CGROUP_DEVICE, (MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME), Subsystem) < 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Target = std::format("{}/{}", CGROUP_MOUNTPOINT, Subsystem);
|
||||||
|
THROW_LAST_ERROR_IF(
|
||||||
|
UtilMount(CGROUP_DEVICE, Target.c_str(), CGROUP_DEVICE, (MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME), Subsystem) < 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CATCH_LOG()
|
CATCH_LOG()
|
||||||
|
|||||||
@ -406,7 +406,7 @@ void ConfigHandleInteropMessage(
|
|||||||
const MESSAGE_HEADER* Header,
|
const MESSAGE_HEADER* Header,
|
||||||
const wsl::linux::WslDistributionConfig& Config);
|
const wsl::linux::WslDistributionConfig& Config);
|
||||||
|
|
||||||
void ConfigInitializeCgroups(void);
|
void ConfigInitializeCgroups(wsl::linux::WslDistributionConfig& Config);
|
||||||
|
|
||||||
int ConfigInitializeInstance(wsl::shared::SocketChannel& Channel, gsl::span<gsl::byte> Buffer, wsl::linux::WslDistributionConfig& Config);
|
int ConfigInitializeInstance(wsl::shared::SocketChannel& Channel, gsl::span<gsl::byte> Buffer, wsl::linux::WslDistributionConfig& Config);
|
||||||
|
|
||||||
|
|||||||
@ -6156,5 +6156,43 @@ Error code: Wsl/InstallDistro/WSL_E_INVALID_JSON\r\n",
|
|||||||
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"dmesg | grep -iF 'vmbus_send_tl_connect_request'"), 0L);
|
VERIFY_ARE_EQUAL(LxsstuLaunchWsl(L"dmesg | grep -iF 'vmbus_send_tl_connect_request'"), 0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(CGroupv1)
|
||||||
|
{
|
||||||
|
WSL2_TEST_ONLY();
|
||||||
|
|
||||||
|
auto expectedMount = [](const char* path, const wchar_t* expected) {
|
||||||
|
auto [out, _] = LxsstuLaunchWslAndCaptureOutput(std::format(L"findmnt -ln '{}' || true", path));
|
||||||
|
|
||||||
|
VERIFY_ARE_EQUAL(out, expected);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Validate that cgroupv2 is mounted by default.
|
||||||
|
expectedMount("/sys/fs/cgroup", L"/sys/fs/cgroup cgroup2 cgroup2 rw,nosuid,nodev,noexec,relatime,nsdelegate\n");
|
||||||
|
|
||||||
|
// Validate that setting cgroup=v1 causes unified cgroups to be mounted.
|
||||||
|
DistroFileChange wslConf(L"/etc/wsl.conf", false);
|
||||||
|
wslConf.SetContent(L"[automount]\ncgroups=v1");
|
||||||
|
|
||||||
|
TerminateDistribution();
|
||||||
|
|
||||||
|
expectedMount(
|
||||||
|
"/sys/fs/cgroup/unified", L"/sys/fs/cgroup/unified cgroup2 cgroup2 rw,nosuid,nodev,noexec,relatime,nsdelegate\n");
|
||||||
|
|
||||||
|
// Validate that the cgroupv1 mounts are present.
|
||||||
|
expectedMount("/sys/fs/cgroup/cpu", L"/sys/fs/cgroup/cpu cgroup cgroup rw,nosuid,nodev,noexec,relatime,cpu\n");
|
||||||
|
|
||||||
|
// Validate that having cgroup_no_v1=all causes the distribution to fall back to v2.
|
||||||
|
WslConfigChange wslConfig(LxssGenerateTestConfig({.kernelCommandLine = L"cgroup_no_v1=all"}));
|
||||||
|
|
||||||
|
expectedMount("/sys/fs/cgroup/unified", L"");
|
||||||
|
expectedMount("/sys/fs/cgroup", L"/sys/fs/cgroup cgroup2 cgroup2 rw,nosuid,nodev,noexec,relatime,nsdelegate\n");
|
||||||
|
|
||||||
|
auto [dmesg, __] = LxsstuLaunchWslAndCaptureOutput(L"dmesg");
|
||||||
|
VERIFY_ARE_NOT_EQUAL(
|
||||||
|
dmesg.find(
|
||||||
|
L"Distribution has cgroupv1 enabled, but kernel command line has cgroup_no_v1=all. Falling back to cgroupv2"),
|
||||||
|
std::wstring::npos);
|
||||||
|
}
|
||||||
|
|
||||||
}; // namespace UnitTests
|
}; // namespace UnitTests
|
||||||
} // namespace UnitTests
|
} // namespace UnitTests
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user