From b2eafb8898856a32fe5425b1e71a4d351af64cf4 Mon Sep 17 00:00:00 2001 From: Jian Zeng Date: Wed, 15 Dec 2021 14:08:27 +0800 Subject: [PATCH] fix(libcgroup): set blkio weight Signed-off-by: Jian Zeng --- crates/libcgroups/src/v1/blkio.rs | 34 ++++++++++++++++- crates/libcgroups/src/v2/io.rs | 62 ++++++++++++++++++++++++------- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/crates/libcgroups/src/v1/blkio.rs b/crates/libcgroups/src/v1/blkio.rs index effaa4b9..43c3bda6 100644 --- a/crates/libcgroups/src/v1/blkio.rs +++ b/crates/libcgroups/src/v1/blkio.rs @@ -33,8 +33,12 @@ const BLKIO_THROTTLE_IO_SERVICE_BYTES: &str = "blkio.throttle.io_service_bytes"; // Proportional weight division policy // --------------------------------------- // Specifies the relative proportion of block I/O access available to the cgroup -// Format: weight (weight can range from 100 to 1000) +// Format: weight (weight can range from 10 to 1000) const BLKIO_WEIGHT: &str = "blkio.weight"; +// Similar to BLKIO_WEIGHT, but is only available in kernels starting with version 5.0 +// with blk-mq and when using BFQ I/O scheduler +// Format: weight (weight can range from 1 to 10000) +const BLKIO_BFQ_WEIGHT: &str = "blkio.bfq.weight"; // Specifies the relative proportion of block I/O access for specific devices available // to the cgroup. This overrides the the blkio.weight value for the specified device // Format: Major:Minor weight (weight can range from 100 to 1000) @@ -103,6 +107,19 @@ impl StatsProvider for Blkio { impl Blkio { fn apply(root_path: &Path, blkio: &LinuxBlockIo) -> Result<()> { + if let Some(blkio_weight) = blkio.weight() { + // be aligned with what runc does + // See also: https://github.com/opencontainers/runc/blob/81044ad7c902f3fc153cb8ffadaf4da62855193f/libcontainer/cgroups/fs/blkio.go#L28-L33 + if blkio_weight != 0 { + let cgroup_file = root_path.join(BLKIO_WEIGHT); + if cgroup_file.exists() { + common::write_cgroup_file(&cgroup_file, blkio_weight)?; + } else { + common::write_cgroup_file(&root_path.join(BLKIO_BFQ_WEIGHT), blkio_weight)?; + } + } + } + if let Some(throttle_read_bps_device) = blkio.throttle_read_bps_device().as_ref() { for trbd in throttle_read_bps_device { common::write_cgroup_file_str( @@ -226,6 +243,21 @@ mod tests { use anyhow::Result; use oci_spec::runtime::{LinuxBlockIoBuilder, LinuxThrottleDeviceBuilder}; + #[test] + fn test_set_blkio_weight() { + for cgroup_file in &[BLKIO_WEIGHT, BLKIO_BFQ_WEIGHT] { + let (tmp, weight_file) = setup("test_set_blkio_weight", cgroup_file); + let blkio = LinuxBlockIoBuilder::default() + .weight(200_u16) + .build() + .unwrap(); + + Blkio::apply(&tmp, &blkio).expect("apply blkio"); + let content = fs::read_to_string(weight_file).expect("read blkio weight"); + assert_eq!("200", content); + } + } + #[test] fn test_set_blkio_read_bps() { let (tmp, throttle) = setup("test_set_blkio_read_bps", BLKIO_THROTTLE_READ_BPS); diff --git a/crates/libcgroups/src/v2/io.rs b/crates/libcgroups/src/v2/io.rs index 8fe6d6c5..4ce9a2a5 100644 --- a/crates/libcgroups/src/v2/io.rs +++ b/crates/libcgroups/src/v2/io.rs @@ -79,6 +79,17 @@ impl StatsProvider for Io { } impl Io { + // Since the OCI spec is designed for cgroup v1, in some cases + // there is need to convert from the cgroup v1 configuration to cgroup v2 + // the formula for BlkIOWeight to IOWeight is y = (1 + (x - 10) * 9999 / 990) + // convert linearly from [10-1000] to [1-10000] + fn convert_cfq_io_weight_to_bfq(v: u16) -> u16 { + if v == 0 { + return 0; + } + 1 + (v - 10) * 9999 / 990 + } + fn io_max_path(path: &Path) -> PathBuf { path.join("io.max") } @@ -99,11 +110,18 @@ impl Io { } } if let Some(io_weight) = blkio.weight() { + // be aligned with what runc does + // See also: https://github.com/opencontainers/runc/blob/81044ad7c902f3fc153cb8ffadaf4da62855193f/libcontainer/cgroups/fs2/io.go#L57-L69 if io_weight > 0 { - common::write_cgroup_file( - root_path.join(CGROUP_IO_WEIGHT), - format!("{}", io_weight), - )?; + let cgroup_file = root_path.join(CGROUP_BFQ_IO_WEIGHT); + if cgroup_file.exists() { + common::write_cgroup_file(cgroup_file, io_weight)?; + } else { + common::write_cgroup_file( + root_path.join(CGROUP_IO_WEIGHT), + Self::convert_cfq_io_weight_to_bfq(io_weight), + )?; + } } } @@ -259,17 +277,33 @@ mod test { #[test] fn test_set_ioweight() { - let (tmp, throttle) = setup("test_set_io_weight", CGROUP_IO_WEIGHT); - let blkio = LinuxBlockIoBuilder::default() - .weight(100u16) - .build() - .unwrap(); + struct TestCase { + cgroup_file: &'static str, + weight: u16, + expected_weight: String, + } + for case in &[ + TestCase { + cgroup_file: CGROUP_BFQ_IO_WEIGHT, + weight: 100, + expected_weight: String::from("100"), + }, + TestCase { + cgroup_file: CGROUP_IO_WEIGHT, + weight: 10, + expected_weight: String::from("1"), + }, + ] { + let (tmp, weight_file) = setup("test_set_io_weight", case.cgroup_file); + let blkio = LinuxBlockIoBuilder::default() + .weight(case.weight) + .build() + .unwrap(); - Io::apply(&tmp, &blkio).expect("apply blkio"); - let content = - fs::read_to_string(throttle).unwrap_or_else(|_| panic!("read bfq_io_weight content")); - - assert_eq!("100", content); + Io::apply(&tmp, &blkio).expect("apply blkio"); + let content = fs::read_to_string(weight_file).expect("read blkio weight"); + assert_eq!(case.expected_weight, content); + } } #[test]