mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
The cgroup v2 fs is initialized early in the boot process, so that every task
in the sandbox resides in at least the root v2 cgroup. A new runsc flag
--mount-cgroup-v2 has been added: this controls whether runsc mounts a
cgroupv2 filesystem at /sys/fs/cgroup automatically (currently it always
mounts a v1 hierarchy at this path). This flag also gates whether userspace
can mount a cgroup2 fs. When this flag is false, which is the default, all
tasks in the sandbox reside forever in the root cgroup.
Like in Linux, the v2 hierarchy is deemed the default owner of a controller,
that is, until the corresponding v1 hierarchy is mounted: then, the v1 tree
steals ownership of that controller and it remains this way till as long as
a v1 mount exists. In other words, hybrid mode is supported, even if such
workloads are rare these days.
The pids controller is the only controller implemented in full: it serves
as validation for the unified hierarchy. The memory controller can be used
to learn the usage stats of a subtree: but like the current v1 implementation,
and unlike Linux, it doesn't achieve this through charging up the hierarchy
during allocation, instead it queries pgalloc for every active controller's
id. And it does no enforcing. The cpu and cpuset controllers are mere stubs,
like in the current v1 implementation.
The following are supported:
* General matters of topology: cgroup.subtree_control, cgroup.controllers,
cgroup.procs etc
* CLONE_INTO_CGROUP
* cgroup.kill
* cgroup.events
* A working pids controller and its events files
* A minimal memory controller that just reports mem usage
* Stubbed cpu and cpuset controllers
The following are NOT supported:
* threaded cgroups
* cgroup namespaces
* BPF_PROG_TYPE_CGROUP_DEVICE
* cgroup.freeze
Updates #13007
PiperOrigin-RevId: 943519748
168 lines
5.3 KiB
C++
168 lines
5.3 KiB
C++
// Copyright 2021 The gVisor Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef GVISOR_TEST_UTIL_CGROUP_UTIL_H_
|
|
#define GVISOR_TEST_UTIL_CGROUP_UTIL_H_
|
|
|
|
#include <unistd.h>
|
|
|
|
#include "absl/container/flat_hash_map.h"
|
|
#include "absl/container/flat_hash_set.h"
|
|
#include "absl/strings/string_view.h"
|
|
#include "test/util/cleanup.h"
|
|
#include "test/util/fs_util.h"
|
|
#include "test/util/temp_path.h"
|
|
|
|
namespace gvisor {
|
|
namespace testing {
|
|
|
|
// Cgroup represents a cgroup directory on a mounted cgroupfs.
|
|
class Cgroup {
|
|
public:
|
|
static Cgroup RootCgroup(absl::string_view path) {
|
|
return Cgroup(path, path);
|
|
}
|
|
|
|
uint64_t id() const { return id_; }
|
|
|
|
// Deletes the current cgroup represented by this object.
|
|
PosixError Delete();
|
|
|
|
const std::string& Path() const { return cgroup_path_; }
|
|
|
|
// Returns the canonical path for this cgroup, which is the absolute path
|
|
// starting at the hierarchy root.
|
|
const std::string CanonicalPath() const {
|
|
std::string relpath =
|
|
GetRelativePath(mountpoint_, cgroup_path_).ValueOrDie();
|
|
if (relpath == ".") {
|
|
return "/";
|
|
}
|
|
return "/" + relpath;
|
|
}
|
|
|
|
// Creates a child cgroup under this cgroup with the given name.
|
|
PosixErrorOr<Cgroup> CreateChild(absl::string_view name) const;
|
|
|
|
std::string Relpath(absl::string_view leaf) const {
|
|
return JoinPath(cgroup_path_, leaf);
|
|
}
|
|
|
|
// Returns the contents of a cgroup control file with the given name.
|
|
PosixErrorOr<std::string> ReadControlFile(absl::string_view name) const;
|
|
|
|
// Reads the contents of a cgroup control with the given name, and attempts
|
|
// to parse it as an integer.
|
|
PosixErrorOr<int64_t> ReadIntegerControlFile(absl::string_view name) const;
|
|
|
|
// Writes a string to a cgroup control file.
|
|
PosixError WriteControlFile(absl::string_view name,
|
|
const std::string& value) const;
|
|
|
|
// Writes an integer value to a cgroup control file.
|
|
PosixError WriteIntegerControlFile(absl::string_view name,
|
|
int64_t value) const;
|
|
|
|
// Waits for a control file's value to change.
|
|
PosixError PollControlFileForChange(absl::string_view name,
|
|
absl::Duration timeout) const;
|
|
|
|
// Waits for a control file's value to change after calling body.
|
|
PosixError PollControlFileForChangeAfter(absl::string_view name,
|
|
absl::Duration timeout,
|
|
std::function<void()> body) const;
|
|
|
|
// Returns the thread ids of the leaders of thread groups managed by this
|
|
// cgroup.
|
|
PosixErrorOr<absl::flat_hash_set<pid_t>> Procs() const;
|
|
|
|
PosixErrorOr<absl::flat_hash_set<pid_t>> Tasks() const;
|
|
|
|
// ContainsCallingProcess checks whether the calling process is part of the
|
|
// cgroup.
|
|
PosixError ContainsCallingProcess() const;
|
|
|
|
// ContainsCallingThread checks whether the calling thread is part of the
|
|
// cgroup.
|
|
PosixError ContainsCallingThread() const;
|
|
|
|
// Moves process with the specified pid to this cgroup.
|
|
PosixError Enter(pid_t pid) const;
|
|
|
|
// Moves thread with the specified pid to this cgroup.
|
|
PosixError EnterThread(pid_t pid) const;
|
|
|
|
private:
|
|
Cgroup(absl::string_view path, absl::string_view mountpoint);
|
|
|
|
PosixErrorOr<absl::flat_hash_set<pid_t>> ParsePIDList(
|
|
absl::string_view data) const;
|
|
|
|
static int64_t next_id_;
|
|
int64_t id_;
|
|
const std::string cgroup_path_;
|
|
const std::string mountpoint_;
|
|
};
|
|
|
|
// Mounter is a utility for creating cgroupfs mounts. It automatically manages
|
|
// the lifetime of created mounts.
|
|
class Mounter {
|
|
public:
|
|
Mounter(TempPath root) : root_(std::move(root)) {}
|
|
|
|
PosixErrorOr<Cgroup> MountCgroupfs(std::string mopts);
|
|
|
|
PosixErrorOr<Cgroup> MountCgroup2fs(std::string mopts = "");
|
|
|
|
PosixError Unmount(const Cgroup& c);
|
|
|
|
void release(const Cgroup& c);
|
|
|
|
private:
|
|
// The destruction order of these members avoids errors during cleanup. We
|
|
// first unmount (by executing the mounts_ cleanups), then delete the
|
|
// mountpoint subdirs, then delete the root.
|
|
TempPath root_;
|
|
absl::flat_hash_map<int64_t, TempPath> mountpoints_;
|
|
absl::flat_hash_map<int64_t, Cleanup> mounts_;
|
|
};
|
|
|
|
// Represents a line from /proc/cgroups.
|
|
struct CgroupsEntry {
|
|
std::string subsys_name;
|
|
uint32_t hierarchy;
|
|
uint64_t num_cgroups;
|
|
bool enabled;
|
|
};
|
|
|
|
// Returns a parsed representation of /proc/cgroups.
|
|
PosixErrorOr<absl::flat_hash_map<std::string, CgroupsEntry>>
|
|
ProcCgroupsEntries();
|
|
|
|
// Represents a line from /proc/<pid>/cgroup.
|
|
struct PIDCgroupEntry {
|
|
uint32_t hierarchy;
|
|
std::string controllers;
|
|
std::string path;
|
|
};
|
|
|
|
// Returns a parsed representation of /proc/<pid>/cgroup.
|
|
PosixErrorOr<absl::flat_hash_map<std::string, PIDCgroupEntry>>
|
|
ProcPIDCgroupEntries(pid_t pid);
|
|
|
|
} // namespace testing
|
|
} // namespace gvisor
|
|
|
|
#endif // GVISOR_TEST_UTIL_CGROUP_UTIL_H_
|