use anyhow::Result;
use ktstr::assert::{AssertDetail, AssertResult, DetailKind};
use ktstr::ktstr_test;
use ktstr::scenario::Ctx;
use ktstr::test_support::{Payload, Scheduler, SchedulerSpec};
use std::fs;
const MULTI_LEVEL_SCHED: Scheduler = Scheduler::new("ktstr_sched")
.binary(SchedulerSpec::Discover("scx-ktstr"))
.cgroup_parent("/ktstr-multi-l1/l2/l3");
const MULTI_LEVEL_SCHED_PAYLOAD: Payload = Payload::from_scheduler(&MULTI_LEVEL_SCHED);
#[ktstr_test(
scheduler = MULTI_LEVEL_SCHED_PAYLOAD,
llcs = 1,
cores = 1,
threads = 1,
memory_mb = 256,
)]
fn cgroup_parent_three_levels_writes_subtree_control_at_every_ancestor(
_ctx: &Ctx,
) -> Result<AssertResult> {
let intermediate_levels: &[&str] = &[
"/sys/fs/cgroup",
"/sys/fs/cgroup/ktstr-multi-l1",
"/sys/fs/cgroup/ktstr-multi-l1/l2",
];
for level in intermediate_levels {
let control_path = format!("{level}/cgroup.subtree_control");
let contents = match fs::read_to_string(&control_path) {
Ok(s) => s,
Err(e) => {
return Ok(AssertResult::fail(AssertDetail::new(
DetailKind::Other,
format!(
"read {control_path}: {e}. \
enable_subtree_controllers_to should have \
created the cgroup directory and populated \
its subtree_control before the test body \
dispatched."
),
)));
}
};
let tokens: std::collections::HashSet<&str> = contents.split_whitespace().collect();
if !tokens.contains("cpuset") || !tokens.contains("cpu") {
return Ok(AssertResult::fail(AssertDetail::new(
DetailKind::Other,
format!(
"{control_path} = {contents:?}: missing one of \
cpuset/cpu. enable_subtree_controllers_to writes \
`+cpuset +cpu` to every ancestor's \
cgroup.subtree_control; an absent controller \
here means the ancestor walk skipped this \
level."
),
)));
}
}
let leaf = "/sys/fs/cgroup/ktstr-multi-l1/l2/l3";
if !std::path::Path::new(leaf).is_dir() {
return Ok(AssertResult::fail(AssertDetail::new(
DetailKind::Other,
format!(
"leaf cgroup {leaf} does not exist. \
create_cgroup_parent_from_sched_args should have \
parsed `--cell-parent-cgroup /ktstr-multi-l1/l2/l3` \
from /sched_args and called mkdir_p before the \
scheduler started."
),
)));
}
Ok(AssertResult::pass())
}