containers/youki

libcgroups v2 manager stats failed when no hugetlb releated files

Sherlock-Holo opened this issue · 3 comments

if a cgroup doesn't contain hugetlb releated files, the v2 manager will fail with

Caused by:
0: io error: failed to read /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/prctl-ttt/hugetlb.2MB.events: No such file or directory (os error 2)
1: failed to read /sys/fs/cgroup/user.slice/user-1000.slice/user@1000.service/prctl-ttt/hugetlb.2MB.events: No such file or directory (os error 2)

Hey, thanks for reporting this. Can you also add your system information / setup and how you were running this, so we can try to reproduce?

I am using archlinux

uname -a

Linux sherlock 6.5.9-arch2-1 #1 SMP PREEMPT_DYNAMIC Thu, 26 Oct 2023 00:52:20 +0000 x86_64 GNU/Linux

pub fn show_cgroup_info<M>(manager: &M, name: &str) -> anyhow::Result<CgroupInfo>
where
    M: CgroupManager,
    M::Error: Error + Send + Sync + 'static,
{
    let stats = manager
        .stats()
        .with_context(|| format!("get cgroup {name} info failed"))?;
    let memory = (stats.memory.memory.limit != u64::MAX)
        .then(|| Byte::from_bytes(stats.memory.memory.limit as _));

    Ok(CgroupInfo {
        cpu: CpuInfo {
            cpu: MaxOrInt::Int(0),
        },
        memory: MemoryInfo { limit: memory },
    })
}

and when I call this function, I use the v2 manager implement

The stats method of libcgroups::v2::Manager assumes that all types of controller listed in CONTROLLER_TYPES are enabled in the cgroup it manages. Therefore, it will attempt to read the hugetlb.2MB.events file even if the hugetlb controller is not enabled.

fn stats(&self) -> Result<Stats, Self::Error> {
let mut stats = Stats::default();
for subsystem in CONTROLLER_TYPES {
match subsystem {
ControllerType::Cpu => stats.cpu = Cpu::stats(&self.full_path)?,
ControllerType::HugeTlb => stats.hugetlb = HugeTlb::stats(&self.full_path)?,
ControllerType::Pids => {
stats.pids = Pids::stats(&self.full_path).map_err(V2ManagerError::PidsStats)?
}
ControllerType::Memory => stats.memory = Memory::stats(&self.full_path)?,
ControllerType::Io => stats.blkio = Io::stats(&self.full_path)?,
_ => continue,
}
}
Ok(stats)
}

I think a potential solution is to implement a method similar to util::get_available_controllers, which reads the enabled controllers of the current cgroup, and then generate stats for these enabled controllers. (I'm willing to submit a pull request if this issue needs to be addressed.)