aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2022-12-02 12:57:41 +0100
committerEelco Dolstra <edolstra@gmail.com>2022-12-02 12:59:13 +0100
commit1e6a5d1ff6e8ef5bf340502f74c4d5039cedc67a (patch)
tree59899facd4e1989db3f0370aa2e75d0748577d66
parent1211e59a038379026496bbee4b203bbd66833b01 (diff)
Clean up cgroup handling in getMaxCPU()
Also, don't assume in LocalDerivationGoal that cgroups are mounted on /sys/fs/cgroup.
-rw-r--r--src/libstore/build/local-derivation-goal.cc6
-rw-r--r--src/libutil/cgroup.cc17
-rw-r--r--src/libutil/cgroup.hh2
-rw-r--r--src/libutil/util.cc49
4 files changed, 39 insertions, 35 deletions
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index c9b7b24f3..d2798888b 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -409,12 +409,16 @@ void LocalDerivationGoal::startBuilder()
#if __linux__
settings.requireExperimentalFeature(Xp::Cgroups);
+ auto cgroupFS = getCgroupFS();
+ if (!cgroupFS)
+ throw Error("cannot determine the cgroups file system");
+
auto ourCgroups = getCgroups("/proc/self/cgroup");
auto ourCgroup = ourCgroups[""];
if (ourCgroup == "")
throw Error("cannot determine cgroup name from /proc/self/cgroup");
- auto ourCgroupPath = canonPath("/sys/fs/cgroup/" + ourCgroup);
+ auto ourCgroupPath = canonPath(*cgroupFS + "/" + ourCgroup);
if (!pathExists(ourCgroupPath))
throw Error("expected cgroup directory '%s'", ourCgroupPath);
diff --git a/src/libutil/cgroup.cc b/src/libutil/cgroup.cc
index f693d77be..a008481ca 100644
--- a/src/libutil/cgroup.cc
+++ b/src/libutil/cgroup.cc
@@ -2,6 +2,7 @@
#include "cgroup.hh"
#include "util.hh"
+#include "finally.hh"
#include <chrono>
#include <cmath>
@@ -10,9 +11,25 @@
#include <thread>
#include <dirent.h>
+#include <mntent.h>
namespace nix {
+std::optional<Path> getCgroupFS()
+{
+ static auto res = [&]() -> std::optional<Path> {
+ auto fp = fopen("/proc/mounts", "r");
+ if (!fp) return std::nullopt;
+ Finally delFP = [&]() { fclose(fp); };
+ while (auto ent = getmntent(fp))
+ if (std::string_view(ent->mnt_type) == "cgroup2")
+ return ent->mnt_dir;
+
+ return std::nullopt;
+ }();
+ return res;
+}
+
// FIXME: obsolete, check for cgroup2
std::map<std::string, std::string> getCgroups(const Path & cgroupFile)
{
diff --git a/src/libutil/cgroup.hh b/src/libutil/cgroup.hh
index 3ead4735f..d08c8ad29 100644
--- a/src/libutil/cgroup.hh
+++ b/src/libutil/cgroup.hh
@@ -9,6 +9,8 @@
namespace nix {
+std::optional<Path> getCgroupFS();
+
std::map<std::string, std::string> getCgroups(const Path & cgroupFile);
struct CgroupStats
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 623b74bdd..2c2aae82e 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -2,6 +2,7 @@
#include "sync.hh"
#include "finally.hh"
#include "serialise.hh"
+#include "cgroup.hh"
#include <array>
#include <cctype>
@@ -36,7 +37,6 @@
#include <sys/prctl.h>
#include <sys/resource.h>
-#include <mntent.h>
#include <cmath>
#endif
@@ -727,43 +727,24 @@ unsigned int getMaxCPU()
{
#if __linux__
try {
- FILE *fp = fopen("/proc/mounts", "r");
- if (!fp)
- return 0;
+ auto cgroupFS = getCgroupFS();
+ if (!cgroupFS) return 0;
- Strings cgPathParts;
+ if (!pathExists("/proc/self/cgroup")) return 0;
- struct mntent *ent;
- while ((ent = getmntent(fp))) {
- std::string mountType, mountPath;
+ auto cgroups = getCgroups("/proc/self/cgroup");
+ auto cgroup = cgroups[""];
+ if (cgroup == "") return 0;
- mountType = ent->mnt_type;
- mountPath = ent->mnt_dir;
+ auto cpuFile = *cgroupFS + "/" + cgroup + "/cpu.max";
- if (mountType == "cgroup2") {
- cgPathParts.push_back(mountPath);
- break;
- }
- }
-
- fclose(fp);
-
- if (cgPathParts.size() > 0 && pathExists("/proc/self/cgroup")) {
- std::string currentCgroup = readFile("/proc/self/cgroup");
- Strings cgValues = tokenizeString<Strings>(currentCgroup, ":");
- cgPathParts.push_back(trim(cgValues.back(), "\n"));
- cgPathParts.push_back("cpu.max");
- std::string fullCgPath = canonPath(concatStringsSep("/", cgPathParts));
-
- if (pathExists(fullCgPath)) {
- std::string cpuMax = readFile(fullCgPath);
- std::vector<std::string> cpuMaxParts = tokenizeString<std::vector<std::string>>(cpuMax, " ");
- std::string quota = cpuMaxParts[0];
- std::string period = trim(cpuMaxParts[1], "\n");
-
- if (quota != "max")
- return std::ceil(std::stoi(quota) / std::stof(period));
- }
+ if (pathExists(cpuFile)) {
+ auto cpuMax = readFile(cpuFile);
+ auto cpuMaxParts = tokenizeString<std::vector<std::string>>(cpuMax, " \n");
+ auto quota = cpuMaxParts[0];
+ auto period = cpuMaxParts[1];
+ if (quota != "max")
+ return std::ceil(std::stoi(quota) / std::stof(period));
}
} catch (Error &) { ignoreException(); }
#endif