Simplify cgroup creation

This commit is contained in:
Eelco Dolstra 2020-05-16 21:21:41 +02:00
parent 7bdcf43b40
commit 570c443f56
3 changed files with 35 additions and 37 deletions

View file

@ -2375,50 +2375,30 @@ void DerivationGoal::startBuilder()
#if __linux__ #if __linux__
if (useChroot) { if (useChroot) {
/* Create a cgroup. */ /* Create a systemd cgroup since that's the minimum required
by systemd-nspawn. */
// FIXME: do we want to use the parent cgroup? We should // FIXME: do we want to use the parent cgroup? We should
// always use the same cgroup regardless of whether we're the // always use the same cgroup regardless of whether we're the
// daemon or run from a user session via sudo. // daemon or run from a user session via sudo.
std::string msg; auto ourCgroups = getCgroups("/proc/self/cgroup");
std::vector<Path> cgroups; auto systemdCgroup = ourCgroups["systemd"];
for (auto & line : tokenizeString<std::vector<std::string>>(readFile("/proc/self/cgroup"), "\n")) { if (systemdCgroup == "")
static std::regex regex("([0-9]+):([^:]*):(.*)"); throw Error("'systemd' cgroup does not exist");
std::smatch match;
if (!std::regex_match(line, match, regex))
throw Error("invalid line '%s' in '/proc/self/cgroup'", line);
/* We only create a systemd cgroup, since that's enough auto hostCgroup = canonPath("/sys/fs/cgroup/systemd/" + systemdCgroup);
for running systemd-nspawn. */
std::string name;
if (match[2] == "name=systemd")
name = "systemd";
//else if (match[2] == "")
// name = "unified";
else continue;
std::string cgroup = match[3]; if (!pathExists(hostCgroup))
throw Error("expected cgroup directory '%s'", hostCgroup);
auto hostCgroup = canonPath("/sys/fs/cgroup/" + name + "/" + cgroup); auto childCgroup = fmt("%s/nix-%d", hostCgroup, buildUser->getUID());
if (!pathExists(hostCgroup)) destroyCgroup(childCgroup);
throw Error("expected cgroup directory '%s'", hostCgroup);
auto childCgroup = fmt("%s/nix-%d", hostCgroup, buildUser->getUID()); if (mkdir(childCgroup.c_str(), 0755) == -1)
throw SysError("creating cgroup '%s'", childCgroup);
destroyCgroup(childCgroup); chownToBuilder(childCgroup);
chownToBuilder(childCgroup + "/cgroup.procs");
if (mkdir(childCgroup.c_str(), 0755) == -1)
throw SysError("creating cgroup '%s'", childCgroup);
chownToBuilder(childCgroup);
chownToBuilder(childCgroup + "/cgroup.procs");
if (name == "unified") {
chownToBuilder(childCgroup + "/cgroup.threads");
chownToBuilder(childCgroup + "/cgroup.subtree_control");
}
cgroups.push_back(childCgroup);
}
/* Set up private namespaces for the build: /* Set up private namespaces for the build:
@ -2545,8 +2525,7 @@ void DerivationGoal::startBuilder()
throw SysError("getting sandbox mount namespace"); throw SysError("getting sandbox mount namespace");
/* Move the child into its own cgroup. */ /* Move the child into its own cgroup. */
for (auto & childCgroup : cgroups) writeFile(childCgroup + "/cgroup.procs", fmt("%d", (pid_t) pid));
writeFile(childCgroup + "/cgroup.procs", fmt("%d", (pid_t) pid));
/* Signal the builder that we've updated its user namespace. */ /* Signal the builder that we've updated its user namespace. */
writeFull(userNamespaceSync.writeSide.get(), "1"); writeFull(userNamespaceSync.writeSide.get(), "1");

View file

@ -9,6 +9,23 @@
namespace nix { namespace nix {
std::map<std::string, std::string> getCgroups(const Path & cgroupFile)
{
std::map<std::string, std::string> cgroups;
for (auto & line : tokenizeString<std::vector<std::string>>(readFile(cgroupFile), "\n")) {
static std::regex regex("([0-9]+):([^:]*):(.*)");
std::smatch match;
if (!std::regex_match(line, match, regex))
throw Error("invalid line '%s' in '%s'", line, cgroupFile);
std::string name = hasPrefix(match[2], "name=") ? std::string(match[2], 5) : match[2];
cgroups.insert_or_assign(name, match[3]);
}
return cgroups;
}
void destroyCgroup(const Path & cgroup) void destroyCgroup(const Path & cgroup)
{ {
for (auto & entry : readDirectory(cgroup)) { for (auto & entry : readDirectory(cgroup)) {

View file

@ -6,6 +6,8 @@
namespace nix { namespace nix {
std::map<std::string, std::string> getCgroups(const Path & cgroupFile);
void destroyCgroup(const Path & cgroup); void destroyCgroup(const Path & cgroup);
} }