scx_utils/cgroup.rs
1// SPDX-License-Identifier: GPL-2.0
2//
3// Copyright (c) 2025 Meta Platforms, Inc. and affiliates.
4// Author: Changwoo Min <changwoo@igalia.com>
5//
6// This software may be used and distributed according to the terms of the
7// GNU General Public License version 2.
8
9//! Userspace helpers for the cgroup-related BPF libraries. Currently this
10//! covers `lib/cgroup_bw` (cpu.max); a scheduler that links it calls the
11//! helper below once between opening and loading its skeleton.
12
13use anyhow::anyhow;
14use anyhow::Result;
15use libbpf_rs::OpenObject;
16
17/// Per-cgroup context map defined in `lib/cgroup_bw.bpf.c`.
18const CBW_CGRP_MAP: &str = "cbw_cgrp_map";
19/// Per-(cgroup, LLC) context map defined in `lib/cgroup_bw.bpf.c`.
20const CBW_CGRP_LLC_MAP: &str = "cbw_cgrp_llc_map";
21
22/// Size the cpu.max per-(cgroup, LLC) context map to the running system.
23///
24/// `cbw_cgrp_llc_map` holds one entry per LLC for each tracked cgroup. Its
25/// BPF definition ships with a single-LLC default (`CBW_NR_CGRP_MAX`
26/// entries) because a BPF map's `max_entries` is fixed at load time while
27/// the LLC count is only known at runtime. Call this once after opening and
28/// before loading the skeleton to grow it to `<cgroup cap> * nr_llcs`.
29///
30/// The cgroup cap is read from the sibling `cbw_cgrp_map`, so the
31/// `CBW_NR_CGRP_MAX` constant stays defined only in the BPF source.
32pub fn resize_cgroup_bw_llc_map(open_obj: &mut OpenObject, nr_llcs: usize) -> Result<()> {
33 let cgrp_max = open_obj
34 .maps_mut()
35 .find(|m| m.name().to_str() == Some(CBW_CGRP_MAP))
36 .map(|m| m.max_entries())
37 .ok_or_else(|| anyhow!("cgroup_bw: map `{CBW_CGRP_MAP}` not found"))?;
38
39 let max_entries = cgrp_max
40 .checked_mul(nr_llcs as u32)
41 .ok_or_else(|| anyhow!("cgroup_bw: `{CBW_CGRP_LLC_MAP}` size overflow"))?;
42
43 open_obj
44 .maps_mut()
45 .find(|m| m.name().to_str() == Some(CBW_CGRP_LLC_MAP))
46 .ok_or_else(|| anyhow!("cgroup_bw: map `{CBW_CGRP_LLC_MAP}` not found"))?
47 .set_max_entries(max_entries)?;
48
49 Ok(())
50}