diff --git a/tests/contest/contest/src/main.rs b/tests/contest/contest/src/main.rs index b1b81281..bb1825d3 100644 --- a/tests/contest/contest/src/main.rs +++ b/tests/contest/contest/src/main.rs @@ -6,6 +6,7 @@ use crate::tests::example::get_example_test; use crate::tests::hooks::get_hooks_tests; use crate::tests::hostname::get_hostname_test; use crate::tests::intel_rdt::get_intel_rdt_test; +use crate::tests::io_priority::get_io_priority_test; use crate::tests::lifecycle::{ContainerCreate, ContainerLifecycle}; use crate::tests::linux_ns_itype::get_ns_itype_tests; use crate::tests::mounts_recursive::get_mounts_recursive_test; @@ -107,6 +108,7 @@ fn main() -> Result<()> { let intel_rdt = get_intel_rdt_test(); let sysctl = get_sysctl_test(); let scheduler = get_scheduler_test(); + let io_priority_test = get_io_priority_test(); tm.add_test_group(Box::new(cl)); tm.add_test_group(Box::new(cc)); @@ -130,6 +132,7 @@ fn main() -> Result<()> { tm.add_test_group(Box::new(sysctl)); tm.add_test_group(Box::new(scheduler)); + tm.add_test_group(Box::new(io_priority_test)); tm.add_cleanup(Box::new(cgroups::cleanup_v1)); tm.add_cleanup(Box::new(cgroups::cleanup_v2)); diff --git a/tests/contest/contest/src/tests/io_priority/io_priority_test.rs b/tests/contest/contest/src/tests/io_priority/io_priority_test.rs new file mode 100644 index 00000000..37b65454 --- /dev/null +++ b/tests/contest/contest/src/tests/io_priority/io_priority_test.rs @@ -0,0 +1,78 @@ +use crate::utils::test_inside_container; +use anyhow::{Context, Result}; +use oci_spec::runtime::{ + IOPriorityClass, LinuxIOPriorityBuilder, ProcessBuilder, Spec, SpecBuilder, +}; +use test_framework::{test_result, Test, TestGroup, TestResult}; + +fn create_spec( + io_priority_class: IOPriorityClass, + execute_test: &str, + priority: i64, +) -> Result { + let io_p = LinuxIOPriorityBuilder::default() + .class(io_priority_class) + .priority(priority) + .build() + .unwrap(); + SpecBuilder::default() + .process( + ProcessBuilder::default() + .args( + ["runtimetest", execute_test] + .iter() + .map(|s| s.to_string()) + .collect::>(), + ) + .io_priority(io_p) + .build()?, + ) + .build() + .context("failed to create spec") +} + +fn io_priority_class_rt_test() -> TestResult { + let spec = test_result!(create_spec( + IOPriorityClass::IoprioClassRt, + "io_priority_class_rt", + 1, + )); + test_inside_container(spec, &|_| Ok(())) +} + +fn io_priority_class_be_test() -> TestResult { + let spec = test_result!(create_spec( + IOPriorityClass::IoprioClassBe, + "io_priority_class_be", + 2, + )); + test_inside_container(spec, &|_| Ok(())) +} + +fn io_priority_class_idle_test() -> TestResult { + let spec = test_result!(create_spec( + IOPriorityClass::IoprioClassIdle, + "io_priority_class_idle", + 3, + )); + test_inside_container(spec, &|_| Ok(())) +} + +pub fn get_io_priority_test() -> TestGroup { + let mut io_priority_group = TestGroup::new("set_io_priority"); + let io_priority_class_rt = + Test::new("io_priority_class_rt", Box::new(io_priority_class_rt_test)); + let io_priority_class_be = + Test::new("io_priority_class_be", Box::new(io_priority_class_be_test)); + let io_priority_class_idle = Test::new( + "io_priority_class_idle", + Box::new(io_priority_class_idle_test), + ); + + io_priority_group.add(vec![ + Box::new(io_priority_class_rt), + Box::new(io_priority_class_be), + Box::new(io_priority_class_idle), + ]); + io_priority_group +} diff --git a/tests/contest/contest/src/tests/io_priority/mod.rs b/tests/contest/contest/src/tests/io_priority/mod.rs new file mode 100644 index 00000000..9d684954 --- /dev/null +++ b/tests/contest/contest/src/tests/io_priority/mod.rs @@ -0,0 +1,3 @@ +mod io_priority_test; + +pub use io_priority_test::get_io_priority_test; diff --git a/tests/contest/contest/src/tests/mod.rs b/tests/contest/contest/src/tests/mod.rs index 927fe07c..5847f6f8 100644 --- a/tests/contest/contest/src/tests/mod.rs +++ b/tests/contest/contest/src/tests/mod.rs @@ -4,6 +4,7 @@ pub mod example; pub mod hooks; pub mod hostname; pub mod intel_rdt; +pub mod io_priority; pub mod lifecycle; pub mod linux_ns_itype; pub mod mounts_recursive; diff --git a/tests/contest/runtimetest/src/main.rs b/tests/contest/runtimetest/src/main.rs index ff685141..9474c468 100644 --- a/tests/contest/runtimetest/src/main.rs +++ b/tests/contest/runtimetest/src/main.rs @@ -1,6 +1,7 @@ mod tests; mod utils; +use oci_spec::runtime::IOPriorityClass::{IoprioClassBe, IoprioClassIdle, IoprioClassRt}; use oci_spec::runtime::Spec; use std::env; use std::path::PathBuf; @@ -38,6 +39,9 @@ fn main() { "sysctl" => tests::validate_sysctl(&spec), "scheduler_policy_other" => tests::validate_scheduler_policy(&spec), "scheduler_policy_batch" => tests::validate_scheduler_policy(&spec), + "io_priority_class_rt" => tests::test_io_priority_class(&spec, IoprioClassRt), + "io_priority_class_be" => tests::test_io_priority_class(&spec, IoprioClassBe), + "io_priority_class_idle" => tests::test_io_priority_class(&spec, IoprioClassIdle), _ => eprintln!("error due to unexpected execute test name: {execute_test}"), } } diff --git a/tests/contest/runtimetest/src/tests.rs b/tests/contest/runtimetest/src/tests.rs index 8b4b90cb..dee3afc7 100644 --- a/tests/contest/runtimetest/src/tests.rs +++ b/tests/contest/runtimetest/src/tests.rs @@ -1,7 +1,11 @@ use crate::utils::{self, test_read_access, test_write_access}; use anyhow::{bail, Result}; +use nix::libc; use nix::{errno::Errno, sys::utsname, unistd::getcwd}; -use oci_spec::runtime::{LinuxSchedulerPolicy, Spec}; +use oci_spec::runtime::{ + IOPriorityClass::{self, IoprioClassBe, IoprioClassIdle, IoprioClassRt}, + LinuxSchedulerPolicy, Spec, +}; use std::fs::{self, read_dir}; use std::mem; use std::path::Path; @@ -376,3 +380,55 @@ pub fn validate_scheduler_policy(spec: &Spec) { eprintln!("error due to sched_nice want {want_sn}, got {sn}") } } + +pub fn test_io_priority_class(spec: &Spec, io_priority_class: IOPriorityClass) { + let io_priority_spec = spec + .process() + .as_ref() + .unwrap() + .io_priority() + .as_ref() + .unwrap(); + if io_priority_spec.class() != io_priority_class { + let io_class = io_priority_spec.class(); + return eprintln!("error io_priority class want {io_priority_class:?}, got {io_class:?}"); + } + + let io_priority_who_progress: libc::c_int = 1; + let io_priority_who_pid = 0; + let res = unsafe { + libc::syscall( + libc::SYS_ioprio_get, + io_priority_who_progress, + io_priority_who_pid, + ) + }; + if let Err(e) = Errno::result(res) { + return eprintln!("error ioprio_get error {e}"); + } + + // ref: https://docs.kernel.org/block/ioprio.html + let class = res as u16 >> 13; + let priority = res as u16 & 0xFF; + + let expected_class = match io_priority_class { + IoprioClassRt => 1, + IoprioClassBe => 2, + IoprioClassIdle => 3, + }; + if class != expected_class { + return eprintln!( + "error ioprio_get class expected {io_priority_class:?} ({expected_class}), got {class}" + ); + } + + // these number mappings are arbitrary, we set the priority in test cases io_priority_test.rs file + let expected_priority = match io_priority_class { + IoprioClassRt => 1, + IoprioClassBe => 2, + IoprioClassIdle => 3, + }; + if priority != expected_priority { + eprintln!("error ioprio_get expected priority {expected_priority:?}, got {priority}") + } +}