use super::*;
pub(crate) fn mount_filesystems() {
let mounts: &[(&str, &str, &str, bool)] = &[
("/proc", "proc", "proc", true),
("/sys", "sys", "sysfs", true),
("/dev", "dev", "devtmpfs", true),
("/sys/kernel/debug", "debugfs", "debugfs", false),
("/sys/kernel/tracing", "tracefs", "tracefs", false),
("/sys/fs/bpf", "bpffs", "bpf", false),
("/sys/fs/cgroup", "none", "cgroup2", false),
("/tmp", "tmpfs", "tmpfs", true),
("/dev/shm", "tmpfs", "tmpfs", false),
("/run", "tmpfs", "tmpfs", false),
];
for &(target, source, fstype, required) in mounts {
mkdir_p(target);
let result = mount(
Some(source),
target,
Some(fstype),
MsFlags::empty(),
None::<&str>,
);
if let Err(e) = result
&& required
{
tracing::error!(fstype, target, err = %e, "ktstr-init: mount failed");
}
}
let _ = std::os::unix::fs::symlink("/proc/self/fd", "/dev/fd");
let _ = std::os::unix::fs::symlink("/proc/self/fd/0", "/dev/stdin");
let _ = std::os::unix::fs::symlink("/proc/self/fd/1", "/dev/stdout");
let _ = std::os::unix::fs::symlink("/proc/self/fd/2", "/dev/stderr");
}
pub(crate) fn auto_mount_data_disks() {
let Some(fstype) = cmdline_val("KTSTR_DISK0_FS") else {
return;
};
let recognized = matches!(fstype.as_str(), "btrfs");
if !recognized {
let msg = format!(
"ktstr-init: KTSTR_DISK0_FS={fstype} not recognized; \
skipping auto-mount of /dev/vda"
);
let _ = fs::write(COM2, &msg);
tracing::warn!("{msg}");
return;
}
let ro = cmdline_val("KTSTR_DISK0_RO").as_deref() == Some("1");
let mount_point_owned =
cmdline_val("KTSTR_DISK0_MOUNT").unwrap_or_else(|| "/mnt/disk0".to_string());
let mount_point = mount_point_owned.as_str();
mkdir_p(mount_point);
let flags = if ro {
MsFlags::MS_RDONLY
} else {
MsFlags::empty()
};
let result = mount(
Some("/dev/vda"),
mount_point,
Some(fstype.as_str()),
flags,
None::<&str>,
);
if let Err(e) = result {
let msg = format!(
"ktstr-init: mount {fstype} on {mount_point} \
(ro={ro}): {e}"
);
let _ = fs::write(COM2, &msg);
tracing::warn!("{msg}");
}
}
pub(crate) fn mkdir_p(path: &str) {
use std::os::unix::fs::DirBuilderExt;
let _ = fs::DirBuilder::new()
.recursive(true)
.mode(0o755)
.create(path);
}
pub(crate) fn write_com2(msg: &str) {
if let Ok(mut f) = fs::OpenOptions::new().write(true).open(COM2) {
let _ = writeln!(f, "{msg}");
} else {
tracing::warn!(target: "com1_fallback", "ktstr-init: {msg}");
}
}
#[tracing::instrument]
pub(crate) fn create_workload_root_cgroup_from_file() {
create_cgroup_from_file("/workload_root_cgroup");
}
#[tracing::instrument]
pub(crate) fn create_scheduler_cgroup_parent_from_file() {
create_cgroup_from_file("/scheduler_cgroup_parent");
}
fn create_cgroup_from_file(file: &str) {
let raw = match fs::read_to_string(file) {
Ok(s) => s,
Err(_) => return,
};
let path = raw.trim();
if !crate::test_support::cell_parent_path_is_valid(path) {
if !path.is_empty() {
write_com2(&format!(
"ktstr-init: ignoring malformed `{file}` value {path:?}; \
skipping cgroup creation (host-side `CgroupPath::new` \
gate normally rejects this at compile time)",
));
}
return;
}
let cgroup_dir = format!("/sys/fs/cgroup{path}");
mkdir_p(&cgroup_dir);
enable_subtree_controllers_to(&cgroup_dir);
}
#[tracing::instrument]
pub(crate) fn create_cgroup_parent_from_sched_args() {
let sched_args = match fs::read_to_string("/sched_args") {
Ok(s) => s,
Err(_) => return,
};
let path = match crate::test_support::parse_cell_parent_cgroup(sched_args.split_whitespace()) {
crate::test_support::CellParentCgroupArg::Value(p)
if crate::test_support::cell_parent_path_is_valid(p) =>
{
p
}
crate::test_support::CellParentCgroupArg::Value(bad) => {
write_com2(&format!(
"ktstr-init: ignoring malformed `--cell-parent-cgroup` value \
{bad:?} in /sched_args; skipping per-test cgroup creation \
(host-side gate normally panics on this)",
));
return;
}
crate::test_support::CellParentCgroupArg::MissingValue => {
write_com2(
"ktstr-init: ignoring bare `--cell-parent-cgroup` (no value) \
in /sched_args; skipping per-test cgroup creation",
);
return;
}
crate::test_support::CellParentCgroupArg::Absent => return,
};
let cgroup_dir = format!("/sys/fs/cgroup{path}");
mkdir_p(&cgroup_dir);
enable_subtree_controllers_to(&cgroup_dir);
}
fn enable_subtree_controllers_to(leaf: &str) {
let cgroup_root = Path::new("/sys/fs/cgroup");
let leaf_path = Path::new(leaf);
if !leaf_path.starts_with(cgroup_root) || leaf_path == cgroup_root {
return;
}
let mut ancestors: Vec<&Path> = leaf_path
.ancestors()
.skip(1)
.take_while(|p| p.starts_with(cgroup_root))
.collect();
ancestors.reverse();
for level in ancestors {
let control = level.join("cgroup.subtree_control");
if let Err(e) = fs::write(&control, "+cpuset +cpu") {
write_com2(&format!(
"ktstr-init: write {} +cpuset +cpu: {}",
control.display(),
e
));
}
}
}