From c3af8c1f8b0da050a7c4c8fb5083ff44885fa959 Mon Sep 17 00:00:00 2001 From: Brian Chen Date: Mon, 23 Aug 2021 11:45:01 -0700 Subject: [PATCH] Fix procfs when reading cgroup membership (#8106) Summary: When reading cgroup membership, we currently assume that the cgroup v2 line will be first in /proc/[pid]/cgroup. This is not necessarily the case. Instead let's take the first line that starts with "0::". Tested on ubuntu where ``` $ cat /proc/1/cgroup 12:blkio:/init.scope 11:pids:/init.scope 8:memory:/init.scope 7:freezer:/ 4:devices:/init.scope 2:cpu,cpuacct:/init.scope 1:name=systemd:/init.scope 0::/init.scope ``` This should fix https://github.com/facebookincubator/below/issues/8105. Pull Request resolved: https://github.com/facebookincubator/below/pull/8106 Test Plan: Existing procfs tests should pass Reviewed By: lnyng Differential Revision: D30476031 Pulled By: brianc118 fbshipit-source-id: e0352fb039bebf44a0d5584120ea0a0a82c0cd01 --- below/procfs/src/lib.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) --- a/below/procfs/src/lib.rs +++ b/below/procfs/src/lib.rs @@ -556,24 +556,27 @@ impl ProcReader { let path = path.as_ref().join("cgroup"); let file = File::open(&path).map_err(|e| Error::IoError(path.clone(), e))?; let buf_reader = BufReader::new(file); - let pid_line = buf_reader.lines().next().map_or_else( - || Err(Error::InvalidFileFormat(path.clone())), - |line| line.map_err(|e| Error::IoError(path.clone(), e)), - )?; - - // cgroup V2 - if pid_line.len() > 3 && pid_line.starts_with("0::") { - return Ok(pid_line[3..].to_string()); - } - // legacy cgroup will have multiple lines with the first line of [0-9]+:pids:PATH - if let Some(pid_idx) = pid_line.find(":pids:") { - if pid_idx + 6 < pid_line.len() { - return Ok(pid_line[pid_idx + 6..].to_string()); + let mut cgroup_path = None; + for line in buf_reader.lines() { + let line = line.map_err(|e| Error::IoError(path.clone(), e))?; + // Lines contain three colon separated fields: + // hierarchy-ID:controller-list:cgroup-path + // A line starting with "0::" would be an entry for cgroup v2. + // Otherwise, the line containing "pids" controller is what we want + // for cgroup v1. + let parts: Vec<_> = line.split(':').collect(); + if parts.len() == 3 { + if parts[0] == "0" && parts[1] == "" { + cgroup_path = Some(parts[2].to_owned()); + // cgroup v2 takes precedence + break; + } else if parts[1].split(',').any(|c| c == "pids") { + cgroup_path = Some(parts[2].to_owned()); + } } } - - Err(Error::InvalidFileFormat(path)) + cgroup_path.ok_or_else(|| Error::InvalidFileFormat(path)) } pub fn read_pid_cgroup(&self, pid: u32) -> Result {