diff --git a/rust/scx_utils/src/compat.rs b/rust/scx_utils/src/compat.rs index 8627579..2ca2a8f 100644 --- a/rust/scx_utils/src/compat.rs +++ b/rust/scx_utils/src/compat.rs @@ -151,9 +151,47 @@ pub fn is_sched_ext_enabled() -> io::Result { } } -/// struct sched_ext_ops can change over time. If -/// compat.bpf.h::SCX_OPS_DEFINE() is used to define ops and scx_ops_load!() -/// and scx_ops_attach!() are used to load and attach it, backward +/// struct sched_ext_ops can change over time. If compat.bpf.h::SCX_OPS_DEFINE() +/// is used to define ops, and scx_ops_open!(), scx_ops_load!(), and +/// scx_ops_attach!() are used to open, load and attach it, backward +/// compatibility is automatically maintained where reasonable. +/// +/// - sched_ext_ops.hotplug_seq was added later. On kernels which support it, +/// set the value to a nonzero value to trigger an exit in the scheduler when +/// a hotplug event occurs between opening and attaching the scheduler. +#[macro_export] +macro_rules! scx_ops_open { + ($builder: expr, $ops: ident) => {{ + scx_utils::paste! { + let mut skel = $builder.open().context("Failed to open BPF program")?; + let ops = skel.struct_ops.[<$ops _mut>](); + let has_field = scx_utils::compat::struct_has_field("sched_ext_ops", "hotplug_seq")?; + if has_field { + let path = std::path::Path::new("/sys/kernel/sched_ext/hotplug_seq"); + let val = match std::fs::read_to_string(&path) { + Ok(val) => val, + Err(_) => { + return Err(anyhow::anyhow!("Failed to open or read file {:?}", path)); + } + }; + + ops.hotplug_seq = match val.trim().parse::() { + Ok(parsed) => parsed, + Err(_) => { + return Err(anyhow::anyhow!("Failed to parse hotplug seq {}", val)); + } + }; + } + + let result : Result, anyhow::Error> = Ok(skel); + result + } + }}; +} + +/// struct sched_ext_ops can change over time. If compat.bpf.h::SCX_OPS_DEFINE() +/// is used to define ops, and scx_ops_open!(), scx_ops_load!(), and +/// scx_ops_attach!() are used to open, load and attach it, backward /// compatibility is automatically maintained where reasonable. /// /// - sched_ext_ops.exit_dump_len was added later. On kernels which don't diff --git a/rust/scx_utils/src/lib.rs b/rust/scx_utils/src/lib.rs index 239483b..cce0ffa 100644 --- a/rust/scx_utils/src/lib.rs +++ b/rust/scx_utils/src/lib.rs @@ -44,6 +44,8 @@ pub use builder::Builder; mod user_exit_info; pub use user_exit_info::ScxExitKind; pub use user_exit_info::ScxConsts; +pub use user_exit_info::SCX_ECODE_RSN_HOTPLUG; +pub use user_exit_info::SCX_ECODE_ACT_RESTART; pub use user_exit_info::UeiDumpPtr; pub use user_exit_info::UserExitInfo; pub use user_exit_info::UEI_DUMP_PTR_MUTEX; diff --git a/rust/scx_utils/src/user_exit_info.rs b/rust/scx_utils/src/user_exit_info.rs index ee36e98..740d7bb 100644 --- a/rust/scx_utils/src/user_exit_info.rs +++ b/rust/scx_utils/src/user_exit_info.rs @@ -3,6 +3,7 @@ // This software may be used and distributed according to the terms of the // GNU General Public License version 2. use crate::bindings; +use crate::compat; use anyhow::bail; use anyhow::Result; use std::ffi::CStr; @@ -18,11 +19,22 @@ pub static UEI_DUMP_PTR_MUTEX: Mutex = Mutex::new(UeiDumpPtr { ptr: std::ptr::null(), }); +lazy_static::lazy_static! { + pub static ref SCX_ECODE_RSN_HOTPLUG: u64 = + compat::read_enum("scx_exit_code", "SCX_ECODE_RSN_HOTPLUG").unwrap_or(0); +} + +lazy_static::lazy_static! { + pub static ref SCX_ECODE_ACT_RESTART: u64 = + compat::read_enum("scx_exit_code", "SCX_ECODE_ACT_RESTART").unwrap_or(0); +} + pub enum ScxExitKind { None = bindings::scx_exit_kind_SCX_EXIT_NONE as isize, Done = bindings::scx_exit_kind_SCX_EXIT_DONE as isize, Unreg = bindings::scx_exit_kind_SCX_EXIT_UNREG as isize, UnregBPF = bindings::scx_exit_kind_SCX_EXIT_UNREG_BPF as isize, + UnregKern = bindings::scx_exit_kind_SCX_EXIT_UNREG_KERN as isize, SysRq = bindings::scx_exit_kind_SCX_EXIT_SYSRQ as isize, Error = bindings::scx_exit_kind_SCX_EXIT_ERROR as isize, ErrorBPF = bindings::scx_exit_kind_SCX_EXIT_ERROR_BPF as isize, @@ -194,7 +206,7 @@ impl UserExitInfo { _ => "".into(), }; - if self.kind <= ScxExitKind::UnregBPF as i32 { + if self.kind <= ScxExitKind::UnregKern as i32 { eprintln!("{}", why); Ok(()) } else { @@ -206,7 +218,7 @@ impl UserExitInfo { /// only applies when the BPF scheduler exits with scx_bpf_exit(), i.e. kind /// ScxExitKind::UnregBPF. pub fn exit_code(&self) -> Option { - if self.kind == ScxExitKind::UnregBPF as i32 { + if self.kind == ScxExitKind::UnregBPF as i32 || self.kind == ScxExitKind::UnregKern as i32 { Some(self.exit_code) } else { None diff --git a/scheds/rust/scx_rusty/src/bpf/intf.h b/scheds/rust/scx_rusty/src/bpf/intf.h index 01bb052..5f5ae23 100644 --- a/scheds/rust/scx_rusty/src/bpf/intf.h +++ b/scheds/rust/scx_rusty/src/bpf/intf.h @@ -61,10 +61,6 @@ enum consts { MAX_DOM_ACTIVE_PIDS = 1024, }; -enum rusty_exit_codes { - RUSTY_EXIT_HOTPLUG, -}; - /* Statistics */ enum stat_idx { /* The following fields add up to all dispatched tasks */ diff --git a/scheds/rust/scx_rusty/src/bpf/main.bpf.c b/scheds/rust/scx_rusty/src/bpf/main.bpf.c index 1a72e88..27c1a91 100644 --- a/scheds/rust/scx_rusty/src/bpf/main.bpf.c +++ b/scheds/rust/scx_rusty/src/bpf/main.bpf.c @@ -1743,16 +1743,6 @@ static s32 initialize_cpu(s32 cpu) return 0; } -void BPF_STRUCT_OPS(rusty_cpu_online, s32 cpu) -{ - __COMPAT_scx_bpf_exit(RUSTY_EXIT_HOTPLUG, "CPU %d went online", cpu); -} - -void BPF_STRUCT_OPS(rusty_cpu_offline, s32 cpu) -{ - __COMPAT_scx_bpf_exit(RUSTY_EXIT_HOTPLUG, "CPU %d went offline", cpu); -} - s32 BPF_STRUCT_OPS_SLEEPABLE(rusty_init) { s32 i, ret; @@ -1812,8 +1802,6 @@ SCX_OPS_DEFINE(rusty, .set_cpumask = (void *)rusty_set_cpumask, .init_task = (void *)rusty_init_task, .exit_task = (void *)rusty_exit_task, - .cpu_online = (void *)rusty_cpu_online, - .cpu_offline = (void *)rusty_cpu_offline, .init = (void *)rusty_init, .exit = (void *)rusty_exit, .timeout_ms = 10000, diff --git a/scheds/rust/scx_rusty/src/main.rs b/scheds/rust/scx_rusty/src/main.rs index 6ef17b2..7a88dc4 100644 --- a/scheds/rust/scx_rusty/src/main.rs +++ b/scheds/rust/scx_rusty/src/main.rs @@ -38,8 +38,10 @@ use scx_utils::compat; use scx_utils::init_libbpf_logging; use scx_utils::scx_ops_attach; use scx_utils::scx_ops_load; +use scx_utils::scx_ops_open; use scx_utils::uei_exited; use scx_utils::uei_read; +use scx_utils::SCX_ECODE_ACT_RESTART; use scx_utils::Cpumask; use scx_utils::Topology; use scx_utils::UserExitInfo; @@ -234,7 +236,7 @@ impl<'a> Scheduler<'a> { let mut skel_builder = BpfSkelBuilder::default(); skel_builder.obj_builder.debug(opts.verbose > 0); init_libbpf_logging(None); - let mut skel = skel_builder.open().context("Failed to open BPF program")?; + let mut skel = scx_ops_open!(skel_builder, rusty).unwrap(); // Initialize skel according to @opts. let top = Arc::new(Topology::new()?); @@ -620,7 +622,7 @@ fn main() -> Result<()> { let uei = sched.run(shutdown.clone())?; if let Some(exit_code) = uei.exit_code() { - if exit_code == bpf_intf::rusty_exit_codes_RUSTY_EXIT_HOTPLUG as i64 { + if (exit_code & *SCX_ECODE_ACT_RESTART as i64) != 0 { continue; } }