Skip to main content

libcgroups/v2/
util.rs

1use std::io::{BufRead, BufReader};
2use std::path::{Path, PathBuf};
3
4use pathrs::flags::OpenFlags;
5use pathrs::procfs::{ProcfsBase, ProcfsHandle};
6use procfs::ProcError;
7use procfs::process::MountInfo;
8
9use super::controller_type::ControllerType;
10use crate::common::{self, WrappedIoError};
11
12pub const CGROUP_CONTROLLERS: &str = "cgroup.controllers";
13pub const CGROUP_SUBTREE_CONTROL: &str = "cgroup.subtree_control";
14
15#[derive(thiserror::Error, Debug)]
16pub enum V2UtilError {
17    #[error("io error: {0}")]
18    Io(#[from] std::io::Error),
19    #[error("io error: {0}")]
20    WrappedIo(#[from] WrappedIoError),
21    #[error("proc error: {0}")]
22    Proc(#[from] ProcError),
23    #[error("could not find mountpoint for unified")]
24    CouldNotFind,
25    #[error("cannot get available controllers. {0} does not exist")]
26    DoesNotExist(PathBuf),
27    #[error(transparent)]
28    Pathrs(#[from] pathrs::error::Error),
29}
30
31// Reads the `/proc/self/mountinfo` to get the mount point of this cgroup
32pub fn get_unified_mount_point() -> Result<PathBuf, V2UtilError> {
33    let reader = BufReader::new(ProcfsHandle::new()?.open(
34        ProcfsBase::ProcSelf,
35        "mountinfo",
36        OpenFlags::O_RDONLY | OpenFlags::O_CLOEXEC,
37    )?);
38
39    reader
40        .lines()
41        .map(|lr| {
42            lr.map_err(V2UtilError::Io)
43                .and_then(|s| MountInfo::from_line(&s).map_err(V2UtilError::from))
44        })
45        .find_map(|r| match r {
46            Ok(mi) if mi.fs_type == "cgroup2" => Some(Ok(mi.mount_point)),
47            Ok(_) => None,
48            Err(e) => Some(Err(e)),
49        })
50        .transpose()?
51        .ok_or(V2UtilError::CouldNotFind)
52}
53
54/// Reads the `{root_path}/cgroup.controllers` file to get the list of the controllers that are
55/// available in this cgroup
56pub fn get_available_controllers<P: AsRef<Path>>(
57    root_path: P,
58) -> Result<Vec<ControllerType>, V2UtilError> {
59    let root_path = root_path.as_ref();
60    let controllers_path = root_path.join(CGROUP_CONTROLLERS);
61    if !controllers_path.exists() {
62        return Err(V2UtilError::DoesNotExist(controllers_path));
63    }
64
65    let mut controllers = Vec::new();
66    for controller in common::read_cgroup_file(controllers_path)?.split_whitespace() {
67        match controller {
68            "cpu" => controllers.push(ControllerType::Cpu),
69            "cpuset" => controllers.push(ControllerType::CpuSet),
70            "hugetlb" => controllers.push(ControllerType::HugeTlb),
71            "io" => controllers.push(ControllerType::Io),
72            "memory" => controllers.push(ControllerType::Memory),
73            "pids" => controllers.push(ControllerType::Pids),
74            tpe => tracing::warn!("Controller {} is not yet implemented.", tpe),
75        }
76    }
77
78    Ok(controllers)
79}