Merge pull request #13272 from cayoub-oai/codex/upstream-cgroupfs-init-subcgroup

agent: Apply init subcgroup in cgroupfs manager
This commit is contained in:
Fabiano Fidêncio
2026-06-25 13:54:19 +02:00
committed by GitHub

View File

@@ -43,6 +43,8 @@ use std::sync::{Arc, RwLock};
use super::DevicesCgroupInfo;
const GUEST_CPUS_PATH: &str = "/sys/devices/system/cpu/online";
const ROOT_SUBCGROUP: &str = "/";
const INIT_SUBCGROUP: &str = "/init/";
// Convenience function to obtain the scope logger.
fn sl() -> slog::Logger {
@@ -83,7 +85,17 @@ macro_rules! set_resource {
impl CgroupManager for Manager {
fn apply(&self, pid: pid_t) -> Result<()> {
self.cgroup.add_task_by_tgid(CgroupPid::from(pid as u64))?;
let cgroup_pid = CgroupPid::from(pid as u64);
if cgroup_has_init_subcgroup(&self.cpath) {
let cpath = self.cgroup_path_with_subcgroup(INIT_SUBCGROUP);
load_cgroup(cgroups::hierarchies::auto(), &cpath)
.add_task_by_tgid(cgroup_pid)
.with_context(|| format!("add task {} to cgroup {}", pid, cpath))?;
} else {
self.cgroup
.add_task_by_tgid(cgroup_pid)
.with_context(|| format!("add task {} to cgroup {}", pid, self.cpath))?;
}
Ok(())
}
@@ -1011,6 +1023,17 @@ pub fn get_paths() -> Result<HashMap<String, String>> {
Ok(m)
}
fn cgroup_path_under_root(root: impl AsRef<Path>, cpath: &str) -> PathBuf {
root.as_ref().join(cpath.trim_start_matches('/'))
}
fn cgroup_has_init_subcgroup(cpath: &str) -> bool {
cgroups::hierarchies::is_cgroup2_unified_mode()
&& cgroup_path_under_root(cgroups::hierarchies::auto().root(), cpath)
.join("init")
.exists()
}
pub fn get_mounts(paths: &HashMap<String, String>) -> Result<HashMap<String, String>> {
let mut m = HashMap::new();
@@ -1168,19 +1191,23 @@ impl Manager {
}
pub fn subcgroup(&self) -> &str {
// Check if we're in a Docker-in-Docker setup by verifying:
// Check if we're running with cgroup v2 delegation by verifying:
// 1. We're using cgroups v2 (which restricts direct process control)
// 2. An "init" subdirectory exists (used by DinD for process delegation)
let is_dind = cgroups::hierarchies::is_cgroup2_unified_mode()
&& cgroups::hierarchies::auto()
.root()
.join(&self.cpath)
.join("init")
.exists();
if is_dind {
"/init/"
// 2. An "init" subdirectory exists for delegated process attachment
// (for example, Docker-in-Docker or systemd in a container)
if cgroup_has_init_subcgroup(&self.cpath) {
INIT_SUBCGROUP
} else {
"/"
ROOT_SUBCGROUP
}
}
fn cgroup_path_with_subcgroup(&self, subcgroup: &str) -> String {
let subcgroup = subcgroup.trim_matches('/');
if subcgroup.is_empty() {
self.cpath.clone()
} else {
Path::new(&self.cpath).join(subcgroup).display().to_string()
}
}
@@ -1386,6 +1413,7 @@ fn convert_memory_swap_to_v2_value(memory_swap: i64, memory: i64) -> Result<i64>
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use std::path::PathBuf;
use std::process::Command;
use std::sync::{Arc, RwLock};
use std::time::{SystemTime, UNIX_EPOCH};
@@ -1398,13 +1426,45 @@ mod tests {
use oci_spec::runtime as oci;
use test_utils::skip_if_not_root;
use super::default_allowed_devices;
use super::{cgroup_path_under_root, default_allowed_devices, load_cgroup};
use crate::cgroups::fs::{
line_to_vec, lines_to_map, Manager, DEFAULT_ALLOWED_DEVICES, WILDCARD,
};
use crate::cgroups::DevicesCgroupInfo;
use crate::container::DEFAULT_DEVICES;
#[test]
fn test_cgroup_path_under_root_trims_absolute_cpath() {
assert_eq!(
cgroup_path_under_root(
"/sys/fs/cgroup",
"/docker.slice/docker-containers.slice/container"
),
PathBuf::from("/sys/fs/cgroup/docker.slice/docker-containers.slice/container")
);
}
#[test]
fn test_cgroup_path_with_subcgroup_preserves_absolute_cpath() {
let manager = Manager {
paths: HashMap::new(),
mounts: HashMap::new(),
cpath: "/docker.slice/docker-containers.slice/container".to_string(),
cgroup: load_cgroup(cgroups::hierarchies::auto(), "/"),
pod_cgroup: None,
devcg_allowed_all: false,
};
assert_eq!(
manager.cgroup_path_with_subcgroup("/init/"),
"/docker.slice/docker-containers.slice/container/init"
);
assert_eq!(
manager.cgroup_path_with_subcgroup("/"),
"/docker.slice/docker-containers.slice/container"
);
}
#[test]
fn test_line_to_vec() {
let test_cases = vec![