Fix spurious ERROR log for unsupported optional cgroup controllers (#41122)

* Fix spurious ERROR log for unsupported optional cgroup controllers UtilEnableAllCgroupControllers previously attempted to enable a hardcoded list of optional controllers (pids, io, cpuset, hugetlb, rdma, misc) regardless of kernel support. On the default WSL2 kernel, which lacks CONFIG_CGROUP_MISC, the write for +misc fails and WriteToFile logs it as an ERROR, producing a scary but harmless line in dmesg on every boot: WSL ERROR: WriteToFile:3414: write(.../cgroup.subtree_control, +misc) failed -1 22 Fix: use cgroup.controllers as the single source of truth for which optional controllers are actually supported by the running kernel, instead of guessing with a hardcoded list. cpu and memory remain required and are enabled unconditionally (fatal if it fails); every other controller the kernel reports is enabled best-effort (a failure there is just a warning). Validated on a live WSL2 instance: dmesg is clean and cgroup.controllers/cgroup.subtree_control are consistent at every cgroup level. * Drop redundant WARNING for optional cgroup controller failures WriteToFile already logs on failure, so the extra LOG_WARNING wrapper was redundant double-logging. This path shouldn't be hit in practice now that optional controllers are sourced from cgroup.controllers. --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>

Ben Hillis committed Jul 23, 2026 at 13:48 UTC 745dd85b62a848710c07fb925d422711ac86a9d1
1 file changed +28 -6
src/linux/init/util.cpp
+28 -6
@@ -26,6 +26,7 @@ Abstract:
26 #include <fstream>
27 #include <iostream>
28 #include <sstream>
29 +#include <algorithm>
30 #include <regex>
31 #include <thread>
32 #include <chrono>
@@ -3772,19 +3773,40 @@ std::string UtilGetDistroCgroupPath(pid_t DistroInitPid)
3773
3774 int UtilEnableAllCgroupControllers(const std::string& CgroupPath)
3775 {
3775 - // Only cpu and memory are required for wsl's resource limit.
3776 - if (WriteToFile((CgroupPath + "/cgroup.subtree_control").c_str(), "+cpu +memory") < 0)
3776 + // Only cpu and memory are required for wsl's resource limit; every other controller cgroup.controllers
3777 + // reports is enabled on a best-effort basis.
3778 + constexpr std::string_view RequiredControllers[] = {"cpu", "memory"};
3779 + std::string RequiredEntries;
3780 + for (const auto Controller : RequiredControllers)
3781 + {
3782 + RequiredEntries += std::format("+{} ", Controller);
3783 + }
3784 +
3785 + if (WriteToFile((CgroupPath + "/cgroup.subtree_control").c_str(), RequiredEntries.c_str()) < 0)
3786 {
3787 LOG_ERROR("Failed to enable cgroup controllers for {}: {}", CgroupPath, errno);
3788 return -1;
3789 }
3781 - const char* const OptionalControllers[] = {"+pids", "+io", "+cpuset", "+hugetlb", "+rdma", "+misc"};
3782 - for (const auto Controller : OptionalControllers)
3790 +
3791 + std::string AvailableControllers;
3792 + try
3793 + {
3794 + AvailableControllers = UtilReadFileContent(CgroupPath + "/cgroup.controllers");
3795 + }
3796 + CATCH_LOG();
3797 +
3798 + std::string_view Remaining{AvailableControllers};
3799 + while (!Remaining.empty())
3800 {
3784 - if (WriteToFile((CgroupPath + "/cgroup.subtree_control").c_str(), Controller) < 0)
3801 + auto Controller = UtilStringNextToken(Remaining, " \n");
3802 + if (Controller.empty() ||
3803 + std::find(std::begin(RequiredControllers), std::end(RequiredControllers), Controller) != std::end(RequiredControllers))
3804 {
3786 - LOG_WARNING("Failed to enable optional cgroup controller {} for {}: {}", Controller, CgroupPath, errno);
3805 + continue;
3806 }
3807 +
3808 + // WriteToFile() already logs a failure; these controllers are best-effort so no extra handling is needed.
3809 + WriteToFile((CgroupPath + "/cgroup.subtree_control").c_str(), std::format("+{}", Controller).c_str());
3810 }
3811 return 0;
3812 }