From 9ce206f6bc2ed786bf2c4e102c455765b9112f45 Mon Sep 17 00:00:00 2001 From: bin liu Date: Tue, 25 Aug 2020 10:50:52 +0800 Subject: [PATCH 01/71] probe cgroup v1 mount path Signed-off-by: bin liu --- src/hierarchies.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 368251a5..204c8871 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -126,11 +126,21 @@ fn find_v1_mount() -> Option { let mut fields = line.split_whitespace(); let index = line.find(" - ").unwrap(); let mut more_fields = line[index + 3..].split_whitespace().collect::>(); - let fstype = more_fields[0]; - if fstype == "tmpfs" && more_fields[2].contains("ro") { + if more_fields.len() == 0 { + continue; + } + if more_fields[0] == "cgroup" { + if more_fields.len() < 3 { + continue; + } let cgroups_mount = fields.nth(4).unwrap(); - info!("found cgroups at {:?}", cgroups_mount); - return Some(cgroups_mount.to_string()); + if let Some(parent) = std::path::Path::new(cgroups_mount).parent() { + if let Some(path) = parent.as_os_str().to_str() { + debug!("found cgroups {:?} from {:?}", path, cgroups_mount); + return Some(path.to_string()); + } + } + continue; } } From 6b1b26b1fe7f944216f5d7e1ccc5a62bd84a36b8 Mon Sep 17 00:00:00 2001 From: bin liu Date: Tue, 25 Aug 2020 10:51:29 +0800 Subject: [PATCH 02/71] copy cpuset after created Signed-off-by: bin liu --- src/cpuset.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 7 +++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/cpuset.rs b/src/cpuset.rs index b7b679a7..92e981d7 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -2,6 +2,8 @@ //! //! See the Kernel's documentation for more information about this subsystem, found at: //! [Documentation/cgroup-v1/cpusets.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt) + +use log::*; use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; @@ -104,6 +106,69 @@ impl ControllerInternal for CpuSetController { Ok(()) } + + fn post_create(&self){ + let current = self.get_path(); + let parent = match current.parent() { + Some(p) => p, + None => return, + }; + + if current != self.get_base() { + match copy_from_parent(current.to_str().unwrap(), parent.to_str().unwrap()) { + Ok(_)=>(), + Err(err) => error!("error create_dir {:?}", err), + } + } + } +} + +/// copy_from_parent copy the cpuset.cpus and cpuset.mems from the parent +/// directory to the current directory if the file's contents are 0 +fn copy_from_parent(current: &str, parent: &str) -> Result<()> { + let cpus_str: &str = "cpuset.cpus"; + let mems_str: &str = "cpuset.mems"; + + let current_cpus_path = ::std::path::Path::new(current).join(cpus_str); + let current_mems_path = ::std::path::Path::new(current).join(mems_str); + let parent_cpus_path = ::std::path::Path::new(parent).join(cpus_str); + let parent_mems_path = ::std::path::Path::new(parent).join(mems_str); + + let current_cpus = match ::std::fs::read_to_string(current_cpus_path.to_str().unwrap()) { + Ok(cpus) => String::from(cpus.trim()), + Err(e) => return Err(Error::with_cause(ReadFailed, e)), + }; + + let current_mems = match ::std::fs::read_to_string(current_mems_path.to_str().unwrap()) { + Ok(mems) => String::from(mems.trim()), + Err(e) => return Err(Error::with_cause(ReadFailed, e)), + }; + + let parent_cpus = match ::std::fs::read_to_string(parent_cpus_path.to_str().unwrap()) { + Ok(cpus) => cpus, + Err(e) => return Err(Error::with_cause(ReadFailed, e)), + }; + + let parent_mems = match ::std::fs::read_to_string(parent_mems_path.to_str().unwrap()) { + Ok(mems) => mems, + Err(e) => return Err(Error::with_cause(ReadFailed, e)), + }; + + if current_cpus == "" { + match ::std::fs::write(current_cpus_path.to_str().unwrap(), parent_cpus.as_bytes()) { + Ok(_) => (), + Err(e) => return Err(Error::with_cause(WriteFailed, e)), + } + } + + if current_mems == "" { + match ::std::fs::write(current_mems_path.to_str().unwrap(), parent_mems.as_bytes()) { + Ok(_) => (), + Err(e) => return Err(Error::with_cause(WriteFailed, e)), + } + } + + Ok(()) } impl ControllIdentifier for CpuSetController { diff --git a/src/lib.rs b/src/lib.rs index e6ed6459..c7b539be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -120,6 +120,11 @@ mod sealed { fn get_path_mut(&mut self) -> &mut PathBuf; fn get_base(&self) -> &PathBuf; + /// Hooks running after controller crated, if have + fn post_create(&self){ + } + + fn verify_path(&self) -> Result<()> { if self.get_path().starts_with(self.get_base()) { Ok(()) @@ -211,7 +216,7 @@ impl Controller for T where T: ControllerInternal { self.verify_path().expect("path should be valid"); match ::std::fs::create_dir(self.get_path()) { - Ok(_) => (), + Ok(_) => self.post_create(), Err(e) => warn!("error create_dir {:?}", e), } } From 9d7046732733f4d098557b55048af5df49a9d7ca Mon Sep 17 00:00:00 2001 From: bin liu Date: Tue, 25 Aug 2020 10:51:49 +0800 Subject: [PATCH 03/71] add hugetlb functions Signed-off-by: bin liu --- Cargo.toml | 1 + src/error.rs | 3 + src/hugetlb.rs | 144 +++++++++++++++++++++++++++++++++++++++++++++-- tests/hugetlb.rs | 34 +++++++++++ 4 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 tests/hugetlb.rs diff --git a/Cargo.toml b/Cargo.toml index 524e0063..1556a405 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" [dependencies] log = "0.4" +regex = "1.1" [dev-dependencies] nix = "0.11.0" diff --git a/src/error.rs b/src/error.rs index 70eb4eca..f14a15c4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -27,6 +27,8 @@ pub enum ErrorKind { /// This crate checks against this and operations will fail with this error. InvalidPath, + InvalidBytesSize, + /// An unknown error has occured. Other, } @@ -45,6 +47,7 @@ impl fmt::Display for Error { ErrorKind::ParseError => "unable to parse control group file", ErrorKind::InvalidOperation => "the requested operation is invalid", ErrorKind::InvalidPath => "the given path is invalid", + ErrorKind::InvalidBytesSize => "invalid bytes size", ErrorKind::Other => "an unknown error", }; diff --git a/src/hugetlb.rs b/src/hugetlb.rs index 5c3b1b73..3a1560f1 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -20,8 +20,9 @@ use crate::{ /// the control group. #[derive(Debug, Clone)] pub struct HugeTlbController { - base: PathBuf, - path: PathBuf, + base: PathBuf, + path: PathBuf, + sizes: Vec, } impl ControllerInternal for HugeTlbController { @@ -87,16 +88,26 @@ impl HugeTlbController { pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); + let sizes = get_hugepage_sizes().unwrap(); Self { base: root.clone(), path: root, + sizes: sizes, } } /// Whether the system supports `hugetlb_size` hugepages. - pub fn size_supported(&self, _hugetlb_size: &str) -> bool { - // TODO - true + pub fn size_supported(&self, hugetlb_size: &str) -> bool { + for s in &self.sizes { + if s == hugetlb_size { + return true + } + } + false + } + + pub fn get_sizes(&self) -> Vec { + self.sizes.clone() } /// Check how many times has the limit of `hugetlb_size` hugepages been hit. @@ -138,3 +149,126 @@ impl HugeTlbController { }) } } + + +pub const HUGEPAGESIZE_DIR: &'static str = "/sys/kernel/mm/hugepages"; +use regex::Regex; +use std::collections::HashMap; +use std::fs; + +fn get_hugepage_sizes() -> Result> { + let mut m = Vec::new(); + let dirs = fs::read_dir(HUGEPAGESIZE_DIR); + if dirs.is_err() { + return Ok(m); + } + + for e in dirs.unwrap() { + let entry = e.unwrap(); + let name = entry.file_name().into_string().unwrap(); + let parts: Vec<&str> = name.split('-').collect(); + if parts.len() != 2 { + continue; + } + let bmap= get_binary_size_map(); + let size = parse_size(parts[1], &bmap)?; + let dabbrs = get_decimal_abbrs(); + m.push(custom_size(size as f64, 1024.0, &dabbrs)); + } + + Ok(m) +} + + +pub const KB: u128 = 1000; +pub const MB: u128 = 1000 * KB; +pub const GB: u128 = 1000 * MB; +pub const TB: u128 = 1000 * GB; +pub const PB: u128 = 1000 * TB; + +pub const KiB: u128 = 1024; +pub const MiB: u128 = 1024 * KiB; +pub const GiB: u128 = 1024 * MiB; +pub const TiB: u128 = 1024 * GiB; +pub const PiB: u128 = 1024 * TiB; + + +pub fn get_binary_size_map() -> HashMap { + let mut m = HashMap::new(); + m.insert("k".to_string(), KiB); + m.insert("m".to_string(), MiB); + m.insert("g".to_string(), GiB); + m.insert("t".to_string(), TiB); + m.insert("p".to_string(), PiB); + m +} + +pub fn get_decimal_size_map() -> HashMap { + let mut m = HashMap::new(); + m.insert("k".to_string(), KB); + m.insert("m".to_string(), MB); + m.insert("g".to_string(), GB); + m.insert("t".to_string(), TB); + m.insert("p".to_string(), PB); + m +} + +pub fn get_decimal_abbrs() -> Vec { + let m = vec![ + "B".to_string(), + "KB".to_string(), + "MB".to_string(), + "GB".to_string(), + "TB".to_string(), + "PB".to_string(), + "EB".to_string(), + "ZB".to_string(), + "YB".to_string(), + ]; + m +} + +fn parse_size(s: &str, m: &HashMap) -> Result { + let re = Regex::new(r"(?P\d+)(?P[kKmMgGtTpP]?)[bB]?$"); + + if re.is_err() { + return Err(Error::new(InvalidBytesSize)); + } + let caps = re.unwrap().captures(s).unwrap(); + + let num = caps.name("num"); + let size: u128 = if num.is_some() { + let n = num.unwrap().as_str().trim().parse::(); + if n.is_err(){ + return Err(Error::new(InvalidBytesSize)); + } + n.unwrap() + } else { + return Err(Error::new(InvalidBytesSize)); + }; + + let q = caps.name("mul"); + let mul: u128 = if q.is_some() { + let t = m.get(q.unwrap().as_str()); + if t.is_some() { + *t.unwrap() + } else { + return Err(Error::new(InvalidBytesSize)); + } + } else { + return Err(Error::new(InvalidBytesSize)); + }; + + Ok(size * mul) +} + +fn custom_size(mut size: f64, base: f64, m: &Vec) -> String { + let mut i = 0; + while size >= base && i < m.len() - 1 { + size /= base; + i += 1; + } + + format!("{}{}", size, m[i].as_str()) +} + diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs new file mode 100644 index 00000000..8ceeecfe --- /dev/null +++ b/tests/hugetlb.rs @@ -0,0 +1,34 @@ +//! Integration tests about the hugetlb subsystem +use cgroups::hugetlb::{HugeTlbController}; +use cgroups::Controller; +use cgroups::Cgroup; + +use cgroups::error::*; +use cgroups::error::ErrorKind::*; + +#[test] +fn test_hugetlb_sizes() { + let hier = cgroups::hierarchies::V1::new(); + let cg = Cgroup::new(&hier, String::from("test_hugetlb_sizes")); + { + let hugetlb_controller: &HugeTlbController = cg.controller_of().unwrap(); + let sizes = hugetlb_controller.get_sizes(); + + let size = "2MB"; + assert_eq!(sizes, vec![size.to_string()]); + + let supported = hugetlb_controller.size_supported(size); + assert_eq!(supported, true); + + assert_no_error( hugetlb_controller.failcnt(size)); + assert_no_error( hugetlb_controller.limit_in_bytes(size)); + assert_no_error( hugetlb_controller.usage_in_bytes(size)); + assert_no_error( hugetlb_controller.max_usage_in_bytes(size)); + } + cg.delete(); +} + + +fn assert_no_error(r: Result ) { + assert_eq!(!r.is_err() , true) +} \ No newline at end of file From c702852fd706f866fab49e3e29fcd2115cb9d032 Mon Sep 17 00:00:00 2001 From: bin liu Date: Tue, 25 Aug 2020 11:35:01 +0800 Subject: [PATCH 04/71] add disable oom_control function Signed-off-by: bin liu --- src/memory.rs | 142 ++++++++++++++++++++++++++++------------------- tests/hugetlb.rs | 21 ++++--- tests/memory.rs | 29 ++++++++++ 3 files changed, 125 insertions(+), 67 deletions(-) create mode 100644 tests/memory.rs diff --git a/src/memory.rs b/src/memory.rs index d7acaf81..a9adedb0 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -2,12 +2,13 @@ //! //! See the Kernel's documentation for more information about this subsystem, found at: //! [Documentation/cgroup-v1/memory.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt) +use std::collections::HashMap; use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ ControllIdentifier, ControllerInternal, Controllers, MemoryResources, Resources, Subsystem, @@ -109,7 +110,8 @@ fn parse_numa_stat(s: String) -> Result { x.split("=").collect::>()[1] .parse::() .unwrap_or(0) - }).collect() + }) + .collect() }, file_pages: file_line .split(|x| x == ' ' || x == '=') @@ -123,7 +125,8 @@ fn parse_numa_stat(s: String) -> Result { x.split("=").collect::>()[1] .parse::() .unwrap_or(0) - }).collect() + }) + .collect() }, anon_pages: anon_line .split(|x| x == ' ' || x == '=') @@ -137,7 +140,8 @@ fn parse_numa_stat(s: String) -> Result { x.split("=").collect::>()[1] .parse::() .unwrap_or(0) - }).collect() + }) + .collect() }, unevictable_pages: unevict_line .split(|x| x == ' ' || x == '=') @@ -151,7 +155,8 @@ fn parse_numa_stat(s: String) -> Result { x.split("=").collect::>()[1] .parse::() .unwrap_or(0) - }).collect() + }) + .collect() }, hierarchical_total_pages: hier_total_line .split(|x| x == ' ' || x == '=') @@ -165,7 +170,8 @@ fn parse_numa_stat(s: String) -> Result { x.split("=").collect::>()[1] .parse::() .unwrap_or(0) - }).collect() + }) + .collect() }, hierarchical_file_pages: hier_file_line .split(|x| x == ' ' || x == '=') @@ -179,7 +185,8 @@ fn parse_numa_stat(s: String) -> Result { x.split("=").collect::>()[1] .parse::() .unwrap_or(0) - }).collect() + }) + .collect() }, hierarchical_anon_pages: hier_anon_line .split(|x| x == ' ' || x == '=') @@ -193,7 +200,8 @@ fn parse_numa_stat(s: String) -> Result { x.split("=").collect::>()[1] .parse::() .unwrap_or(0) - }).collect() + }) + .collect() }, hierarchical_unevictable_pages: hier_unevict_line .split(|x| x == ' ' || x == '=') @@ -207,7 +215,8 @@ fn parse_numa_stat(s: String) -> Result { x.split("=").collect::>()[1] .parse::() .unwrap_or(0) - }).collect() + }) + .collect() }, }) } @@ -250,52 +259,63 @@ pub struct MemoryStat { pub total_inactive_file: u64, pub total_active_file: u64, pub total_unevictable: u64, + pub raw: HashMap, } fn parse_memory_stat(s: String) -> Result { - let sp: Vec<&str> = s - .split_whitespace() - .filter(|x| x.parse::().is_ok()) - .collect(); + let mut raw = HashMap::new(); + + for l in s.lines() { + let t: Vec<&str> = l.split(' ').collect(); + if t.len() != 2 { + continue; + } + let n = t[1].trim().parse::(); + if n.is_err() { + continue; + } + + raw.insert(t[0].to_string(), n.unwrap()); + } - let mut spl = sp.iter(); Ok(MemoryStat { - cache: spl.next().unwrap().parse::().unwrap(), - rss: spl.next().unwrap().parse::().unwrap(), - rss_huge: spl.next().unwrap().parse::().unwrap(), - shmem: spl.next().unwrap().parse::().unwrap(), - mapped_file: spl.next().unwrap().parse::().unwrap(), - dirty: spl.next().unwrap().parse::().unwrap(), - writeback: spl.next().unwrap().parse::().unwrap(), - swap: spl.next().unwrap().parse::().unwrap(), - pgpgin: spl.next().unwrap().parse::().unwrap(), - pgpgout: spl.next().unwrap().parse::().unwrap(), - pgfault: spl.next().unwrap().parse::().unwrap(), - pgmajfault: spl.next().unwrap().parse::().unwrap(), - inactive_anon: spl.next().unwrap().parse::().unwrap(), - active_anon: spl.next().unwrap().parse::().unwrap(), - inactive_file: spl.next().unwrap().parse::().unwrap(), - active_file: spl.next().unwrap().parse::().unwrap(), - unevictable: spl.next().unwrap().parse::().unwrap(), - hierarchical_memory_limit: spl.next().unwrap().parse::().unwrap(), - hierarchical_memsw_limit: spl.next().unwrap().parse::().unwrap(), - total_cache: spl.next().unwrap().parse::().unwrap(), - total_rss: spl.next().unwrap().parse::().unwrap(), - total_rss_huge: spl.next().unwrap().parse::().unwrap(), - total_shmem: spl.next().unwrap().parse::().unwrap(), - total_mapped_file: spl.next().unwrap().parse::().unwrap(), - total_dirty: spl.next().unwrap().parse::().unwrap(), - total_writeback: spl.next().unwrap().parse::().unwrap(), - total_swap: spl.next().unwrap().parse::().unwrap(), - total_pgpgin: spl.next().unwrap().parse::().unwrap(), - total_pgpgout: spl.next().unwrap().parse::().unwrap(), - total_pgfault: spl.next().unwrap().parse::().unwrap(), - total_pgmajfault: spl.next().unwrap().parse::().unwrap(), - total_inactive_anon: spl.next().unwrap().parse::().unwrap(), - total_active_anon: spl.next().unwrap().parse::().unwrap(), - total_inactive_file: spl.next().unwrap().parse::().unwrap(), - total_active_file: spl.next().unwrap().parse::().unwrap(), - total_unevictable: spl.next().unwrap().parse::().unwrap(), + cache: *raw.get("cache").unwrap_or(&0), + rss: *raw.get("rss").unwrap_or(&0), + rss_huge: *raw.get("rss_huge").unwrap_or(&0), + shmem: *raw.get("shmem").unwrap_or(&0), + mapped_file: *raw.get("mapped_file").unwrap_or(&0), + dirty: *raw.get("dirty").unwrap_or(&0), + writeback: *raw.get("writeback").unwrap_or(&0), + swap: *raw.get("swap").unwrap_or(&0), + pgpgin: *raw.get("pgpgin").unwrap_or(&0), + pgpgout: *raw.get("pgpgout").unwrap_or(&0), + pgfault: *raw.get("pgfault").unwrap_or(&0), + pgmajfault: *raw.get("pgmajfault").unwrap_or(&0), + inactive_anon: *raw.get("inactive_anon").unwrap_or(&0), + active_anon: *raw.get("active_anon").unwrap_or(&0), + inactive_file: *raw.get("inactive_file").unwrap_or(&0), + active_file: *raw.get("active_file").unwrap_or(&0), + unevictable: *raw.get("unevictable").unwrap_or(&0), + hierarchical_memory_limit: *raw.get("hierarchical_memory_limit").unwrap_or(&0), + hierarchical_memsw_limit: *raw.get("hierarchical_memsw_limit").unwrap_or(&0), + total_cache: *raw.get("total_cache").unwrap_or(&0), + total_rss: *raw.get("total_rss").unwrap_or(&0), + total_rss_huge: *raw.get("total_rss_huge").unwrap_or(&0), + total_shmem: *raw.get("total_shmem").unwrap_or(&0), + total_mapped_file: *raw.get("total_mapped_file").unwrap_or(&0), + total_dirty: *raw.get("total_dirty").unwrap_or(&0), + total_writeback: *raw.get("total_writeback").unwrap_or(&0), + total_swap: *raw.get("total_swap").unwrap_or(&0), + total_pgpgin: *raw.get("total_pgpgin").unwrap_or(&0), + total_pgpgout: *raw.get("total_pgpgout").unwrap_or(&0), + total_pgfault: *raw.get("total_pgfault").unwrap_or(&0), + total_pgmajfault: *raw.get("total_pgmajfault").unwrap_or(&0), + total_inactive_anon: *raw.get("total_inactive_anon").unwrap_or(&0), + total_active_anon: *raw.get("total_active_anon").unwrap_or(&0), + total_inactive_file: *raw.get("total_inactive_file").unwrap_or(&0), + total_active_file: *raw.get("total_active_file").unwrap_or(&0), + total_unevictable: *raw.get("total_unevictable").unwrap_or(&0), + raw: raw, }) } @@ -564,11 +584,10 @@ impl MemController { /// Reset the fail counter pub fn reset_fail_count(&self) -> Result<()> { - self.open_path("memory.failcnt", true) - .and_then(|mut file| { - file.write_all("0".to_string().as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path("memory.failcnt", true).and_then(|mut file| { + file.write_all("0".to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } /// Reset the kernel memory fail counter @@ -657,6 +676,14 @@ impl MemController { .map_err(|e| Error::with_cause(WriteFailed, e)) }) } + + pub fn disable_oom_killer(&self) -> Result<()> { + self.open_path("memory.oom_control", true) + .and_then(|mut file| { + file.write_all("1".to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) + } } impl ControllIdentifier for MemController { @@ -682,7 +709,10 @@ impl<'a> From<&'a Subsystem> for &'a MemController { fn read_u64_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { - Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)), + Ok(_) => string + .trim() + .parse() + .map_err(|e| Error::with_cause(ParseError, e)), Err(e) => Err(Error::with_cause(ReadFailed, e)), } } diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index 8ceeecfe..00ac46a0 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -1,10 +1,10 @@ //! Integration tests about the hugetlb subsystem -use cgroups::hugetlb::{HugeTlbController}; -use cgroups::Controller; +use cgroups::hugetlb::HugeTlbController; use cgroups::Cgroup; +use cgroups::Controller; -use cgroups::error::*; use cgroups::error::ErrorKind::*; +use cgroups::error::*; #[test] fn test_hugetlb_sizes() { @@ -20,15 +20,14 @@ fn test_hugetlb_sizes() { let supported = hugetlb_controller.size_supported(size); assert_eq!(supported, true); - assert_no_error( hugetlb_controller.failcnt(size)); - assert_no_error( hugetlb_controller.limit_in_bytes(size)); - assert_no_error( hugetlb_controller.usage_in_bytes(size)); - assert_no_error( hugetlb_controller.max_usage_in_bytes(size)); + assert_no_error(hugetlb_controller.failcnt(size)); + assert_no_error(hugetlb_controller.limit_in_bytes(size)); + assert_no_error(hugetlb_controller.usage_in_bytes(size)); + assert_no_error(hugetlb_controller.max_usage_in_bytes(size)); } cg.delete(); } - -fn assert_no_error(r: Result ) { - assert_eq!(!r.is_err() , true) -} \ No newline at end of file +fn assert_no_error(r: Result) { + assert_eq!(!r.is_err(), true) +} diff --git a/tests/memory.rs b/tests/memory.rs new file mode 100644 index 00000000..c80f35b1 --- /dev/null +++ b/tests/memory.rs @@ -0,0 +1,29 @@ +//! Integration tests about the hugetlb subsystem +use cgroups::memory::MemController; +use cgroups::Cgroup; +use cgroups::Controller; + +use cgroups::error::ErrorKind::*; +use cgroups::error::*; + +#[test] +fn test_disable_oom_killer() { + let hier = cgroups::hierarchies::V1::new(); + let cg = Cgroup::new(&hier, String::from("test_disable_oom_killer")); + { + let mem_controller: &MemController = cg.controller_of().unwrap(); + + // before disable + let m = mem_controller.memory_stat(); + assert_eq!(m.oom_control.oom_kill_disable, false); + + // disable oom killer + let r = mem_controller.disable_oom_killer(); + assert_eq!(r.is_err(), false); + + // after disable + let m = mem_controller.memory_stat(); + assert_eq!(m.oom_control.oom_kill_disable, true); + } + cg.delete(); +} From 9fe6cb58e46bfedd874cb3ef7fe82465495d62dc Mon Sep 17 00:00:00 2001 From: bin liu Date: Tue, 25 Aug 2020 13:28:36 +0800 Subject: [PATCH 05/71] change *limit* in memory from u64 to i64 Signed-off-by: bin liu --- Cargo.toml | 4 +- src/blkio.rs | 12 +++- src/cgroup.rs | 62 ++++++++++++++++++-- src/cgroup_builder.rs | 21 +++---- src/cpu.rs | 12 +++- src/cpuset.rs | 19 +++++- src/error.rs | 27 ++++++--- src/events.rs | 83 ++++++++++++++++++++++++++ src/hierarchies.rs | 133 ++++++++++++++++++++++++++++++++++++++---- src/hugetlb.rs | 12 +++- src/lib.rs | 75 +++++++++++++++++++++--- src/memory.rs | 117 ++++++++++++++++++++++++++++++------- src/pid.rs | 48 +++++---------- tests/builder.rs | 47 ++++++++++----- tests/cgroup.rs | 7 ++- tests/cpuset.rs | 43 +++++++++++++- tests/devices.rs | 7 ++- tests/hugetlb.rs | 7 ++- tests/memory.rs | 85 +++++++++++++++++++++++---- tests/pids.rs | 32 +++++----- tests/resources.rs | 13 +++-- 21 files changed, 700 insertions(+), 166 deletions(-) create mode 100644 src/events.rs diff --git a/Cargo.toml b/Cargo.toml index 1556a405..6c99a682 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" [dependencies] log = "0.4" regex = "1.1" +nix = "0.18.0" [dev-dependencies] -nix = "0.11.0" -libc = "0.2.43" +libc = "0.2.76" diff --git a/src/blkio.rs b/src/blkio.rs index fa55f64e..97464bd3 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -21,6 +21,7 @@ use crate::{ pub struct BlkIoController { base: PathBuf, path: PathBuf, + v2: bool, } #[derive(Eq, PartialEq, Debug)] @@ -269,6 +270,10 @@ impl ControllerInternal for BlkIoController { &self.base } + fn is_v2(&self) -> bool { + self.v2 + } + fn apply(&self, res: &Resources) -> Result<()> { // get the resources that apply to this controller let res: &BlkIoResources = &res.blkio; @@ -341,12 +346,15 @@ fn read_u64_from(mut file: File) -> Result { impl BlkIoController { /// Constructs a new `BlkIoController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { + pub fn new(oroot: PathBuf, v2: bool) -> Self { let mut root = oroot; - root.push(Self::controller_type().to_string()); + if !v2{ + root.push(Self::controller_type().to_string()); + } Self { base: root.clone(), path: root, + v2: v2, } } diff --git a/src/cgroup.rs b/src/cgroup.rs index 140a4f4a..dd424efb 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -5,7 +5,8 @@ use crate::error::*; use crate::{CgroupPid, ControllIdentifier, Controller, Hierarchy, Resources, Subsystem}; use std::convert::From; -use std::path::Path; +use std::fs; +use std::path::{Path, PathBuf}; /// A control group is the central structure to this crate. /// @@ -24,14 +25,19 @@ pub struct Cgroup<'b> { subsystems: Vec, /// The hierarchy. - hier: &'b Hierarchy, + hier: Box<&'b dyn Hierarchy>, + path: String, } impl<'b> Cgroup<'b> { /// Create this control group. fn create(&self) { - for subsystem in &self.subsystems { - subsystem.to_controller().create(); + if self.hier.v2() { + create_v2_cgroup(self.hier.root().clone(), &self.path); + }else{ + for subsystem in &self.subsystems { + subsystem.to_controller().create(); + } } } @@ -41,7 +47,7 @@ impl<'b> Cgroup<'b> { /// /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. - pub fn new>(hier: &Hierarchy, path: P) -> Cgroup { + pub fn new>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup<'b> { let cg = Cgroup::load(hier, path); cg.create(); cg @@ -54,7 +60,7 @@ impl<'b> Cgroup<'b> { /// /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. - pub fn load>(hier: &Hierarchy, path: P) -> Cgroup { + pub fn load>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup<'b> { let path = path.as_ref(); let mut subsystems = hier.subsystems(); if path.as_os_str() != "" { @@ -67,6 +73,7 @@ impl<'b> Cgroup<'b> { let cg = Cgroup { subsystems: subsystems, hier: hier, + path: path.to_str().unwrap().to_string(), }; cg @@ -165,3 +172,46 @@ impl<'b> Cgroup<'b> { v } } + +pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; + +fn supported_controllers(p: &PathBuf) -> Vec{ + let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers"); + let ret = fs::read_to_string(p.as_str()); + ret.unwrap_or(String::new()).split(" ").map(|x| x.to_string() ).collect::>() +} + +fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { + // controler list ["memory", "cpu"] + let controllers = supported_controllers(&root); + let mut fp = root; + + // path: "a/b/c" + let elements = path.split("/").collect::>(); + let last_index = elements.len() - 1 ; + for (i, ele) in elements.iter().enumerate() { + // ROOT/a + fp.push(ele); + // create dir, need not check if is a file or directory + if !fp.exists(){ + // FIXME set mode to 0755 + match ::std::fs::create_dir(fp.clone()) { + Err(e) => return Err(Error::with_cause(ErrorKind::FsError, e)), + Ok(_) => {}, + } + } + + if i < last_index { + // enable controllers for substree + let mut f = fp.clone(); + f.push("cgroup.subtree_control"); + for c in &controllers{ + let body = format!("+{}", c); + // FIXME set mode to 0644 + let _rest = fs::write(f.as_path(), body.as_bytes()); + } + } + } + + Ok(()) +} \ No newline at end of file diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index 31999c88..f6a7f2cd 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -55,7 +55,7 @@ //! ``` use crate::error::*; -use crate::{pid, BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy, HugePageResource, NetworkPriority, Resources}; +use crate::{pid, BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy, HugePageResource, MaxValue, NetworkPriority, Resources}; macro_rules! gen_setter { ($res:ident, $cont:ident, $func:ident, $name:ident, $ty:ty) => { @@ -71,7 +71,7 @@ macro_rules! gen_setter { /// A control group builder instance pub struct CgroupBuilder<'a> { name: String, - hierarchy: &'a Hierarchy, + hierarchy: Box<&'a dyn Hierarchy>, /// Internal, unsupported field: use the associated builders instead. resources: Resources, } @@ -80,7 +80,7 @@ impl<'a> CgroupBuilder<'a> { /// Start building a control group with the supplied hierarchy and name pair. /// /// Note that this does not actually create the control group until `build()` is called. - pub fn new(name: &'a str, hierarchy: &'a Hierarchy) -> CgroupBuilder<'a> { + pub fn new(name: &'a str, hierarchy: Box<&'a dyn Hierarchy>) -> CgroupBuilder<'a> { CgroupBuilder { name: name.to_owned(), hierarchy: hierarchy, @@ -155,11 +155,11 @@ pub struct MemoryResourceBuilder<'a> { impl<'a> MemoryResourceBuilder<'a> { - gen_setter!(memory, MemController, set_kmem_limit, kernel_memory_limit, u64); - gen_setter!(memory, MemController, set_limit, memory_hard_limit, u64); - gen_setter!(memory, MemController, set_soft_limit, memory_soft_limit, u64); - gen_setter!(memory, MemController, set_tcp_limit, kernel_tcp_memory_limit, u64); - gen_setter!(memory, MemController, set_memswap_limit, memory_swap_limit, u64); + gen_setter!(memory, MemController, set_kmem_limit, kernel_memory_limit, i64); + gen_setter!(memory, MemController, set_limit, memory_hard_limit, i64); + gen_setter!(memory, MemController, set_soft_limit, memory_soft_limit, i64); + gen_setter!(memory, MemController, set_tcp_limit, kernel_tcp_memory_limit, i64); + gen_setter!(memory, MemController, set_memswap_limit, memory_swap_limit, i64); gen_setter!(memory, MemController, set_swappiness, swappiness, u64); /// Finish the construction of the memory resources of a control group. @@ -175,7 +175,7 @@ pub struct PidResourceBuilder<'a> { impl<'a> PidResourceBuilder<'a> { - gen_setter!(pid, PidController, set_pid_max, maximum_number_of_processes, pid::PidMax); + gen_setter!(pid, PidController, set_pid_max, maximum_number_of_processes, MaxValue); /// Finish the construction of the pid resources of a control group. pub fn done(self) -> CgroupBuilder<'a> { @@ -190,7 +190,8 @@ pub struct CpuResourceBuilder<'a> { impl<'a> CpuResourceBuilder<'a> { - gen_setter!(cpu, CpuSetController, set_cpus, cpus, String); + // FIXME this should all changed to options. + gen_setter!(cpu, CpuSetController, set_cpus, cpus, Option); gen_setter!(cpu, CpuSetController, set_mems, mems, String); gen_setter!(cpu, CpuController, set_shares, shares, u64); gen_setter!(cpu, CpuController, set_cfs_quota, quota, i64); diff --git a/src/cpu.rs b/src/cpu.rs index 3e43ea8e..ae48c1cd 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -23,6 +23,7 @@ use crate::{ pub struct CpuController { base: PathBuf, path: PathBuf, + v2: bool, } /// The current state of the control group and its processes. @@ -51,6 +52,10 @@ impl ControllerInternal for CpuController { &self.base } + fn is_v2(&self) -> bool { + self.v2 + } + fn apply(&self, res: &Resources) -> Result<()> { // get the resources that apply to this controller let res: &CpuResources = &res.cpu; @@ -109,12 +114,15 @@ fn read_u64_from(mut file: File) -> Result { impl CpuController { /// Contructs a new `CpuController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { + pub fn new(oroot: PathBuf, v2: bool) -> Self { let mut root = oroot; - root.push(Self::controller_type().to_string()); + if !v2 { + root.push(Self::controller_type().to_string()); + } Self { base: root.clone(), path: root, + v2: v2, } } diff --git a/src/cpuset.rs b/src/cpuset.rs index 92e981d7..fd2661a5 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -23,6 +23,7 @@ use crate::{ pub struct CpuSetController { base: PathBuf, path: PathBuf, + v2: bool, } /// The current state of the `cpuset` controller for this control group. @@ -95,12 +96,18 @@ impl ControllerInternal for CpuSetController { &self.base } + fn is_v2(&self) -> bool { + self.v2 + } + fn apply(&self, res: &Resources) -> Result<()> { // get the resources that apply to this controller let res: &CpuResources = &res.cpu; if res.update_values { - let _ = self.set_cpus(&res.cpus); + if res.cpus.is_some(){ + let _ = self.set_cpus(res.cpus.as_ref().unwrap().as_str()); + } let _ = self.set_mems(&res.mems); } @@ -108,6 +115,9 @@ impl ControllerInternal for CpuSetController { } fn post_create(&self){ + if self.is_v2(){ + return + } let current = self.get_path(); let parent = match current.parent() { Some(p) => p, @@ -246,12 +256,15 @@ fn parse_range(s: String) -> Result> { impl CpuSetController { /// Contructs a new `CpuSetController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { + pub fn new(oroot: PathBuf, v2: bool) -> Self { let mut root = oroot; - root.push(Self::controller_type().to_string()); + if !v2{ + root.push(Self::controller_type().to_string()); + } Self { base: root.clone(), path: root, + v2: v2, } } diff --git a/src/error.rs b/src/error.rs index f14a15c4..7bfea9b6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,6 +4,9 @@ use std::fmt; /// The different types of errors that can occur while manipulating control groups. #[derive(Debug, Eq, PartialEq)] pub enum ErrorKind { + FsError, + Common(String), + /// An error occured while writing to a control group file. WriteFailed, @@ -41,14 +44,16 @@ pub struct Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let msg = match self.kind { - ErrorKind::WriteFailed => "unable to write to a control group file", - ErrorKind::ReadFailed => "unable to read a control group file", - ErrorKind::ParseError => "unable to parse control group file", - ErrorKind::InvalidOperation => "the requested operation is invalid", - ErrorKind::InvalidPath => "the given path is invalid", - ErrorKind::InvalidBytesSize => "invalid bytes size", - ErrorKind::Other => "an unknown error", + let msg = match &self.kind { + ErrorKind::FsError => "fs error".to_string(), + ErrorKind::Common(s) => s.clone(), + ErrorKind::WriteFailed => "unable to write to a control group file".to_string(), + ErrorKind::ReadFailed => "unable to read a control group file".to_string(), + ErrorKind::ParseError => "unable to parse control group file".to_string(), + ErrorKind::InvalidOperation => "the requested operation is invalid".to_string(), + ErrorKind::InvalidPath => "the given path is invalid".to_string(), + ErrorKind::InvalidBytesSize => "invalid bytes size".to_string(), + ErrorKind::Other => "an unknown error".to_string(), }; write!(f, "{}", msg) @@ -65,6 +70,12 @@ impl StdError for Error { } impl Error { + pub(crate) fn from_string(s: String) -> Self { + Self { + kind: ErrorKind::Common(s), + cause: None, + } + } pub(crate) fn new(kind: ErrorKind) -> Self { Self { kind, diff --git a/src/events.rs b/src/events.rs new file mode 100644 index 00000000..3e7ac7dd --- /dev/null +++ b/src/events.rs @@ -0,0 +1,83 @@ +use eventfd::{eventfd, EfdFlags}; +use nix::sys::eventfd; +use std::fs::{self, File}; +use std::io::Read; +use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::path::{Path, PathBuf}; +use std::sync::mpsc::{self, Receiver}; +use std::thread; + +use crate::error::*; +use crate::error::ErrorKind::*; + + +// notify_on_oom returns channel on which you can expect event about OOM, +// if process died without OOM this channel will be closed. +pub fn notify_on_oom_v2(key: &str, dir: &PathBuf) -> Result> { + register_memory_event(key, dir, "memory.oom_control", "") +} + +// notify_on_oom returns channel on which you can expect event about OOM, +// if process died without OOM this channel will be closed. +pub fn notify_on_oom_v1(key: &str, dir: &PathBuf) -> Result> { + register_memory_event(key, dir, "memory.oom_control", "") +} + +// level is one of "low", "medium", or "critical" +fn notify_memory_pressure(key: &str, dir: &PathBuf, level: &str) -> Result> { + if level != "low" && level != "medium" && level != "critical" { + return Err(Error::from_string(format!("invalid pressure level {}", level))); + } + + register_memory_event(key, dir, "memory.pressure_level", level) +} + +fn register_memory_event( + key: &str, + cg_dir: &PathBuf, + event_name: &str, + arg: &str, +) -> Result> { + let path = cg_dir.join(event_name); + let event_file = File::open(path).map_err(|e| Error::with_cause(ReadFailed, e))?; + + let eventfd = eventfd(0, EfdFlags::EFD_CLOEXEC).map_err(|e| Error::with_cause(ReadFailed, e))?; + + let event_control_path = cg_dir.join("cgroup.event_control"); + let data; + if arg == "" { + data = format!("{} {}", eventfd, event_file.as_raw_fd()); + } else { + data = format!("{} {} {}", eventfd, event_file.as_raw_fd(), arg); + } + + // write to file and set mode to 0700(FIXME) + fs::write(&event_control_path, data).map_err(|e| Error::with_cause(WriteFailed, e)); + + let mut eventfd_file = unsafe { File::from_raw_fd(eventfd) }; + + let (sender, receiver) = mpsc::channel(); + let key = key.to_string(); + + thread::spawn(move || { + loop { + let mut buf = [0; 8]; + match eventfd_file.read(&mut buf) { + Err(err) => { + return; + } + Ok(_) => { + } + } + + // When a cgroup is destroyed, an event is sent to eventfd. + // So if the control path is gone, return instead of notifying. + if !Path::new(&event_control_path).exists() { + return; + } + sender.send(key.clone()).unwrap(); + } + }); + + Ok(receiver) +} \ No newline at end of file diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 204c8871..f99fd3fd 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -2,8 +2,9 @@ //! //! Currently, we only support the cgroupv1 hierarchy, but in the future we will add support for //! the Unified Hierarchy. +use nix::sys::statfs; -use std::fs::File; +use std::fs::{self, File}; use std::io::BufRead; use std::io::BufReader; use std::path::{Path, PathBuf}; @@ -32,23 +33,32 @@ pub struct V1 { mount_point: String, } +pub struct V2 { + root: String, +} + impl Hierarchy for V1 { + + fn v2(&self) -> bool { + false + } + fn subsystems(&self) -> Vec { let mut subs = vec![]; if self.check_support(Controllers::Pids) { - subs.push(Subsystem::Pid(PidController::new(self.root()))); + subs.push(Subsystem::Pid(PidController::new(self.root(), false))); } if self.check_support(Controllers::Mem) { - subs.push(Subsystem::Mem(MemController::new(self.root()))); + subs.push(Subsystem::Mem(MemController::new(self.root(), false))); } if self.check_support(Controllers::CpuSet) { - subs.push(Subsystem::CpuSet(CpuSetController::new(self.root()))); + subs.push(Subsystem::CpuSet(CpuSetController::new(self.root(), false))); } if self.check_support(Controllers::CpuAcct) { subs.push(Subsystem::CpuAcct(CpuAcctController::new(self.root()))); } if self.check_support(Controllers::Cpu) { - subs.push(Subsystem::Cpu(CpuController::new(self.root()))); + subs.push(Subsystem::Cpu(CpuController::new(self.root(), false))); } if self.check_support(Controllers::Devices) { subs.push(Subsystem::Devices(DevicesController::new(self.root()))); @@ -60,7 +70,7 @@ impl Hierarchy for V1 { subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); } if self.check_support(Controllers::BlkIo) { - subs.push(Subsystem::BlkIo(BlkIoController::new(self.root()))); + subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), true))); } if self.check_support(Controllers::PerfEvent) { subs.push(Subsystem::PerfEvent(PerfEventController::new(self.root()))); @@ -69,7 +79,7 @@ impl Hierarchy for V1 { subs.push(Subsystem::NetPrio(NetPrioController::new(self.root()))); } if self.check_support(Controllers::HugeTlb) { - subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root()))); + subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root(), false))); } if self.check_support(Controllers::Rdma) { subs.push(Subsystem::Rdma(RdmaController::new(self.root()))); @@ -79,7 +89,8 @@ impl Hierarchy for V1 { } fn root_control_group(&self) -> Cgroup { - Cgroup::load(self, "".to_string()) + let b : &Hierarchy = self as &Hierarchy; + Cgroup::load(Box::new(&*b), "".to_string()) } fn check_support(&self, sub: Controllers) -> bool { @@ -99,10 +110,82 @@ impl Hierarchy for V1 { } } +impl Hierarchy for V2 { + fn v2(&self) -> bool { + true + } + + fn subsystems(&self) -> Vec { + let mut subs = vec![]; + + let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers"); + let ret = fs::read_to_string(p.as_str()); + if ret.is_err() { + return subs; + } + + let controllers = ret.unwrap().trim().to_string(); + println!("controllers: {:?}", controllers); + + let controller_list: Vec<&str> = controllers.split(' ').collect(); + + for s in controller_list { + match s { + "cpu" => {subs.push(Subsystem::Cpu(CpuController::new(self.root(), true)));}, + "io" => {subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), true)));}, + "cpuset" => {subs.push(Subsystem::CpuSet(CpuSetController::new(self.root(), true)));}, + "memory" => {subs.push(Subsystem::Mem(MemController::new(self.root(), true)));}, + "pids" => {subs.push(Subsystem::Pid(PidController::new(self.root(), true)));}, + _ => {}, + } + } + + if self.check_support(Controllers::CpuAcct) { + subs.push(Subsystem::CpuAcct(CpuAcctController::new(self.root()))); + } + if self.check_support(Controllers::Devices) { + subs.push(Subsystem::Devices(DevicesController::new(self.root()))); + } + if self.check_support(Controllers::Freezer) { + subs.push(Subsystem::Freezer(FreezerController::new(self.root()))); + } + if self.check_support(Controllers::NetCls) { + subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); + } + if self.check_support(Controllers::PerfEvent) { + subs.push(Subsystem::PerfEvent(PerfEventController::new(self.root()))); + } + if self.check_support(Controllers::NetPrio) { + subs.push(Subsystem::NetPrio(NetPrioController::new(self.root()))); + } + if self.check_support(Controllers::HugeTlb) { + subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root(), true))); + } + if self.check_support(Controllers::Rdma) { + subs.push(Subsystem::Rdma(RdmaController::new(self.root()))); + } + + subs + } + + fn root_control_group(&self) -> Cgroup { + let b : &Hierarchy = self as &Hierarchy; + Cgroup::load(Box::new(&*b), "".to_string()) + } + + fn check_support(&self, _sub: Controllers) -> bool { + return false; + } + + fn root(&self) -> PathBuf { + PathBuf::from(self.root.clone()) + } +} + impl V1 { /// Finds where control groups are mounted to and returns a hierarchy in which control groups /// can be created. - pub fn new() -> Self { + pub fn new() -> V1 { let mount_point = find_v1_mount().unwrap(); V1 { mount_point: mount_point, @@ -110,6 +193,36 @@ impl V1 { } } +impl V2 { + /// Finds where control groups are mounted to and returns a hierarchy in which control groups + /// can be created. + pub fn new() -> V2 { + V2 { + root: String::from(UNIFIED_MOUNTPOINT), + } + } +} + +pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; + +pub fn is_cgroup2_unified_mode() -> bool { + let path = Path::new(UNIFIED_MOUNTPOINT); + let fs_stat = statfs::statfs(path); + if fs_stat.is_err() { + return false + } + + fs_stat.unwrap().filesystem_type() == statfs::CGROUP2_SUPER_MAGIC +} + +pub fn auto() -> Box { + if is_cgroup2_unified_mode() { + Box::new(V2::new()) + }else{ + Box::new(V1::new()) + } +} + fn find_v1_mount() -> Option { // Open mountinfo so we can get a parseable mount list let mountinfo_path = Path::new("/proc/self/mountinfo"); @@ -125,7 +238,7 @@ fn find_v1_mount() -> Option { let line = _line.unwrap(); let mut fields = line.split_whitespace(); let index = line.find(" - ").unwrap(); - let mut more_fields = line[index + 3..].split_whitespace().collect::>(); + let more_fields = line[index + 3..].split_whitespace().collect::>(); if more_fields.len() == 0 { continue; } diff --git a/src/hugetlb.rs b/src/hugetlb.rs index 3a1560f1..dcf98faa 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -23,6 +23,7 @@ pub struct HugeTlbController { base: PathBuf, path: PathBuf, sizes: Vec, + v2: bool, } impl ControllerInternal for HugeTlbController { @@ -39,6 +40,10 @@ impl ControllerInternal for HugeTlbController { &self.base } + fn is_v2(&self) -> bool { + self.v2 + } + fn apply(&self, res: &Resources) -> Result<()> { // get the resources that apply to this controller let res: &HugePageResources = &res.hugepages; @@ -85,14 +90,17 @@ fn read_u64_from(mut file: File) -> Result { impl HugeTlbController { /// Constructs a new `HugeTlbController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { + pub fn new(oroot: PathBuf, v2: bool) -> Self { let mut root = oroot; - root.push(Self::controller_type().to_string()); + if !v2 { + root.push(Self::controller_type().to_string()); + } let sizes = get_hugepage_sizes().unwrap(); Self { base: root.clone(), path: root, sizes: sizes, + v2: v2, } } diff --git a/src/lib.rs b/src/lib.rs index c7b539be..f1133300 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ use log::*; use std::fs::File; -use std::io::{BufRead, BufReader, Write}; +use std::io::{Read, BufRead, BufReader, Write}; use std::path::{Path, PathBuf}; pub mod blkio; @@ -11,6 +11,7 @@ pub mod cpuacct; pub mod cpuset; pub mod devices; pub mod error; +pub mod events; pub mod freezer; pub mod hierarchies; pub mod hugetlb; @@ -28,6 +29,7 @@ use crate::cpuacct::CpuAcctController; use crate::cpuset::CpuSetController; use crate::devices::DevicesController; use crate::error::*; +use crate::error::ErrorKind::*; use crate::freezer::FreezerController; use crate::hugetlb::HugeTlbController; use crate::memory::MemController; @@ -124,6 +126,9 @@ mod sealed { fn post_create(&self){ } + fn is_v2(&self) -> bool { + false + } fn verify_path(&self) -> Result<()> { if self.get_path().starts_with(self.get_base()) { @@ -152,6 +157,17 @@ mod sealed { } } + fn get_max_value(&self, f: &str) -> Result { + self.open_path(f, false).and_then(|mut file| { + let mut string = String::new(); + let res = file.read_to_string(&mut string); + match res { + Ok(_) => parse_max_value(&string), + Err(e) => Err(Error::with_cause(ReadFailed, e)), + } + }) + } + #[doc(hidden)] fn path_exists(&self, p: &str) -> bool { if let Err(_) = self.verify_path() { @@ -194,6 +210,8 @@ pub trait Controller { /// Get the list of tasks that this controller has. fn tasks(&self) -> Vec; + + fn v2(&self) -> bool; } impl Controller for T where T: ControllerInternal { @@ -256,6 +274,11 @@ impl Controller for T where T: ControllerInternal { Ok(v.into_iter().map(CgroupPid::from).collect()) }).unwrap_or(vec![]) } + + fn v2(&self) -> bool { + self.is_v2() + } + } #[doc(hidden)] @@ -275,6 +298,8 @@ pub trait Hierarchy { /// Return a handle to the root control group in the hierarchy. fn root_control_group(&self) -> Cgroup; + fn v2(&self) -> bool; + /// Checks whether a certain subsystem is supported in the hierarchy. /// /// This is an internal function and should not be used. @@ -288,16 +313,16 @@ pub struct MemoryResources { /// Whether values should be applied to the controller. pub update_values: bool, /// How much memory (in bytes) can the kernel consume. - pub kernel_memory_limit: u64, + pub kernel_memory_limit: i64, /// Upper limit of memory usage of the control group's tasks. - pub memory_hard_limit: u64, + pub memory_hard_limit: i64, /// How much memory the tasks in the control group can use when the system is under memory /// pressure. - pub memory_soft_limit: u64, + pub memory_soft_limit: i64, /// How much of the kernel's memory (in bytes) can be used for TCP-related buffers. - pub kernel_tcp_memory_limit: u64, + pub kernel_tcp_memory_limit: i64, /// How much memory and swap together can the tasks in the control group use. - pub memory_swap_limit: u64, + pub memory_swap_limit: i64, /// Controls the tendency of the kernel to swap out parts of the address space of the tasks to /// disk. Lower value implies less likely. /// @@ -316,7 +341,7 @@ pub struct PidResources { /// Note that attaching processes to the control group will still succeed _even_ if the limit /// would be violated, however forks/clones inside the control group will have with `EAGAIN` if /// they would violate the limit set here. - pub maximum_number_of_processes: pid::PidMax, + pub maximum_number_of_processes: MaxValue, } /// Resources limits about how the tasks can use the CPU. @@ -327,7 +352,7 @@ pub struct CpuResources { // cpuset /// A comma-separated list of CPU IDs where the task in the control group can run. Dashes /// between numbers indicate ranges. - pub cpus: String, + pub cpus: Option, /// Same syntax as the `cpus` field of this structure, but applies to memory nodes instead of /// processors. pub mems: String, @@ -584,3 +609,37 @@ impl Subsystem { } } } + + + +/// The values for `memory.hight` or `pids.max` +#[derive(Eq, PartialEq, Copy, Clone, Debug)] +pub enum MaxValue { + /// This value is returned when the text is `"max"`. + Max, + /// When the value is a numerical value, they are returned via this enum field. + Value(i64), +} + +impl Default for MaxValue { + fn default() -> Self { + MaxValue::Max + } +} + +pub fn parse_max_value(s: &String) -> Result { + if s.trim() == "max" { + return Ok(MaxValue::Max) + } + match s.trim().parse() { + Ok(val) => Ok(MaxValue::Value(val)), + Err(e) => Err(Error::with_cause(ParseError, e)), + } +} + +pub fn max_value_to_string(m: MaxValue) -> String { + match m { + MaxValue::Max => "max".to_string(), + MaxValue::Value(num) => num.to_string(), + } +} \ No newline at end of file diff --git a/src/memory.rs b/src/memory.rs index a9adedb0..8793459e 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -6,14 +6,18 @@ use std::collections::HashMap; use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; +use std::sync::mpsc::{Receiver}; use crate::error::ErrorKind::*; use crate::error::*; +use crate::events; use crate::{ ControllIdentifier, ControllerInternal, Controllers, MemoryResources, Resources, Subsystem, }; +use crate::{MaxValue, max_value_to_string, parse_max_value}; + /// A controller that allows controlling the `memory` subsystem of a Cgroup. /// /// In essence, using the memory controller, the user can gather statistics about the memory usage @@ -23,6 +27,16 @@ use crate::{ pub struct MemController { base: PathBuf, path: PathBuf, + v2: bool, +} + + +#[derive(Default, Debug, PartialEq, Eq)] +pub struct SetMemory { + pub low: Option, + pub high: Option, + pub min: Option, + pub max: Option, } /// Controls statistics and controls about the OOM killer operating in this control group. @@ -240,8 +254,8 @@ pub struct MemoryStat { pub inactive_file: u64, pub active_file: u64, pub unevictable: u64, - pub hierarchical_memory_limit: u64, - pub hierarchical_memsw_limit: u64, + pub hierarchical_memory_limit: i64, + pub hierarchical_memsw_limit: i64, pub total_cache: u64, pub total_rss: u64, pub total_rss_huge: u64, @@ -296,8 +310,8 @@ fn parse_memory_stat(s: String) -> Result { inactive_file: *raw.get("inactive_file").unwrap_or(&0), active_file: *raw.get("active_file").unwrap_or(&0), unevictable: *raw.get("unevictable").unwrap_or(&0), - hierarchical_memory_limit: *raw.get("hierarchical_memory_limit").unwrap_or(&0), - hierarchical_memsw_limit: *raw.get("hierarchical_memsw_limit").unwrap_or(&0), + hierarchical_memory_limit: *raw.get("hierarchical_memory_limit").unwrap_or(&0) as i64, + hierarchical_memsw_limit: *raw.get("hierarchical_memsw_limit").unwrap_or(&0) as i64, total_cache: *raw.get("total_cache").unwrap_or(&0), total_rss: *raw.get("total_rss").unwrap_or(&0), total_rss_huge: *raw.get("total_rss_huge").unwrap_or(&0), @@ -326,7 +340,7 @@ pub struct MemSwap { /// How many times the limit has been hit. pub fail_cnt: u64, /// Memory and swap usage limit in bytes. - pub limit_in_bytes: u64, + pub limit_in_bytes: i64, /// Current usage of memory and swap in bytes. pub usage_in_bytes: u64, /// The maximum observed usage of memory and swap in bytes. @@ -340,7 +354,7 @@ pub struct Memory { /// How many times the limit has been hit. pub fail_cnt: u64, /// The limit in bytes of the memory usage of the control group's tasks. - pub limit_in_bytes: u64, + pub limit_in_bytes: i64, /// The current usage of memory by the control group's tasks. pub usage_in_bytes: u64, /// The maximum observed usage of memory by the control group's tasks. @@ -362,7 +376,7 @@ pub struct Memory { pub oom_control: OomControl, /// Allows setting a limit to memory usage which is enforced when the system (note, _not_ the /// control group) detects memory pressure. - pub soft_limit_in_bytes: u64, + pub soft_limit_in_bytes: i64, /// Contains a wide array of statistics about the memory usage of the tasks in the control /// group. pub stat: MemoryStat, @@ -385,7 +399,7 @@ pub struct Tcp { pub fail_cnt: u64, /// The limit in bytes of the memory usage of the kernel's TCP buffers by control group's /// tasks. - pub limit_in_bytes: u64, + pub limit_in_bytes: i64, /// The current memory used by the kernel's TCP buffers related to these tasks. pub usage_in_bytes: u64, /// The observed maximum usage of memory by the kernel's TCP buffers (that originated from @@ -402,7 +416,7 @@ pub struct Kmem { /// How many times the limit has been hit. pub fail_cnt: u64, /// The limit in bytes of the kernel memory used by the control group's tasks. - pub limit_in_bytes: u64, + pub limit_in_bytes: i64, /// The current usage of kernel memory used by the control group's tasks, in bytes. pub usage_in_bytes: u64, /// The maximum observed usage of kernel memory used by the control group's tasks, in bytes. @@ -425,6 +439,10 @@ impl ControllerInternal for MemController { &self.base } + fn is_v2(&self) -> bool { + self.v2 + } + fn apply(&self, res: &Resources) -> Result<()> { // get the resources that apply to this controller let memres: &MemoryResources = &res.memory; @@ -444,15 +462,48 @@ impl ControllerInternal for MemController { impl MemController { /// Contructs a new `MemController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { + pub fn new(oroot: PathBuf, v2: bool) -> Self { let mut root = oroot; - root.push(Self::controller_type().to_string()); + if !v2 { + root.push(Self::controller_type().to_string()); + } Self { base: root.clone(), path: root, + v2: v2, } } + // for v2 + pub fn set_mem(&self, m: SetMemory) -> Result<()> { + let values = vec![(m.high, "memory.high"),(m.low, "memory.low"),(m.max, "memory.max"),(m.min, "memory.min")]; + for value in values{ + let v = value.0; + let f = value.1; + if v.is_some() { + let v = v.unwrap(); + let v = max_value_to_string(v); + self.open_path(f, true) + .and_then(|mut file| { + file.write_all(v.as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + })?; + } + } + Ok(()) + } + + // for v2 + pub fn get_mem(&self) -> Result { + let mut m: SetMemory = Default::default(); + self.get_max_value("memory.high").map(|x| m.high = Some(x)); + self.get_max_value("memory.low").map(|x| m.low = Some(x)); + self.get_max_value("memory.max").map(|x| m.max = Some(x)); + self.get_max_value("memory.min").map(|x| m.min = Some(x)); + + Ok(m) + } + /// Gathers overall statistics (and the current state of) about the memory usage of the control /// group's tasks. /// @@ -466,7 +517,7 @@ impl MemController { .unwrap_or(0), limit_in_bytes: self .open_path("memory.limit_in_bytes", false) - .and_then(read_u64_from) + .and_then(read_i64_from) .unwrap_or(0), usage_in_bytes: self .open_path("memory.usage_in_bytes", false) @@ -492,7 +543,7 @@ impl MemController { .unwrap_or(OomControl::default()), soft_limit_in_bytes: self .open_path("memory.soft_limit_in_bytes", false) - .and_then(read_u64_from) + .and_then(read_i64_from) .unwrap_or(0), stat: self .open_path("memory.stat", false) @@ -519,8 +570,8 @@ impl MemController { .unwrap_or(0), limit_in_bytes: self .open_path("memory.kmem.limit_in_bytes", false) - .and_then(read_u64_from) - .unwrap_or(0), + .and_then(read_i64_from) + .unwrap_or(-1), usage_in_bytes: self .open_path("memory.kmem.usage_in_bytes", false) .and_then(read_u64_from) @@ -546,7 +597,7 @@ impl MemController { .unwrap_or(0), limit_in_bytes: self .open_path("memory.kmem.tcp.limit_in_bytes", false) - .and_then(read_u64_from) + .and_then(read_i64_from) .unwrap_or(0), usage_in_bytes: self .open_path("memory.kmem.tcp.usage_in_bytes", false) @@ -569,7 +620,7 @@ impl MemController { .unwrap_or(0), limit_in_bytes: self .open_path("memory.memsw.limit_in_bytes", false) - .and_then(read_u64_from) + .and_then(read_i64_from) .unwrap_or(0), usage_in_bytes: self .open_path("memory.memsw.usage_in_bytes", false) @@ -618,7 +669,7 @@ impl MemController { } /// Set the memory usage limit of the control group, in bytes. - pub fn set_limit(&self, limit: u64) -> Result<()> { + pub fn set_limit(&self, limit: i64) -> Result<()> { self.open_path("memory.limit_in_bytes", true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) @@ -627,7 +678,7 @@ impl MemController { } /// Set the kernel memory limit of the control group, in bytes. - pub fn set_kmem_limit(&self, limit: u64) -> Result<()> { + pub fn set_kmem_limit(&self, limit: i64) -> Result<()> { self.open_path("memory.kmem.limit_in_bytes", true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) @@ -636,7 +687,7 @@ impl MemController { } /// Set the memory+swap limit of the control group, in bytes. - pub fn set_memswap_limit(&self, limit: u64) -> Result<()> { + pub fn set_memswap_limit(&self, limit: i64) -> Result<()> { self.open_path("memory.memsw.limit_in_bytes", true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) @@ -645,7 +696,7 @@ impl MemController { } /// Set how much kernel memory can be used for TCP-related buffers by the control group. - pub fn set_tcp_limit(&self, limit: u64) -> Result<()> { + pub fn set_tcp_limit(&self, limit: i64) -> Result<()> { self.open_path("memory.kmem.tcp.limit_in_bytes", true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) @@ -657,7 +708,7 @@ impl MemController { /// /// This limit is enforced when the system is nearing OOM conditions. Contrast this with the /// hard limit, which is _always_ enforced. - pub fn set_soft_limit(&self, limit: u64) -> Result<()> { + pub fn set_soft_limit(&self, limit: i64) -> Result<()> { self.open_path("memory.soft_limit_in_bytes", true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) @@ -684,6 +735,14 @@ impl MemController { .map_err(|e| Error::with_cause(WriteFailed, e)) }) } + + pub fn register_oom_event(&self, key: &str) -> Result>{ + if self.v2{ + events::notify_on_oom_v2(key, self.get_path()) + }else { + events::notify_on_oom_v1(key, self.get_path()) + } + } } impl ControllIdentifier for MemController { @@ -717,6 +776,17 @@ fn read_u64_from(mut file: File) -> Result { } } +fn read_i64_from(mut file: File) -> Result { + let mut string = String::new(); + match file.read_to_string(&mut string) { + Ok(_) => string + .trim() + .parse() + .map_err(|e| Error::with_cause(ParseError, e)), + Err(e) => Err(Error::with_cause(ReadFailed, e)), + } +} + fn read_string_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { @@ -727,6 +797,7 @@ fn read_string_from(mut file: File) -> Result { #[cfg(test)] mod tests { + use std::collections::HashMap; use crate::memory::{ parse_memory_stat, parse_numa_stat, parse_oom_control, MemoryStat, NumaStat, OomControl, }; @@ -830,6 +901,7 @@ total_unevictable 81920 #[test] fn test_parse_memory_stat() { let ok = parse_memory_stat(GOOD_MEMORYSTAT_VAL.to_string()).unwrap(); + let raw = ok.raw.clone(); assert_eq!( ok, MemoryStat { @@ -869,6 +941,7 @@ total_unevictable 81920 total_inactive_file: 1272135680, total_active_file: 2338816000, total_unevictable: 81920, + raw: raw, } ); } diff --git a/src/pid.rs b/src/pid.rs index d7f42d2c..3be3da0d 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -10,7 +10,7 @@ use crate::error::*; use crate::error::ErrorKind::*; use crate::{ - ControllIdentifier, ControllerInternal, Controllers, PidResources, Resources, Subsystem, + ControllIdentifier, ControllerInternal, Controllers, MaxValue, max_value_to_string, parse_max_value, PidResources, Resources, Subsystem, }; /// A controller that allows controlling the `pids` subsystem of a Cgroup. @@ -18,22 +18,7 @@ use crate::{ pub struct PidController { base: PathBuf, path: PathBuf, -} - -/// The values found in the `pids.max` file in a Cgroup's `pids` subsystem. -#[derive(Eq, PartialEq, Copy, Clone, Debug)] -pub enum PidMax { - /// This value is returned when the text found `pids.max` is `"max"`. - Max, - /// When the value in `pids.max` is a numerical value, they are returned via this enum field. - Value(i64), -} - -impl Default for PidMax { - /// By default, (as per the kernel) `pids.max` should contain `"max"`. - fn default() -> Self { - PidMax::Max - } + v2: bool, } impl ControllerInternal for PidController { @@ -50,6 +35,10 @@ impl ControllerInternal for PidController { &self.base } + fn is_v2(&self) -> bool { + self.v2 + } + fn apply(&self, res: &Resources) -> Result<()> { // get the resources that apply to this controller let pidres: &PidResources = &res.pid; @@ -107,12 +96,15 @@ fn read_u64_from(mut file: File) -> Result { impl PidController { /// Constructors a new `PidController` instance, with `oroot` serving as the controller's root /// directory. - pub fn new(oroot: PathBuf) -> Self { + pub fn new(oroot: PathBuf, v2: bool) -> Self { let mut root = oroot; - root.push(Self::controller_type().to_string()); + if !v2 { + root.push(Self::controller_type().to_string()); + } Self { base: root.clone(), path: root, + v2: v2, } } @@ -140,19 +132,12 @@ impl PidController { } /// The maximum number of processes that can exist at one time in the control group. - pub fn get_pid_max(&self) -> Result { + pub fn get_pid_max(&self) -> Result { self.open_path("pids.max", false).and_then(|mut file| { let mut string = String::new(); let res = file.read_to_string(&mut string); match res { - Ok(_) => if string.trim() == "max" { - Ok(PidMax::Max) - } else { - match string.trim().parse() { - Ok(val) => Ok(PidMax::Value(val)), - Err(e) => Err(Error::with_cause(ParseError, e)), - } - }, + Ok(_) => parse_max_value(&string), Err(e) => Err(Error::with_cause(ReadFailed, e)), } }) @@ -163,12 +148,9 @@ impl PidController { /// Note that if `get_pid_current()` returns a higher number than what you /// are about to set (`max_pid`), then no processess will be killed. Additonally, attaching /// extra processes to a control group disregards the limit. - pub fn set_pid_max(&self, max_pid: PidMax) -> Result<()> { + pub fn set_pid_max(&self, max_pid: MaxValue) -> Result<()> { self.open_path("pids.max", true).and_then(|mut file| { - let string_to_write = match max_pid { - PidMax::Max => "max".to_string(), - PidMax::Value(num) => num.to_string(), - }; + let string_to_write = max_value_to_string(max_pid); match file.write_all(string_to_write.as_ref()) { Ok(_) => Ok(()), Err(e) => Err(Error::with_cause(WriteFailed, e)), diff --git a/tests/builder.rs b/tests/builder.rs index 45c11128..bd3687ca 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -11,8 +11,9 @@ use cgroups::cgroup_builder::*; #[test] pub fn test_cpu_res_build() { - let v1 = crate::hierarchies::V1::new(); - let cg: Cgroup = CgroupBuilder::new("test_cpu_res_build", &v1) + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg: Cgroup = CgroupBuilder::new("test_cpu_res_build", h) .cpu() .shares(85) .done() @@ -29,8 +30,9 @@ pub fn test_cpu_res_build() { #[test] pub fn test_memory_res_build() { - let v1 = crate::hierarchies::V1::new(); - let cg: Cgroup = CgroupBuilder::new("test_memory_res_build", &v1) + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg: Cgroup = CgroupBuilder::new("test_memory_res_build", h) .memory() .kernel_memory_limit(128 * 1024 * 1024) .swappiness(70) @@ -50,17 +52,18 @@ pub fn test_memory_res_build() { #[test] pub fn test_pid_res_build() { - let v1 = crate::hierarchies::V1::new(); - let cg: Cgroup = CgroupBuilder::new("test_pid_res_build", &v1) + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg: Cgroup = CgroupBuilder::new("test_pid_res_build", h) .pid() - .maximum_number_of_processes(PidMax::Value(123)) + .maximum_number_of_processes(MaxValue::Value(123)) .done() .build(); { let c: &PidController = cg.controller_of().unwrap(); assert!(c.get_pid_max().is_ok()); - assert_eq!(c.get_pid_max().unwrap(), PidMax::Value(123)); + assert_eq!(c.get_pid_max().unwrap(), MaxValue::Value(123)); } cg.delete(); @@ -69,8 +72,9 @@ pub fn test_pid_res_build() { #[test] #[ignore] // ignore this test for now, not sure why my kernel doesn't like it pub fn test_devices_res_build() { - let v1 = crate::hierarchies::V1::new(); - let cg: Cgroup = CgroupBuilder::new("test_devices_res_build", &v1) + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg: Cgroup = CgroupBuilder::new("test_devices_res_build", h) .devices() .device(1, 6, DeviceType::Char, true, vec![DevicePermissions::Read]) @@ -95,8 +99,13 @@ pub fn test_devices_res_build() { #[test] pub fn test_network_res_build() { - let v1 = crate::hierarchies::V1::new(); - let cg: Cgroup = CgroupBuilder::new("test_network_res_build", &v1) + let h = cgroups::hierarchies::auto(); + if h.v2() { + // FIXME + return + } + let h = Box::new(&*h); + let cg: Cgroup = CgroupBuilder::new("test_network_res_build", h) .network() .class_id(1337) .done() @@ -112,8 +121,13 @@ pub fn test_network_res_build() { #[test] pub fn test_hugepages_res_build() { - let v1 = crate::hierarchies::V1::new(); - let cg: Cgroup = CgroupBuilder::new("test_hugepages_res_build", &v1) + let h = cgroups::hierarchies::auto(); + if h.v2() { + // FIXME + return + } + let h = Box::new(&*h); + let cg: Cgroup = CgroupBuilder::new("test_hugepages_res_build", h) .hugepages() .limit("2MB".to_string(), 4 * 2 * 1024 * 1024) .done() @@ -129,8 +143,9 @@ pub fn test_hugepages_res_build() { #[test] pub fn test_blkio_res_build() { - let v1 = crate::hierarchies::V1::new(); - let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build", &v1) + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build", h) .blkio() .weight(100) .done() diff --git a/tests/cgroup.rs b/tests/cgroup.rs index 8b15d9a4..177eea30 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -1,11 +1,12 @@ //! Simple unit tests about the control groups system. -use cgroups::{Cgroup, CgroupPid}; +use cgroups::{Cgroup, CgroupPid, Hierarchy}; #[test] fn test_tasks_iterator() { - let hier = cgroups::hierarchies::V1::new(); + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); let pid = libc::pid_t::from(nix::unistd::getpid()) as u64; - let cg = Cgroup::new(&hier, String::from("test_tasks_iterator")); + let cg = Cgroup::new(h, String::from("test_tasks_iterator")); { // Add a task to the control group. cg.add_task(CgroupPid::from(pid)); diff --git a/tests/cpuset.rs b/tests/cpuset.rs index c7a8fb0c..bd7d8a40 100644 --- a/tests/cpuset.rs +++ b/tests/cpuset.rs @@ -1,11 +1,12 @@ use cgroups::cpuset::CpuSetController; use cgroups::error::ErrorKind; -use cgroups::Cgroup; +use cgroups::{Cgroup, CpuResources, Hierarchy, Resources}; #[test] fn test_cpuset_memory_pressure_root_cg() { - let hier = cgroups::hierarchies::V1::new(); - let cg = Cgroup::new(&hier, String::from("test_cpuset_memory_pressure_root_cg")); + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("test_cpuset_memory_pressure_root_cg")); { let cpuset: &CpuSetController = cg.controller_of().unwrap(); @@ -15,3 +16,39 @@ fn test_cpuset_memory_pressure_root_cg() { } cg.delete(); } + + +#[test] +fn test_cpuset_set_cpus() { + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus")); + { + let cpuset: &CpuSetController = cg.controller_of().unwrap(); + + let set = cpuset.cpuset(); + assert_eq!(0, set.cpus.len()); + + // 0 + let r = cpuset.set_cpus("0"); + assert_eq!(true, r.is_ok()); + + let set = cpuset.cpuset(); + assert_eq!(1, set.cpus.len()); + assert_eq!((0,0), set.cpus[0]); + + + // 0-1 + // FIXME need two cores + let r = cpuset.set_cpus("0-1"); + assert_eq!(true, r.is_ok()); + + let set = cpuset.cpuset(); + assert_eq!(1, set.cpus.len()); + assert_eq!((0,1), set.cpus[0]); + + + + } + cg.delete(); +} \ No newline at end of file diff --git a/tests/devices.rs b/tests/devices.rs index 2fbb3058..891c8a95 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -1,12 +1,13 @@ //! Integration tests about the devices subsystem use cgroups::devices::{DevicePermissions, DeviceType, DevicesController}; -use cgroups::{Cgroup, DeviceResource}; +use cgroups::{Cgroup, DeviceResource, Hierarchy}; #[test] fn test_devices_parsing() { - let hier = cgroups::hierarchies::V1::new(); - let cg = Cgroup::new(&hier, String::from("test_devices_parsing")); + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("test_devices_parsing")); { let devices: &DevicesController = cg.controller_of().unwrap(); diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index 00ac46a0..f7b0afb4 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -1,6 +1,6 @@ //! Integration tests about the hugetlb subsystem use cgroups::hugetlb::HugeTlbController; -use cgroups::Cgroup; +use cgroups::{Cgroup, Hierarchy}; use cgroups::Controller; use cgroups::error::ErrorKind::*; @@ -8,8 +8,9 @@ use cgroups::error::*; #[test] fn test_hugetlb_sizes() { - let hier = cgroups::hierarchies::V1::new(); - let cg = Cgroup::new(&hier, String::from("test_hugetlb_sizes")); + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("test_hugetlb_sizes")); { let hugetlb_controller: &HugeTlbController = cg.controller_of().unwrap(); let sizes = hugetlb_controller.get_sizes(); diff --git a/tests/memory.rs b/tests/memory.rs index c80f35b1..8838afec 100644 --- a/tests/memory.rs +++ b/tests/memory.rs @@ -1,6 +1,6 @@ //! Integration tests about the hugetlb subsystem -use cgroups::memory::MemController; -use cgroups::Cgroup; +use cgroups::memory::{MemController, SetMemory}; +use cgroups::{Cgroup, Hierarchy, MaxValue}; use cgroups::Controller; use cgroups::error::ErrorKind::*; @@ -8,8 +8,9 @@ use cgroups::error::*; #[test] fn test_disable_oom_killer() { - let hier = cgroups::hierarchies::V1::new(); - let cg = Cgroup::new(&hier, String::from("test_disable_oom_killer")); + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("test_disable_oom_killer")); { let mem_controller: &MemController = cg.controller_of().unwrap(); @@ -17,13 +18,77 @@ fn test_disable_oom_killer() { let m = mem_controller.memory_stat(); assert_eq!(m.oom_control.oom_kill_disable, false); - // disable oom killer - let r = mem_controller.disable_oom_killer(); - assert_eq!(r.is_err(), false); + // FIXME only v1 + if !mem_controller.v2(){ + // disable oom killer + let r = mem_controller.disable_oom_killer(); + assert_eq!(r.is_err(), false); - // after disable - let m = mem_controller.memory_stat(); - assert_eq!(m.oom_control.oom_kill_disable, true); + // after disable + let m = mem_controller.memory_stat(); + assert_eq!(m.oom_control.oom_kill_disable, true); + } + + } + cg.delete(); +} + +#[test] +fn set_mem_v2() { + let h = cgroups::hierarchies::auto(); + if !h.v2() { + return + } + + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("set_mem_v2")); + { + let mem_controller: &MemController = cg.controller_of().unwrap(); + + // before disable + let m = mem_controller.get_mem().unwrap(); + // case 1: get default value + assert_eq!(m.low, Some(MaxValue::Value(0))); + assert_eq!(m.min, Some(MaxValue::Value(0))); + assert_eq!(m.high, Some(MaxValue::Max)); + assert_eq!(m.max, Some(MaxValue::Max)); + + // case 2: set parts + let m = SetMemory{ + low: Some(MaxValue::Value(1024*1024* 2)), + high: Some(MaxValue::Value(1024*1024*1024* 2)), + min: Some(MaxValue::Value(1024*1024* 3)), + max: None, + }; + let r = mem_controller.set_mem(m); + assert_eq!(true, r.is_ok()); + + let m = mem_controller.get_mem().unwrap(); + // get + assert_eq!(m.low, Some(MaxValue::Value(1024*1024* 2))); + assert_eq!(m.min, Some(MaxValue::Value(1024*1024* 3))); + assert_eq!(m.high, Some(MaxValue::Value(1024*1024*1024* 2))); + assert_eq!(m.max, Some(MaxValue::Max)); + + + + // case 3: set parts + let m = SetMemory{ + max: Some(MaxValue::Value(1024*1024*1024* 2)), + min: Some(MaxValue::Value(1024*1024* 4)), + high: Some(MaxValue::Max), + low: None, + }; + let r = mem_controller.set_mem(m); + assert_eq!(true, r.is_ok()); + + let m = mem_controller.get_mem().unwrap(); + // get + assert_eq!(m.low, Some(MaxValue::Value(1024*1024* 2))); + assert_eq!(m.min, Some(MaxValue::Value(1024*1024* 4))); + assert_eq!(m.max, Some(MaxValue::Value(1024*1024*1024* 2))); + assert_eq!(m.high, Some(MaxValue::Max)); } + cg.delete(); } diff --git a/tests/pids.rs b/tests/pids.rs index 4c91e54b..74dd7929 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -1,7 +1,7 @@ //! Integration tests about the pids subsystem -use cgroups::pid::{PidController, PidMax}; +use cgroups::pid::{PidController}; use cgroups::Controller; -use cgroups::{Cgroup, CgroupPid, PidResources, Resources}; +use cgroups::{Cgroup, CgroupPid, Hierarchy, MaxValue, PidResources, Resources}; use nix::sys::wait::{waitpid, WaitStatus}; use nix::unistd::{fork, ForkResult, Pid}; @@ -12,22 +12,24 @@ use std::thread; #[test] fn create_and_delete_cgroup() { - let hier = cgroups::hierarchies::V1::new(); - let cg = Cgroup::new(&hier, String::from("create_and_delete_cgroup")); + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("create_and_delete_cgroup")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); - pidcontroller.set_pid_max(PidMax::Value(1337)); + pidcontroller.set_pid_max(MaxValue::Value(1337)); let max = pidcontroller.get_pid_max(); assert!(max.is_ok()); - assert_eq!(max.unwrap(), PidMax::Value(1337)); + assert_eq!(max.unwrap(), MaxValue::Value(1337)); } cg.delete(); } #[test] fn test_pids_current_is_zero() { - let hier = cgroups::hierarchies::V1::new(); - let cg = Cgroup::new(&hier, String::from("test_pids_current_is_zero")); + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("test_pids_current_is_zero")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); let current = pidcontroller.get_pid_current(); @@ -38,8 +40,9 @@ fn test_pids_current_is_zero() { #[test] fn test_pids_events_is_zero() { - let hier = cgroups::hierarchies::V1::new(); - let cg = Cgroup::new(&hier, String::from("test_pids_events_is_zero")); + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("test_pids_events_is_zero")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); let events = pidcontroller.get_pid_events(); @@ -51,8 +54,9 @@ fn test_pids_events_is_zero() { #[test] fn test_pid_events_is_not_zero() { - let hier = cgroups::hierarchies::V1::new(); - let cg = Cgroup::new(&hier, String::from("test_pid_events_is_not_zero")); + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("test_pid_events_is_not_zero")); { let pids: &PidController = cg.controller_of().unwrap(); let before = pids.get_pid_events(); @@ -66,7 +70,7 @@ fn test_pid_events_is_not_zero() { println!("added task to cg: {:?}", child); // Set limit to one - pids.set_pid_max(PidMax::Value(1)); + pids.set_pid_max(MaxValue::Value(1)); println!("err = {:?}", pids.get_pid_max()); // wait on the child @@ -84,7 +88,7 @@ fn test_pid_events_is_not_zero() { } Ok(ForkResult::Child) => loop { let pids_max = pids.get_pid_max(); - if pids_max.is_ok() && pids_max.unwrap() == PidMax::Value(1) { + if pids_max.is_ok() && pids_max.unwrap() == MaxValue::Value(1) { if let Err(_) = fork() { unsafe { libc::exit(0) }; } else { diff --git a/tests/resources.rs b/tests/resources.rs index c612df12..d26a896b 100644 --- a/tests/resources.rs +++ b/tests/resources.rs @@ -1,16 +1,17 @@ //! Integration test about setting resources using `apply()` -use cgroups::pid::{PidController, PidMax}; -use cgroups::{Cgroup, PidResources, Resources}; +use cgroups::pid::{PidController}; +use cgroups::{Cgroup, Hierarchy, MaxValue, PidResources, Resources}; #[test] fn pid_resources() { - let hier = cgroups::hierarchies::V1::new(); - let cg = Cgroup::new(&hier, String::from("pid_resources")); + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("pid_resources")); { let res = Resources { pid: PidResources { update_values: true, - maximum_number_of_processes: PidMax::Value(512), + maximum_number_of_processes: MaxValue::Value(512), }, ..Default::default() }; @@ -20,7 +21,7 @@ fn pid_resources() { let pidcontroller: &PidController = cg.controller_of().unwrap(); let pid_max = pidcontroller.get_pid_max(); assert_eq!(pid_max.is_ok(), true); - assert_eq!(pid_max.unwrap(), PidMax::Value(512)); + assert_eq!(pid_max.unwrap(), MaxValue::Value(512)); } cg.delete(); } From 704db324aece8c18e96798388e8a81b096955cc3 Mon Sep 17 00:00:00 2001 From: bin liu Date: Tue, 1 Sep 2020 00:01:28 +0800 Subject: [PATCH 06/71] fix: create all dirs Signed-off-by: bin liu --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index f1133300..419263b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -233,7 +233,7 @@ impl Controller for T where T: ControllerInternal { fn create(&self) { self.verify_path().expect("path should be valid"); - match ::std::fs::create_dir(self.get_path()) { + match ::std::fs::create_dir_all(self.get_path()) { Ok(_) => self.post_create(), Err(e) => warn!("error create_dir {:?}", e), } From c623dc3fbab8fa0b5a4f6b844debcfddf93ef9a2 Mon Sep 17 00:00:00 2001 From: bin liu Date: Wed, 2 Sep 2020 22:03:11 +0800 Subject: [PATCH 07/71] add basic v2 cpu/memory functions Signed-off-by: bin liu --- src/cgroup.rs | 62 +++++++++++++++++++++++++++++++++----- src/cpu.rs | 47 ++++++++++++++++++++++++++++- src/hierarchies.rs | 75 ++++++++++++++++++++++++++++++---------------- src/lib.rs | 41 ++++++++++++++++++------- src/memory.rs | 57 ++++++++++++++++++++++++++++++----- src/pid.rs | 4 +-- tests/cgroup.rs | 25 +++++++++++++++- 7 files changed, 256 insertions(+), 55 deletions(-) diff --git a/src/cgroup.rs b/src/cgroup.rs index dd424efb..0cf1ba4e 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -4,6 +4,7 @@ use crate::error::*; use crate::{CgroupPid, ControllIdentifier, Controller, Hierarchy, Resources, Subsystem}; +use std::collections::HashMap; use std::convert::From; use std::fs; use std::path::{Path, PathBuf}; @@ -41,6 +42,10 @@ impl<'b> Cgroup<'b> { } } + pub fn v2(&self) -> bool { + self.hier.v2() + } + /// Create a new control group in the hierarchy `hier`, with name `path`. /// /// Returns a handle to the control group that can be used to manipulate it. @@ -79,6 +84,42 @@ impl<'b> Cgroup<'b> { cg } + pub fn new_with_prefix>(hier: Box<&'b dyn Hierarchy>, path: P, prefixes: HashMap) -> Cgroup<'b> { + let cg = Cgroup::load_with_prefix(hier, path, prefixes); + cg.create(); + cg + } + + pub fn load_with_prefix>(hier: Box<&'b dyn Hierarchy>, path: P, prefixes: HashMap) -> Cgroup<'b> { + let path = path.as_ref(); + let mut subsystems = hier.subsystems(); + if path.as_os_str() != "" { + subsystems = subsystems + .into_iter() + .map(|x| { + let cn = x.controller_name(); + if prefixes.contains_key(&cn) { + let prefix = prefixes.get(&cn).unwrap(); + let valid_path = prefix.trim_start_matches("/").to_string(); + let mut p = PathBuf::from(valid_path); + p.push(path); + x.enter(p.as_ref()) + }else { + x.enter(path) + } + }) + .collect::>(); + } + + let cg = Cgroup { + subsystems: subsystems, + hier: hier, + path: path.to_str().unwrap().to_string(), + }; + + cg + } + /// The list of subsystems that this control group supports. pub fn subsystems(&self) -> &Vec { &self.subsystems @@ -175,6 +216,16 @@ impl<'b> Cgroup<'b> { pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; +fn enable_controllers(controllers: &Vec, path: &PathBuf) { + let mut f = path.clone(); + f.push("cgroup.subtree_control"); + for c in controllers{ + let body = format!("+{}", c); + // FIXME set mode to 0644 + let _rest = fs::write(f.as_path(), body.as_bytes()); + } +} + fn supported_controllers(p: &PathBuf) -> Vec{ let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers"); let ret = fs::read_to_string(p.as_str()); @@ -186,6 +237,9 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { let controllers = supported_controllers(&root); let mut fp = root; + // enable for root + enable_controllers(&controllers, &fp); + // path: "a/b/c" let elements = path.split("/").collect::>(); let last_index = elements.len() - 1 ; @@ -203,13 +257,7 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { if i < last_index { // enable controllers for substree - let mut f = fp.clone(); - f.push("cgroup.subtree_control"); - for c in &controllers{ - let body = format!("+{}", c); - // FIXME set mode to 0644 - let _rest = fs::write(f.as_path(), body.as_bytes()); - } + enable_controllers(&controllers, &fp); } } diff --git a/src/cpu.rs b/src/cpu.rs index ae48c1cd..d816a58e 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -149,7 +149,12 @@ impl CpuController { /// `shares` to `200` ensures that control group `B` receives twice as much as CPU bandwidth. /// (Assuming both `A` and `B` are of the same parent) pub fn set_shares(&self, shares: u64) -> Result<()> { - self.open_path("cpu.shares", true).and_then(|mut file| { + let mut file = "cpu.shares"; + if self.v2 { + file = "cpu.weight"; + } + // NOTE: .CpuShares is not used here. Conversion is the caller's responsibility. + self.open_path(file, true).and_then(|mut file| { file.write_all(shares.to_string().as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) }) @@ -194,4 +199,44 @@ impl CpuController { self.open_path("cpu.cfs_quota_us", false) .and_then(read_u64_from) } + + pub fn set_cfs_quota_and_period(&self, quota: u64, period: u64) -> Result<()> { + if !self.v2 { + self.set_cfs_quota(quota)?; + return self.set_cfs_period(period); + } + let mut line = "max".to_string(); + if quota > 0 { + line = quota.to_string(); + } + + let mut p = period; + if period == 0 { + // This default value is documented in + // https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html + p = 100000 + } + line = format!("{} {}", line, p); + self.open_path("cpu.max", true) + .and_then(|mut file| { + file.write_all(line.as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) + } + + pub fn set_rt_runtime(&self, us: i64) -> Result<()> { + self.open_path("cpu.rt_runtime_us", true) + .and_then(|mut file| { + file.write_all(us.to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) + } + + pub fn set_rt_period_us(&self, us: u64) -> Result<()> { + self.open_path("cpu.rt_period_us", true) + .and_then(|mut file| { + file.write_all(us.to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) + } } diff --git a/src/hierarchies.rs b/src/hierarchies.rs index f99fd3fd..4853b7c0 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -70,7 +70,7 @@ impl Hierarchy for V1 { subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); } if self.check_support(Controllers::BlkIo) { - subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), true))); + subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), false))); } if self.check_support(Controllers::PerfEvent) { subs.push(Subsystem::PerfEvent(PerfEventController::new(self.root()))); @@ -125,7 +125,6 @@ impl Hierarchy for V2 { } let controllers = ret.unwrap().trim().to_string(); - println!("controllers: {:?}", controllers); let controller_list: Vec<&str> = controllers.split(' ').collect(); @@ -140,30 +139,30 @@ impl Hierarchy for V2 { } } - if self.check_support(Controllers::CpuAcct) { - subs.push(Subsystem::CpuAcct(CpuAcctController::new(self.root()))); - } - if self.check_support(Controllers::Devices) { - subs.push(Subsystem::Devices(DevicesController::new(self.root()))); - } - if self.check_support(Controllers::Freezer) { - subs.push(Subsystem::Freezer(FreezerController::new(self.root()))); - } - if self.check_support(Controllers::NetCls) { - subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); - } - if self.check_support(Controllers::PerfEvent) { - subs.push(Subsystem::PerfEvent(PerfEventController::new(self.root()))); - } - if self.check_support(Controllers::NetPrio) { - subs.push(Subsystem::NetPrio(NetPrioController::new(self.root()))); - } - if self.check_support(Controllers::HugeTlb) { - subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root(), true))); - } - if self.check_support(Controllers::Rdma) { - subs.push(Subsystem::Rdma(RdmaController::new(self.root()))); - } + // if self.check_support(Controllers::CpuAcct) { + // subs.push(Subsystem::CpuAcct(CpuAcctController::new(self.root()))); + // } + // if self.check_support(Controllers::Devices) { + // subs.push(Subsystem::Devices(DevicesController::new(self.root()))); + // } + // if self.check_support(Controllers::Freezer) { + // subs.push(Subsystem::Freezer(FreezerController::new(self.root()))); + // } + // if self.check_support(Controllers::NetCls) { + // subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); + // } + // if self.check_support(Controllers::PerfEvent) { + // subs.push(Subsystem::PerfEvent(PerfEventController::new(self.root()))); + // } + // if self.check_support(Controllers::NetPrio) { + // subs.push(Subsystem::NetPrio(NetPrioController::new(self.root()))); + // } + // if self.check_support(Controllers::HugeTlb) { + // subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root(), true))); + // } + // if self.check_support(Controllers::Rdma) { + // subs.push(Subsystem::Rdma(RdmaController::new(self.root()))); + // } subs } @@ -205,6 +204,7 @@ impl V2 { pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; +#[cfg(all(target_os = "linux", not(target_env = "musl")))] pub fn is_cgroup2_unified_mode() -> bool { let path = Path::new(UNIFIED_MOUNTPOINT); let fs_stat = statfs::statfs(path); @@ -212,9 +212,32 @@ pub fn is_cgroup2_unified_mode() -> bool { return false } + // FIXME notwork, nix will not compile CGROUP2_SUPER_MAGIC because not(target_env = "musl") fs_stat.unwrap().filesystem_type() == statfs::CGROUP2_SUPER_MAGIC } +pub const INIT_CGROUP_PATHS: &'static str = "/proc/1/cgroup"; + +#[cfg(all(target_os = "linux", target_env = "musl"))] +pub fn is_cgroup2_unified_mode() -> bool { + let lines = fs::read_to_string(INIT_CGROUP_PATHS); + if lines.is_err() { + return false + } + + for line in lines.unwrap().lines(){ + let fields: Vec<&str> = line.split(':').collect(); + if fields.len() != 3 { + continue; + } + if fields[0] != "0" { + return false; + } + } + + true +} + pub fn auto() -> Box { if is_cgroup2_unified_mode() { Box::new(V2::new()) diff --git a/src/lib.rs b/src/lib.rs index 419263b4..00e8e426 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -231,7 +231,7 @@ impl Controller for T where T: ControllerInternal { /// Create this controller fn create(&self) { - self.verify_path().expect("path should be valid"); + self.verify_path().expect(format!("path should be valid: {:?}", self.path()).as_str()); match ::std::fs::create_dir_all(self.get_path()) { Ok(_) => self.post_create(), @@ -253,7 +253,11 @@ impl Controller for T where T: ControllerInternal { /// Attach a task to this controller. fn add_task(&self, pid: &CgroupPid) -> Result<()> { - self.open_path("tasks", true).and_then(|mut file| { + let mut file = "tasks"; + if self.is_v2() { + file = "cgroup.procs"; + } + self.open_path(file, true).and_then(|mut file| { file.write_all(pid.pid.to_string().as_ref()) .map_err(|e| Error::with_cause(ErrorKind::WriteFailed, e)) }) @@ -261,7 +265,11 @@ impl Controller for T where T: ControllerInternal { /// Get the list of tasks that this controller has. fn tasks(&self) -> Vec { - self.open_path("tasks", false) + let mut file = "tasks"; + if self.is_v2() { + file = "cgroup.procs"; + } + self.open_path(file, false) .and_then(|file| { let bf = BufReader::new(file); let mut v = Vec::new(); @@ -608,6 +616,10 @@ impl Subsystem { Subsystem::Rdma(cont) => cont, } } + + fn controller_name(&self) -> String { + self.to_controller().control_type().to_string() + } } @@ -627,6 +639,22 @@ impl Default for MaxValue { } } +impl MaxValue { + fn to_i64(&self) -> i64 { + match self { + MaxValue::Max => -1, + MaxValue::Value(num) => *num, + } + } + + fn to_string(&self) -> String { + match self { + MaxValue::Max => "max".to_string(), + MaxValue::Value(num) => num.to_string(), + } + } +} + pub fn parse_max_value(s: &String) -> Result { if s.trim() == "max" { return Ok(MaxValue::Max) @@ -636,10 +664,3 @@ pub fn parse_max_value(s: &String) -> Result { Err(e) => Err(Error::with_cause(ParseError, e)), } } - -pub fn max_value_to_string(m: MaxValue) -> String { - match m { - MaxValue::Max => "max".to_string(), - MaxValue::Value(num) => num.to_string(), - } -} \ No newline at end of file diff --git a/src/memory.rs b/src/memory.rs index 8793459e..32f2b074 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -13,11 +13,9 @@ use crate::error::*; use crate::events; use crate::{ - ControllIdentifier, ControllerInternal, Controllers, MemoryResources, Resources, Subsystem, + ControllIdentifier, ControllerInternal, Controllers, MaxValue, MemoryResources, Resources, Subsystem, }; -use crate::{MaxValue, max_value_to_string, parse_max_value}; - /// A controller that allows controlling the `memory` subsystem of a Cgroup. /// /// In essence, using the memory controller, the user can gather statistics about the memory usage @@ -481,8 +479,7 @@ impl MemController { let v = value.0; let f = value.1; if v.is_some() { - let v = v.unwrap(); - let v = max_value_to_string(v); + let v = v.unwrap().to_string(); self.open_path(f, true) .and_then(|mut file| { file.write_all(v.as_ref()) @@ -504,12 +501,44 @@ impl MemController { Ok(m) } + fn memory_stat_v2(&self) -> Memory { + let set = self.get_mem().unwrap(); + + Memory { + fail_cnt: 0, + limit_in_bytes: set.max.unwrap().to_i64(), + usage_in_bytes: self + .open_path("memory.current", false) + .and_then(read_u64_from) + .unwrap_or(0), + max_usage_in_bytes: 0, + move_charge_at_immigrate: 0, + numa_stat: NumaStat::default(), + oom_control: OomControl::default(), + soft_limit_in_bytes: set.high.unwrap().to_i64(), + stat: self + .open_path("memory.stat", false) + .and_then(read_string_from) + .and_then(parse_memory_stat) + .unwrap_or(MemoryStat::default()), + swappiness: self + .open_path("memory.swap.current", false) + .and_then(read_u64_from) + .unwrap_or(0), + use_hierarchy: 0, + } + } + /// Gathers overall statistics (and the current state of) about the memory usage of the control /// group's tasks. /// /// See the individual fields for more explanation, and as always, remember to consult the /// kernel Documentation and/or sources. pub fn memory_stat(&self) -> Memory { + if self.v2 { + return self.memory_stat_v2(); + } + Memory { fail_cnt: self .open_path("memory.failcnt", false) @@ -670,7 +699,11 @@ impl MemController { /// Set the memory usage limit of the control group, in bytes. pub fn set_limit(&self, limit: i64) -> Result<()> { - self.open_path("memory.limit_in_bytes", true) + let mut file = "memory.limit_in_bytes"; + if self.v2 { + file = "memory.max"; + } + self.open_path(file, true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) @@ -688,7 +721,11 @@ impl MemController { /// Set the memory+swap limit of the control group, in bytes. pub fn set_memswap_limit(&self, limit: i64) -> Result<()> { - self.open_path("memory.memsw.limit_in_bytes", true) + let mut file = "memory.memsw.limit_in_bytes"; + if self.v2 { + file = "memory.swap.max"; + } + self.open_path(file, true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) @@ -709,7 +746,11 @@ impl MemController { /// This limit is enforced when the system is nearing OOM conditions. Contrast this with the /// hard limit, which is _always_ enforced. pub fn set_soft_limit(&self, limit: i64) -> Result<()> { - self.open_path("memory.soft_limit_in_bytes", true) + let mut file = "memory.soft_limit_in_bytes"; + if self.v2 { + file = "memory.low" + } + self.open_path(file, true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) diff --git a/src/pid.rs b/src/pid.rs index 3be3da0d..4eb6754e 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -10,7 +10,7 @@ use crate::error::*; use crate::error::ErrorKind::*; use crate::{ - ControllIdentifier, ControllerInternal, Controllers, MaxValue, max_value_to_string, parse_max_value, PidResources, Resources, Subsystem, + ControllIdentifier, ControllerInternal, Controllers, MaxValue, parse_max_value, PidResources, Resources, Subsystem, }; /// A controller that allows controlling the `pids` subsystem of a Cgroup. @@ -150,7 +150,7 @@ impl PidController { /// extra processes to a control group disregards the limit. pub fn set_pid_max(&self, max_pid: MaxValue) -> Result<()> { self.open_path("pids.max", true).and_then(|mut file| { - let string_to_write = max_value_to_string(max_pid); + let string_to_write = max_pid.to_string(); match file.write_all(string_to_write.as_ref()) { Ok(_) => Ok(()), Err(e) => Err(Error::with_cause(WriteFailed, e)), diff --git a/tests/cgroup.rs b/tests/cgroup.rs index 177eea30..1f5efbdc 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -1,5 +1,7 @@ //! Simple unit tests about the control groups system. -use cgroups::{Cgroup, CgroupPid, Hierarchy}; +use cgroups::{Cgroup, CgroupPid, Hierarchy, Subsystem}; +use cgroups::memory::{MemController, SetMemory}; +use std::collections::HashMap; #[test] fn test_tasks_iterator() { @@ -24,3 +26,24 @@ fn test_tasks_iterator() { } cg.delete(); } + + +#[test] +fn test_cgroup_with_prefix() { + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let mut prefixes = HashMap::new(); + prefixes.insert("memory".to_string(), "/memory/abc/def".to_string()); + let cg = Cgroup::new_with_prefix(h, String::from("test_cgroup_with_prefix"), prefixes); + { + let subsystems = cg.subsystems(); + println!("mem path: {:?}", &subsystems); + subsystems.into_iter().for_each(|sub| match sub { + Subsystem::Pid(c) => {println!("path {:?}", c);}, + // base: "/sys/fs/cgroup", path: "/sys/fs/cgroup/memory/abc/def/test_cgroup_with_prefix" + Subsystem::Mem(c) => {println!("path {:?}", c);}, + _ => {}, + }); + } + cg.delete(); +} From cd2c748a74f5a0ce32889fe44696fa148c65b94b Mon Sep 17 00:00:00 2001 From: bin liu Date: Fri, 4 Sep 2020 22:42:49 +0800 Subject: [PATCH 08/71] add systemd controller; add more tests; update blkio stat for v2 Signed-off-by: bin liu --- Cargo.toml | 1 + src/blkio.rs | 149 +++++++++++++++++++++++++++++++++++++----- src/cgroup.rs | 63 +++++++++++++----- src/cgroup_builder.rs | 21 +++--- src/cpu.rs | 7 +- src/cpuset.rs | 79 +++++++++++----------- src/events.rs | 2 +- src/freezer.rs | 37 +++++++++-- src/hierarchies.rs | 40 +++--------- src/hugetlb.rs | 28 +++++++- src/lib.rs | 103 +++++++++++++++++++++++++++-- src/memory.rs | 28 +++++++- src/systemd.rs | 72 ++++++++++++++++++++ tests/builder.rs | 13 ++-- tests/cgroup.rs | 60 ++++++++++++++--- tests/cpuset.rs | 56 +++++++++++++--- tests/devices.rs | 5 ++ tests/hugetlb.rs | 5 ++ tests/pids.rs | 6 +- 19 files changed, 619 insertions(+), 156 deletions(-) create mode 100644 src/systemd.rs diff --git a/Cargo.toml b/Cargo.toml index 6c99a682..156a69ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ edition = "2018" log = "0.4" regex = "1.1" nix = "0.18.0" +libc = "0.2" [dev-dependencies] libc = "0.2.76" diff --git a/src/blkio.rs b/src/blkio.rs index 97464bd3..6ef41481 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -54,6 +54,28 @@ pub struct IoService { pub total: u64, } +#[derive(Eq, PartialEq, Debug)] +/// Per-device activity from the control group. +/// Only for cgroup v2 +pub struct IoStat { + /// The major number of the device. + pub major: i16, + /// The minor number of the device. + pub minor: i16, + /// How many bytes were read from the device. + pub rbytes: u64, + /// How many bytes were written to the device. + pub wbytes: u64, + /// How many iops were read from the device. + pub rios: u64, + /// How many iops were written to the device. + pub wios: u64, + /// How many discard bytes were read from the device. + pub dbytes: u64, + /// How many discard iops were written to the device. + pub dios: u64, +} + fn parse_io_service(s: String) -> Result> { s.lines() .filter(|x| x.split_whitespace().collect::>().len() == 3) @@ -95,6 +117,40 @@ fn parse_io_service(s: String) -> Result> { }) } +fn get_value(s: &str) -> String { + let arr = s.split(':').collect::>(); + if arr.len() != 2 { + return "0".to_string(); + } + arr[1].to_string() +} + +fn parse_io_stat(s: String) -> Result> { + // line: + // 8:0 rbytes=180224 wbytes=0 rios=3 wios=0 dbytes=0 dios=0 + let v = s.lines() + .filter(|x| x.split_whitespace().collect::>().len() == 7) + .map(|x| { + let arr = x.split_whitespace().collect::>(); + let device = arr[0].split(":").collect::>(); + let (major, minor) = (device[0], device[1]); + + IoStat { + major: major.parse::().unwrap(), + minor: minor.parse::().unwrap(), + rbytes: get_value(arr[1]).parse::().unwrap(), + wbytes: get_value(arr[2]).parse::().unwrap(), + rios: get_value(arr[3]).parse::().unwrap(), + wios: get_value(arr[4]).parse::().unwrap(), + dbytes: get_value(arr[5]).parse::().unwrap(), + dios: get_value(arr[6]).parse::().unwrap(), + } + }) + .collect::>(); + + Ok(v) +} + fn parse_io_service_total(s: String) -> Result { s.lines() .filter(|x| x.split_whitespace().collect::>().len() == 2) @@ -142,7 +198,7 @@ fn parse_blkio_data(s: String) -> Result> { /// Current state and statistics about how throttled are the block devices when accessed from the /// controller's control group. -#[derive(Debug)] +#[derive(Default, Debug)] pub struct BlkIoThrottle { /// Statistics about the bytes transferred between the block devices by the tasks in this /// control group. @@ -177,7 +233,7 @@ pub struct BlkIoThrottle { } /// Statistics and state of the block devices. -#[derive(Debug)] +#[derive(Default, Debug)] pub struct BlkIo { /// The number of BIOS requests merged into I/O requests by the control group's tasks. pub io_merged: Vec, @@ -254,6 +310,9 @@ pub struct BlkIo { pub weight: u64, /// Same as `weight`, but per-block-device. pub weight_device: Vec, + + /// IoStat for cgroup v2 + pub io_stat: Vec, } impl ControllerInternal for BlkIoController { @@ -279,12 +338,20 @@ impl ControllerInternal for BlkIoController { let res: &BlkIoResources = &res.blkio; if res.update_values { - let _ = self.set_weight(res.weight as u64); - let _ = self.set_leaf_weight(res.leaf_weight as u64); + if res.weight.is_some() { + let _ = self.set_weight(res.weight.unwrap() as u64); + } + if res.leaf_weight.is_some() { + let _ = self.set_leaf_weight(res.leaf_weight.unwrap() as u64); + } for dev in &res.weight_device { - let _ = self.set_weight_for_device(dev.major, dev.minor, dev.weight as u64); - let _ = self.set_leaf_weight_for_device(dev.major, dev.minor, dev.leaf_weight as u64); + if dev.weight.is_some(){ + let _ = self.set_weight_for_device(dev.major, dev.minor, dev.weight.unwrap() as u64); + } + if dev.leaf_weight.is_some(){ + let _ = self.set_leaf_weight_for_device(dev.major, dev.minor, dev.leaf_weight.unwrap() as u64); + } } for dev in &res.throttle_read_bps_device { @@ -358,9 +425,23 @@ impl BlkIoController { } } + fn blkio_v2(&self) -> BlkIo { + let mut blkio: BlkIo = Default::default(); + blkio.io_stat = self + .open_path("io.stat", false) + .and_then(read_string_from) + .and_then(parse_io_stat) + .unwrap_or(Vec::new()); + + blkio + } + /// Gathers statistics about and reports the state of the block devices used by the control /// group's tasks. pub fn blkio(&self) -> BlkIo { + if self.v2 { + return self.blkio_v2(); + } BlkIo { io_merged: self .open_path("blkio.io_merged", false) @@ -582,6 +663,7 @@ impl BlkIoController { .and_then(read_string_from) .and_then(parse_blkio_data) .unwrap_or(Vec::new()), + io_stat: Vec::new(), } } @@ -626,9 +708,15 @@ impl BlkIoController { minor: u64, bps: u64, ) -> Result<()> { - self.open_path("blkio.throttle.read_bps_device", true) + let mut file = "blkio.throttle.read_bps_device"; + let mut content = format!("{}:{} {}", major, minor, bps); + if self.v2 { + file = "io.max"; + content = format!("{}:{} rbps={}", major, minor, bps); + } + self.open_path(file, true) .and_then(|mut file| { - file.write_all(format!("{}:{} {}", major, minor, bps).to_string().as_ref()) + file.write_all(content.as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) }) } @@ -641,9 +729,15 @@ impl BlkIoController { minor: u64, iops: u64, ) -> Result<()> { - self.open_path("blkio.throttle.read_iops_device", true) + let mut file = "blkio.throttle.read_iops_device"; + let mut content = format!("{}:{} {}", major, minor, iops); + if self.v2 { + file = "io.max"; + content = format!("{}:{} riops={}", major, minor, iops); + } + self.open_path(file, true) .and_then(|mut file| { - file.write_all(format!("{}:{} {}", major, minor, iops).to_string().as_ref()) + file.write_all(content.as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) }) } @@ -655,9 +749,15 @@ impl BlkIoController { minor: u64, bps: u64, ) -> Result<()> { - self.open_path("blkio.throttle.write_bps_device", true) + let mut file = "blkio.throttle.write_bps_device"; + let mut content = format!("{}:{} {}", major, minor, bps); + if self.v2 { + file = "io.max"; + content = format!("{}:{} wbps={}", major, minor, bps); + } + self.open_path(file, true) .and_then(|mut file| { - file.write_all(format!("{}:{} {}", major, minor, bps).to_string().as_ref()) + file.write_all(content.as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) }) } @@ -670,16 +770,27 @@ impl BlkIoController { minor: u64, iops: u64, ) -> Result<()> { - self.open_path("blkio.throttle.write_iops_device", true) + let mut file = "blkio.throttle.write_iops_device"; + let mut content = format!("{}:{} {}", major, minor, iops); + if self.v2 { + file = "io.max"; + content = format!("{}:{} riops={}", major, minor, iops); + } + self.open_path(file, true) .and_then(|mut file| { - file.write_all(format!("{}:{} {}", major, minor, iops).to_string().as_ref()) + file.write_all(content.as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) }) } /// Set the weight of the control group's tasks. pub fn set_weight(&self, w: u64) -> Result<()> { - self.open_path("blkio.weight", true) + // FIXME: not find in high kernel version. + let mut file = "blkio.weight"; + if self.v2 { + file = "io.bfq.weight"; + } + self.open_path(file, true) .and_then(|mut file| { file.write_all(w.to_string().as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) @@ -693,7 +804,13 @@ impl BlkIoController { minor: u64, weight: u64, ) -> Result<()> { - self.open_path("blkio.weight_device", true) + let mut file = "blkio.weight_device"; + if self.v2 { + // FIXME why is there no weight for device in runc ? + // https://github.com/opencontainers/runc/blob/46be7b612e2533c494e6a251111de46d8e286ed5/libcontainer/cgroups/fs2/io.go#L30 + file = "io.bfq.weight"; + } + self.open_path(file, true) .and_then(|mut file| { file.write_all(format!("{}:{} {}", major, minor, weight).as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) diff --git a/src/cgroup.rs b/src/cgroup.rs index 0cf1ba4e..429681a3 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -2,6 +2,8 @@ use crate::error::*; +use crate::libc_rmdir; + use crate::{CgroupPid, ControllIdentifier, Controller, Hierarchy, Resources, Subsystem}; use std::collections::HashMap; @@ -84,13 +86,13 @@ impl<'b> Cgroup<'b> { cg } - pub fn new_with_prefix>(hier: Box<&'b dyn Hierarchy>, path: P, prefixes: HashMap) -> Cgroup<'b> { - let cg = Cgroup::load_with_prefix(hier, path, prefixes); + pub fn new_with_relative_paths>(hier: Box<&'b dyn Hierarchy>, path: P, relative_paths: HashMap) -> Cgroup<'b> { + let cg = Cgroup::load_with_relative_paths(hier, path, relative_paths); cg.create(); cg } - pub fn load_with_prefix>(hier: Box<&'b dyn Hierarchy>, path: P, prefixes: HashMap) -> Cgroup<'b> { + pub fn load_with_relative_paths>(hier: Box<&'b dyn Hierarchy>, path: P, relative_paths: HashMap) -> Cgroup<'b> { let path = path.as_ref(); let mut subsystems = hier.subsystems(); if path.as_os_str() != "" { @@ -98,13 +100,13 @@ impl<'b> Cgroup<'b> { .into_iter() .map(|x| { let cn = x.controller_name(); - if prefixes.contains_key(&cn) { - let prefix = prefixes.get(&cn).unwrap(); - let valid_path = prefix.trim_start_matches("/").to_string(); + if relative_paths.contains_key(&cn) { + let rp = relative_paths.get(&cn).unwrap(); + let valid_path = rp.trim_start_matches("/").to_string(); let mut p = PathBuf::from(valid_path); p.push(path); x.enter(p.as_ref()) - }else { + } else { x.enter(path) } }) @@ -132,6 +134,13 @@ impl<'b> Cgroup<'b> { /// actually removed, and remove the descendants first if not. In the future, this behavior /// will change. pub fn delete(self) { + if self.v2() { + let mut p = self.hier.root().clone(); + p.push(self.path); + libc_rmdir(p.to_str().unwrap()); + return + } + self.subsystems.into_iter().for_each(|sub| match sub { Subsystem::Pid(pidc) => pidc.delete(), Subsystem::Mem(c) => c.delete(), @@ -146,6 +155,7 @@ impl<'b> Cgroup<'b> { Subsystem::NetPrio(c) => c.delete(), Subsystem::HugeTlb(c) => c.delete(), Subsystem::Rdma(c) => c.delete(), + Subsystem::Systemd(c) => c.delete(), }); } @@ -191,23 +201,44 @@ impl<'b> Cgroup<'b> { /// Attach a task to the control group. pub fn add_task(&self, pid: CgroupPid) -> Result<()> { - self.subsystems() + if self.v2() { + let subsystems = self.subsystems(); + if subsystems.len() > 0 { + let c = subsystems[0].to_controller(); + c.add_task(&pid) + } else{ + Ok(()) + } + } else { + self.subsystems() .iter() .try_for_each(|sub| sub.to_controller().add_task(&pid)) + } } /// Returns an Iterator that can be used to iterate over the tasks that are currently in the /// control group. pub fn tasks(&self) -> Vec { // Collect the tasks from all subsystems - let mut v = self - .subsystems() - .iter() - .map(|x| x.to_controller().tasks()) - .fold(vec![], |mut acc, mut x| { - acc.append(&mut x); - acc - }); + let mut v = if self.v2() { + let subsystems = self.subsystems(); + if subsystems.len() > 0 { + let c = subsystems[0].to_controller(); + c.tasks() + } else { + vec![] + } + } else { + self + .subsystems() + .iter() + .map(|x| x.to_controller().tasks()) + .fold(vec![], |mut acc, mut x| { + acc.append(&mut x); + acc + }) + }; + v.sort(); v.dedup(); v diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index f6a7f2cd..1b4293ba 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -13,8 +13,9 @@ //! # use cgroups::*; //! # use cgroups::devices::*; //! # use cgroups::cgroup_builder::*; -//! let v1 = cgroups::hierarchies::V1::new(); -//! let cgroup: Cgroup = CgroupBuilder::new("hello", &v1) +//! let h = cgroups::hierarchies::auto(); +//! let h = Box::new(&*h); +//! let cgroup: Cgroup = CgroupBuilder::new("hello", h) //! .memory() //! .kernel_memory_limit(1024 * 1024) //! .memory_hard_limit(1024 * 1024) @@ -40,10 +41,10 @@ //! .limit("2G".to_string(), 2 * 1024 * 1024 * 1024) //! .done() //! .blkio() -//! .weight(123) -//! .leaf_weight(99) -//! .weight_device(6, 1, 100, 55) -//! .weight_device(6, 1, 100, 55) +//! .weight(Some(123)) +//! .leaf_weight(Some(99)) +//! .weight_device(6, 1, Some(100), Some(55)) +//! .weight_device(6, 1, Some(100), Some(55)) //! .throttle_iops() //! .read(6, 1, 10) //! .write(11, 1, 100) @@ -296,15 +297,15 @@ pub struct BlkIoResourcesBuilder<'a> { impl<'a> BlkIoResourcesBuilder<'a> { - gen_setter!(blkio, BlkIoController, set_weight, weight, u16); - gen_setter!(blkio, BlkIoController, set_leaf_weight, leaf_weight, u16); + gen_setter!(blkio, BlkIoController, set_weight, weight, Option); + gen_setter!(blkio, BlkIoController, set_leaf_weight, leaf_weight, Option); /// Set the weight of a certain device. pub fn weight_device(mut self, major: u64, minor: u64, - weight: u16, - leaf_weight: u16) + weight: Option, + leaf_weight: Option) -> BlkIoResourcesBuilder<'a> { self.cgroup.resources.blkio.update_values = true; self.cgroup.resources.blkio.weight_device.push(BlkIoDeviceResource { diff --git a/src/cpu.rs b/src/cpu.rs index d816a58e..2cbeed0b 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -61,7 +61,6 @@ impl ControllerInternal for CpuController { let res: &CpuResources = &res.cpu; if res.update_values { - // apply pid_max let _ = self.set_shares(res.shares); if self.shares()? != res.shares as u64 { return Err(Error::new(ErrorKind::Other)); @@ -163,7 +162,11 @@ impl CpuController { /// Retrieve the CPU bandwidth that this control group (relative to other control groups and /// this control group's parent) can use. pub fn shares(&self) -> Result { - self.open_path("cpu.shares", false).and_then(read_u64_from) + let mut file = "cpu.shares"; + if self.v2 { + file = "cpu.weight"; + } + self.open_path(file, false).and_then(read_u64_from) } /// Specify a period (when using the CFS scheduler) of time in microseconds for how often this diff --git a/src/cpuset.rs b/src/cpuset.rs index fd2661a5..7b5b7fa3 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -125,54 +125,57 @@ impl ControllerInternal for CpuSetController { }; if current != self.get_base() { - match copy_from_parent(current.to_str().unwrap(), parent.to_str().unwrap()) { + match copy_from_parent(current.to_str().unwrap(), "cpuset.cpus") { Ok(_)=>(), - Err(err) => error!("error create_dir {:?}", err), + Err(err) => error!("error create_dir for cpuset.cpus {:?}", err), + } + match copy_from_parent(current.to_str().unwrap(), "cpuset.mems") { + Ok(_)=>(), + Err(err) => error!("error create_dir for cpuset.mems {:?}", err), } } } } +fn find_no_empty_parent(from: &str, file: &str) -> Result<(String, Vec)> { + let mut current_path = ::std::path::Path::new(from).to_path_buf(); + let mut v = vec![]; + + loop { + let current_value = match ::std::fs::read_to_string(current_path.clone().join(file).to_str().unwrap()) { + Ok(cpus) => String::from(cpus.trim()), + Err(e) => return Err(Error::with_cause(ReadFailed, e)), + }; + + if current_value != "" { + return Ok((current_value, v)); + } + v.push(current_path.clone()); + + let parent = match current_path.parent() { + Some(p) => p, + None => return Ok(("".to_string(), v)), + }; + + // next loop, find parent + current_path = parent.to_path_buf(); + } +} + /// copy_from_parent copy the cpuset.cpus and cpuset.mems from the parent /// directory to the current directory if the file's contents are 0 -fn copy_from_parent(current: &str, parent: &str) -> Result<()> { - let cpus_str: &str = "cpuset.cpus"; - let mems_str: &str = "cpuset.mems"; - - let current_cpus_path = ::std::path::Path::new(current).join(cpus_str); - let current_mems_path = ::std::path::Path::new(current).join(mems_str); - let parent_cpus_path = ::std::path::Path::new(parent).join(cpus_str); - let parent_mems_path = ::std::path::Path::new(parent).join(mems_str); - - let current_cpus = match ::std::fs::read_to_string(current_cpus_path.to_str().unwrap()) { - Ok(cpus) => String::from(cpus.trim()), - Err(e) => return Err(Error::with_cause(ReadFailed, e)), - }; - - let current_mems = match ::std::fs::read_to_string(current_mems_path.to_str().unwrap()) { - Ok(mems) => String::from(mems.trim()), - Err(e) => return Err(Error::with_cause(ReadFailed, e)), - }; - - let parent_cpus = match ::std::fs::read_to_string(parent_cpus_path.to_str().unwrap()) { - Ok(cpus) => cpus, - Err(e) => return Err(Error::with_cause(ReadFailed, e)), - }; - - let parent_mems = match ::std::fs::read_to_string(parent_mems_path.to_str().unwrap()) { - Ok(mems) => mems, - Err(e) => return Err(Error::with_cause(ReadFailed, e)), - }; - - if current_cpus == "" { - match ::std::fs::write(current_cpus_path.to_str().unwrap(), parent_cpus.as_bytes()) { - Ok(_) => (), - Err(e) => return Err(Error::with_cause(WriteFailed, e)), - } +fn copy_from_parent(current: &str, file: &str) -> Result<()> { + // find not empty cpus/memes from current directory. + let (value, parents) = find_no_empty_parent(current, file)?; + + if value == "" || parents.len() == 0 { + return Ok(()); } - if current_mems == "" { - match ::std::fs::write(current_mems_path.to_str().unwrap(), parent_mems.as_bytes()) { + for p in parents.iter().rev() { + let mut pb = p.clone(); + pb.push(file); + match ::std::fs::write(pb.to_str().unwrap(), value.as_bytes()) { Ok(_) => (), Err(e) => return Err(Error::with_cause(WriteFailed, e)), } diff --git a/src/events.rs b/src/events.rs index 3e7ac7dd..0b1576dc 100644 --- a/src/events.rs +++ b/src/events.rs @@ -24,7 +24,7 @@ pub fn notify_on_oom_v1(key: &str, dir: &PathBuf) -> Result> { } // level is one of "low", "medium", or "critical" -fn notify_memory_pressure(key: &str, dir: &PathBuf, level: &str) -> Result> { +pub fn notify_memory_pressure(key: &str, dir: &PathBuf, level: &str) -> Result> { if level != "low" && level != "medium" && level != "critical" { return Err(Error::from_string(format!("invalid pressure level {}", level))); } diff --git a/src/freezer.rs b/src/freezer.rs index 632ee272..59889e57 100644 --- a/src/freezer.rs +++ b/src/freezer.rs @@ -22,6 +22,7 @@ use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subs pub struct FreezerController { base: PathBuf, path: PathBuf, + v2: bool, } /// The current state of the control group @@ -75,40 +76,62 @@ impl<'a> From<&'a Subsystem> for &'a FreezerController { impl FreezerController { /// Contructs a new `FreezerController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { + pub fn new(oroot: PathBuf, v2: bool) -> Self { let mut root = oroot; - root.push(Self::controller_type().to_string()); + if !v2 { + root.push(Self::controller_type().to_string()); + } Self { base: root.clone(), path: root, + v2: v2, } } /// Freezes the processes in the control group. pub fn freeze(&self) -> Result<()> { - self.open_path("freezer.state", true).and_then(|mut file| { - file.write_all("FROZEN".to_string().as_ref()) + let mut file = "freezer.state"; + let mut content = "FROZEN".to_string(); + if self.v2 { + file = "cgroup.freeze"; + content = "1".to_string(); + } + + self.open_path(file, true).and_then(|mut file| { + file.write_all(content.as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) }) } /// Thaws, that is, unfreezes the processes in the control group. pub fn thaw(&self) -> Result<()> { - self.open_path("freezer.state", true).and_then(|mut file| { - file.write_all("THAWED".to_string().as_ref()) + let mut file = "freezer.state"; + let mut content = "THAWED".to_string(); + if self.v2 { + file = "cgroup.freeze"; + content = "0".to_string(); + } + self.open_path(file, true).and_then(|mut file| { + file.write_all(content.as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) }) } /// Retrieve the state of processes in the control group. pub fn state(&self) -> Result { - self.open_path("freezer.state", false).and_then(|mut file| { + let mut file = "freezer.state"; + if self.v2 { + file = "cgroup.freeze"; + } + self.open_path(file, false).and_then(|mut file| { let mut s = String::new(); let res = file.read_to_string(&mut s); match res { Ok(_) => match s.as_ref() { "FROZEN" => Ok(FreezerState::Frozen), "THAWED" => Ok(FreezerState::Thawed), + "1" => Ok(FreezerState::Frozen), + "0" => Ok(FreezerState::Thawed), "FREEZING" => Ok(FreezerState::Freezing), _ => Err(Error::new(ParseError)), }, diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 4853b7c0..8f27ec4d 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -24,6 +24,7 @@ use crate::net_prio::NetPrioController; use crate::perf_event::PerfEventController; use crate::pid::PidController; use crate::rdma::RdmaController; +use crate::systemd::SystemdController; use crate::{Controllers, Hierarchy, Subsystem}; use crate::cgroup::Cgroup; @@ -64,7 +65,7 @@ impl Hierarchy for V1 { subs.push(Subsystem::Devices(DevicesController::new(self.root()))); } if self.check_support(Controllers::Freezer) { - subs.push(Subsystem::Freezer(FreezerController::new(self.root()))); + subs.push(Subsystem::Freezer(FreezerController::new(self.root(), false))); } if self.check_support(Controllers::NetCls) { subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); @@ -84,6 +85,9 @@ impl Hierarchy for V1 { if self.check_support(Controllers::Rdma) { subs.push(Subsystem::Rdma(RdmaController::new(self.root()))); } + if self.check_support(Controllers::Systemd) { + subs.push(Subsystem::Systemd(SystemdController::new(self.root(), false))); + } subs } @@ -116,16 +120,15 @@ impl Hierarchy for V2 { } fn subsystems(&self) -> Vec { - let mut subs = vec![]; - let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers"); let ret = fs::read_to_string(p.as_str()); if ret.is_err() { - return subs; + return vec![]; } - let controllers = ret.unwrap().trim().to_string(); + let mut subs = vec![]; + let controllers = ret.unwrap().trim().to_string(); let controller_list: Vec<&str> = controllers.split(' ').collect(); for s in controller_list { @@ -135,35 +138,12 @@ impl Hierarchy for V2 { "cpuset" => {subs.push(Subsystem::CpuSet(CpuSetController::new(self.root(), true)));}, "memory" => {subs.push(Subsystem::Mem(MemController::new(self.root(), true)));}, "pids" => {subs.push(Subsystem::Pid(PidController::new(self.root(), true)));}, + "freezer" => {subs.push(Subsystem::Freezer(FreezerController::new(self.root(), true)));}, + "hugetlb" => {subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root(), true)));}, _ => {}, } } - // if self.check_support(Controllers::CpuAcct) { - // subs.push(Subsystem::CpuAcct(CpuAcctController::new(self.root()))); - // } - // if self.check_support(Controllers::Devices) { - // subs.push(Subsystem::Devices(DevicesController::new(self.root()))); - // } - // if self.check_support(Controllers::Freezer) { - // subs.push(Subsystem::Freezer(FreezerController::new(self.root()))); - // } - // if self.check_support(Controllers::NetCls) { - // subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); - // } - // if self.check_support(Controllers::PerfEvent) { - // subs.push(Subsystem::PerfEvent(PerfEventController::new(self.root()))); - // } - // if self.check_support(Controllers::NetPrio) { - // subs.push(Subsystem::NetPrio(NetPrioController::new(self.root()))); - // } - // if self.check_support(Controllers::HugeTlb) { - // subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root(), true))); - // } - // if self.check_support(Controllers::Rdma) { - // subs.push(Subsystem::Rdma(RdmaController::new(self.root()))); - // } - subs } diff --git a/src/hugetlb.rs b/src/hugetlb.rs index dcf98faa..80aedf46 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -8,6 +8,7 @@ use std::path::PathBuf; use crate::error::*; use crate::error::ErrorKind::*; +use crate::flat_keyed_to_vec; use crate::{ ControllIdentifier, ControllerInternal, Controllers, HugePageResources, Resources, @@ -118,8 +119,22 @@ impl HugeTlbController { self.sizes.clone() } + fn failcnt_v2(&self, hugetlb_size: &str) -> Result { + self.open_path(&format!("hugetlb.{}.events", hugetlb_size), false) + .and_then(flat_keyed_to_vec) + .and_then(|x| { + if x.len() == 0 { + return Err(Error::from_string(format!("get empty from hugetlb.{}.events", hugetlb_size))); + } + Ok(x[0].1 as u64) + }) + } + /// Check how many times has the limit of `hugetlb_size` hugepages been hit. pub fn failcnt(&self, hugetlb_size: &str) -> Result { + if self.v2 { + return self.failcnt_v2(hugetlb_size); + } self.open_path(&format!("hugetlb.{}.failcnt", hugetlb_size), false) .and_then(read_u64_from) } @@ -134,8 +149,11 @@ impl HugeTlbController { /// Get the current usage of memory that is backed by hugepages of a certain size /// (`hugetlb_size`). pub fn usage_in_bytes(&self, hugetlb_size: &str) -> Result { - self.open_path(&format!("hugetlb.{}.usage_in_bytes", hugetlb_size), false) - .and_then(read_u64_from) + let mut file = format!("hugetlb.{}.usage_in_bytes", hugetlb_size); + if self.v2 { + file = format!("hugetlb.{}.current", hugetlb_size); + } + self.open_path(&file, false).and_then(read_u64_from) } /// Get the maximum observed usage of memory that is backed by hugepages of a certain size @@ -150,7 +168,11 @@ impl HugeTlbController { /// Set the limit (in bytes) of how much memory can be backed by hugepages of a certain size /// (`hugetlb_size`). pub fn set_limit_in_bytes(&self, hugetlb_size: &str, limit: u64) -> Result<()> { - self.open_path(&format!("hugetlb.{}.limit_in_bytes", hugetlb_size), true) + let mut file = format!("hugetlb.{}.limit_in_bytes", hugetlb_size); + if self.v2 { + file = format!("hugetlb.{}.max", hugetlb_size); + } + self.open_path(&file, true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) diff --git a/src/lib.rs b/src/lib.rs index 00e8e426..b4a64d6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ use log::*; +use std::collections::HashMap; use std::fs::File; use std::io::{Read, BufRead, BufReader, Write}; use std::path::{Path, PathBuf}; @@ -21,6 +22,7 @@ pub mod net_prio; pub mod perf_event; pub mod pid; pub mod rdma; +pub mod systemd; pub mod cgroup_builder; use crate::blkio::BlkIoController; @@ -38,6 +40,7 @@ use crate::net_prio::NetPrioController; use crate::perf_event::PerfEventController; use crate::pid::PidController; use crate::rdma::RdmaController; +use crate::systemd::SystemdController; pub use crate::cgroup::Cgroup; @@ -70,6 +73,8 @@ pub enum Subsystem { HugeTlb(HugeTlbController), /// Controller for the `Rdma` subsystem, see `RdmaController` for more information. Rdma(RdmaController), + /// Controller for the `Systemd` subsystem, see `SystemdController` for more information. + Systemd(SystemdController), } #[doc(hidden)] @@ -88,6 +93,7 @@ pub enum Controllers { NetPrio, HugeTlb, Rdma, + Systemd, } impl Controllers { @@ -106,6 +112,7 @@ impl Controllers { Controllers::NetPrio => return "net_prio".to_string(), Controllers::HugeTlb => return "hugetlb".to_string(), Controllers::Rdma => return "rdma".to_string(), + Controllers::Systemd => return "systemd".to_string(), } } } @@ -247,7 +254,7 @@ impl Controller for T where T: ControllerInternal { /// Delete the controller. fn delete(&self) { if self.get_path().exists() { - let _ = ::std::fs::remove_dir(self.get_path()); + libc_rmdir(self.get_path().to_str().unwrap()); } } @@ -452,9 +459,9 @@ pub struct BlkIoDeviceResource { /// The minor number of the device. pub minor: u64, /// The weight of the device against the descendant nodes. - pub weight: u16, + pub weight: Option, /// The weight of the device against the sibling nodes. - pub leaf_weight: u16, + pub leaf_weight: Option, } /// Provides the ability to throttle a device (both byte/sec, and IO op/s) @@ -474,9 +481,9 @@ pub struct BlkIoResources { /// Whether values should be applied to the controller. pub update_values: bool, /// The weight of the control group against descendant nodes. - pub weight: u16, + pub weight: Option, /// The weight of the control group against sibling nodes. - pub leaf_weight: u16, + pub leaf_weight: Option, /// For each device, a separate weight (both normal and leaf) can be provided. pub weight_device: Vec, /// Throttled read bytes/second can be provided for each device. @@ -596,6 +603,11 @@ impl Subsystem { c.get_path_mut().push(path); c }), + Subsystem::Systemd(cont) => Subsystem::Systemd({ + let mut c = cont.clone(); + c.get_path_mut().push(path); + c + }), } } @@ -614,6 +626,7 @@ impl Subsystem { Subsystem::NetPrio(cont) => cont, Subsystem::HugeTlb(cont) => cont, Subsystem::Rdma(cont) => cont, + Subsystem::Systemd(cont) => cont, } } @@ -664,3 +677,83 @@ pub fn parse_max_value(s: &String) -> Result { Err(e) => Err(Error::with_cause(ParseError, e)), } } + +// Flat keyed +// KEY0 VAL0\n +// KEY1 VAL1\n +pub fn flat_keyed_to_vec(mut file: File) -> Result> { + let mut content = String::new(); + file.read_to_string(&mut content).map_err(|e| Error::with_cause(ReadFailed, e))?; + + let mut v = Vec::new(); + for line in content.lines() { + let parts: Vec<&str> = line.split(' ').collect(); + if parts.len() == 2 { + match parts[1].parse::() { + Ok(i) => { v.push((parts[0].to_string(), i)); } , + Err(_) => {}, + } + } + + } + Ok(v) +} + +// Flat keyed +// KEY0 VAL0\n +// KEY1 VAL1\n +pub fn flat_keyed_to_hashmap(mut file: File) -> Result> { + let mut content = String::new(); + file.read_to_string(&mut content).map_err(|e| Error::with_cause(ReadFailed, e))?; + + let mut h = HashMap::new(); + for line in content.lines() { + let parts: Vec<&str> = line.split(' ').collect(); + if parts.len() == 2 { + match parts[1].parse::() { + Ok(i) => { h.insert(parts[0].to_string(), i); } , + Err(_) => {}, + } + } + + } + Ok(h) +} + +// Nested keyed +// KEY0 SUB_KEY0=VAL00 SUB_KEY1=VAL01... +// KEY1 SUB_KEY0=VAL10 SUB_KEY1=VAL11... +pub fn nested_keyed_to_hashmap(mut file: File) -> Result>> { + let mut content = String::new(); + file.read_to_string(&mut content).map_err(|e| Error::with_cause(ReadFailed, e))?; + + let mut h = HashMap::new(); + for line in content.lines() { + let parts: Vec<&str> = line.split(' ').collect(); + if parts.len() == 0 { + continue; + } + let mut th = HashMap::new(); + for item in parts[1..].into_iter() { + let fields: Vec<&str> = item.split('=').collect(); + if fields.len() == 2 { + match fields[1].parse::() { + Ok(i) => { th.insert(fields[0].to_string(), i); } , + Err(_) => {}, + } + } + } + h.insert(parts[0].to_string(), th); + } + + Ok(h) +} + +/// fs::remove_dir_all or fs::remove_dir can't work with cgroup directory sometimes. +/// with error: `Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" }` +pub fn libc_rmdir(p: &str) { + // with int return value + let _ = unsafe { + libc::rmdir(p.as_ptr() as *const i8) + }; +} diff --git a/src/memory.rs b/src/memory.rs index 32f2b074..8f63b9bd 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -12,6 +12,8 @@ use crate::error::ErrorKind::*; use crate::error::*; use crate::events; +use crate::flat_keyed_to_hashmap; + use crate::{ ControllIdentifier, ControllerInternal, Controllers, MaxValue, MemoryResources, Resources, Subsystem, }; @@ -515,7 +517,7 @@ impl MemController { move_charge_at_immigrate: 0, numa_stat: NumaStat::default(), oom_control: OomControl::default(), - soft_limit_in_bytes: set.high.unwrap().to_i64(), + soft_limit_in_bytes: set.low.unwrap().to_i64(), stat: self .open_path("memory.stat", false) .and_then(read_string_from) @@ -639,9 +641,33 @@ impl MemController { } } + pub fn memswap_v2(&self) -> MemSwap { + MemSwap { + fail_cnt: self + .open_path("memory.swap.events", false) + .and_then(flat_keyed_to_hashmap) + .and_then(|x| { + Ok(*x.get("fail").unwrap_or(&0) as u64) + }).unwrap(), + limit_in_bytes: self + .open_path("memory.swap.max", false) + .and_then(read_i64_from) + .unwrap_or(0), + usage_in_bytes: self + .open_path("memory.swap.current", false) + .and_then(read_u64_from) + .unwrap_or(0), + max_usage_in_bytes: 0, + } + } + /// Gathers information about the memory usage of the control group including the swap usage /// (if any). pub fn memswap(&self) -> MemSwap { + if self.v2 { + return self.memswap_v2(); + } + MemSwap { fail_cnt: self .open_path("memory.memsw.failcnt", false) diff --git a/src/systemd.rs b/src/systemd.rs new file mode 100644 index 00000000..5dff8e48 --- /dev/null +++ b/src/systemd.rs @@ -0,0 +1,72 @@ +//! This module contains the implementation of the `systemd` cgroup subsystem. +//! +use std::path::PathBuf; + +use crate::error::*; +use crate::error::ErrorKind::*; + +use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem}; + +/// A controller that allows controlling the `systemd` subsystem of a Cgroup. +/// +#[derive(Debug, Clone)] +pub struct SystemdController { + base: PathBuf, + path: PathBuf, + v2: bool, +} + +impl ControllerInternal for SystemdController { + fn control_type(&self) -> Controllers { + Controllers::Systemd + } + fn get_path(&self) -> &PathBuf { + &self.path + } + fn get_path_mut(&mut self) -> &mut PathBuf { + &mut self.path + } + fn get_base(&self) -> &PathBuf { + &self.base + } + + fn apply(&self, _res: &Resources) -> Result<()> { + Ok(()) + } +} + +impl ControllIdentifier for SystemdController { + fn controller_type() -> Controllers { + Controllers::Systemd + } +} + +impl<'a> From<&'a Subsystem> for &'a SystemdController { + fn from(sub: &'a Subsystem) -> &'a SystemdController { + unsafe { + match sub { + Subsystem::Systemd(c) => c, + _ => { + assert_eq!(1, 0); + ::std::mem::uninitialized() + } + } + } + } +} + +impl SystemdController { + /// Constructs a new `SystemdController` with `oroot` serving as the root of the control group. + pub fn new(oroot: PathBuf, v2: bool) -> Self { + let mut root = oroot; + if !v2{ + root.push(Self::controller_type().to_string()); + } + Self { + base: root.clone(), + path: root, + v2: v2, + } + } + +} diff --git a/tests/builder.rs b/tests/builder.rs index bd3687ca..e44bb5bd 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -42,8 +42,10 @@ pub fn test_memory_res_build() { { let c: &MemController = cg.controller_of().unwrap(); - assert_eq!(c.kmem_stat().limit_in_bytes, 128 * 1024 * 1024); - assert_eq!(c.memory_stat().swappiness, 70); + if !c.v2() { + assert_eq!(c.kmem_stat().limit_in_bytes, 128 * 1024 * 1024); + assert_eq!(c.memory_stat().swappiness, 70); + } assert_eq!(c.memory_stat().limit_in_bytes, 1024 * 1024 * 1024); } @@ -101,7 +103,7 @@ pub fn test_devices_res_build() { pub fn test_network_res_build() { let h = cgroups::hierarchies::auto(); if h.v2() { - // FIXME + // FIXME add cases for v2 return } let h = Box::new(&*h); @@ -123,7 +125,7 @@ pub fn test_network_res_build() { pub fn test_hugepages_res_build() { let h = cgroups::hierarchies::auto(); if h.v2() { - // FIXME + // FIXME add cases for v2 return } let h = Box::new(&*h); @@ -142,12 +144,13 @@ pub fn test_hugepages_res_build() { } #[test] +#[ignore] // high version kernel not support `blkio.weight` pub fn test_blkio_res_build() { let h = cgroups::hierarchies::auto(); let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build", h) .blkio() - .weight(100) + .weight(Some(100)) .done() .build(); diff --git a/tests/cgroup.rs b/tests/cgroup.rs index 1f5efbdc..c5c29496 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -1,6 +1,7 @@ //! Simple unit tests about the control groups system. use cgroups::{Cgroup, CgroupPid, Hierarchy, Subsystem}; use cgroups::memory::{MemController, SetMemory}; +use cgroups::Controller; use std::collections::HashMap; #[test] @@ -11,7 +12,11 @@ fn test_tasks_iterator() { let cg = Cgroup::new(h, String::from("test_tasks_iterator")); { // Add a task to the control group. - cg.add_task(CgroupPid::from(pid)); + cg.add_task(CgroupPid::from(pid)).unwrap(); + + use std::{thread, time}; + thread::sleep(time::Duration::from_millis(100)); + let mut tasks = cg.tasks().into_iter(); // Verify that the task is indeed in the control group assert_eq!(tasks.next(), Some(CgroupPid::from(pid))); @@ -29,21 +34,58 @@ fn test_tasks_iterator() { #[test] -fn test_cgroup_with_prefix() { +fn test_cgroup_with_relative_paths() { + if cgroups::hierarchies::is_cgroup2_unified_mode() { + return + } let h = cgroups::hierarchies::auto(); let h = Box::new(&*h); - let mut prefixes = HashMap::new(); - prefixes.insert("memory".to_string(), "/memory/abc/def".to_string()); - let cg = Cgroup::new_with_prefix(h, String::from("test_cgroup_with_prefix"), prefixes); + let mut relative_paths = HashMap::new(); + relative_paths.insert("memory".to_string(), "/mmm/abc/def".to_string()); + let cg = Cgroup::new_with_relative_paths(h, String::from("test_cgroup_with_prefix"), relative_paths); { let subsystems = cg.subsystems(); - println!("mem path: {:?}", &subsystems); subsystems.into_iter().for_each(|sub| match sub { - Subsystem::Pid(c) => {println!("path {:?}", c);}, - // base: "/sys/fs/cgroup", path: "/sys/fs/cgroup/memory/abc/def/test_cgroup_with_prefix" - Subsystem::Mem(c) => {println!("path {:?}", c);}, + Subsystem::Pid(c) => { + let p = c.path().to_str().unwrap(); + let rel_path = p.trim_start_matches("/sys/fs/cgroup/pids"); + assert_eq!(rel_path, "/test_cgroup_with_prefix") + }, + Subsystem::Mem(c) => { + let p = c.path().to_str().unwrap(); + let rel_path = p.trim_start_matches("/sys/fs/cgroup/memory"); + assert_eq!(rel_path, "/mmm/abc/def/test_cgroup_with_prefix") + }, _ => {}, }); } cg.delete(); } + +#[test] +fn test_cgroup_v2() { + if !cgroups::hierarchies::is_cgroup2_unified_mode() { + return + } + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new_with_relative_paths(h, String::from("test_v2"), HashMap::new()); + + let mem_controller: &MemController = cg.controller_of().unwrap(); + let (mem, swp, rev) = (4 * 1024 * 1000, 2 * 1024* 1000, 1024 * 1000); + + let _ = mem_controller.set_limit(mem); + let _ = mem_controller.set_memswap_limit(swp); + let _ = mem_controller.set_soft_limit(rev); + + let memory_stat = mem_controller.memory_stat(); + println!("memory_stat {:?}", memory_stat); + assert_eq!(mem, memory_stat.limit_in_bytes); + assert_eq!(rev, memory_stat.soft_limit_in_bytes); + + let memswap = mem_controller.memswap(); + println!("memswap {:?}", memswap); + assert_eq!(swp, memswap.limit_in_bytes); + + cg.delete(); +} diff --git a/tests/cpuset.rs b/tests/cpuset.rs index bd7d8a40..aba31636 100644 --- a/tests/cpuset.rs +++ b/tests/cpuset.rs @@ -1,6 +1,8 @@ use cgroups::cpuset::CpuSetController; use cgroups::error::ErrorKind; -use cgroups::{Cgroup, CpuResources, Hierarchy, Resources}; +use cgroups::{Cgroup, CgroupPid, CpuResources, Hierarchy, Resources}; + +use std::fs; #[test] fn test_cpuset_memory_pressure_root_cg() { @@ -27,7 +29,12 @@ fn test_cpuset_set_cpus() { let cpuset: &CpuSetController = cg.controller_of().unwrap(); let set = cpuset.cpuset(); - assert_eq!(0, set.cpus.len()); + if cg.v2() { + assert_eq!(0, set.cpus.len()); + } else { + // for cgroup v1, cpuset is copied from parent. + assert_eq!(true, set.cpus.len() > 0); + } // 0 let r = cpuset.set_cpus("0"); @@ -37,18 +44,47 @@ fn test_cpuset_set_cpus() { assert_eq!(1, set.cpus.len()); assert_eq!((0,0), set.cpus[0]); + // all cpus in system + let cpus = fs::read_to_string("/sys/fs/cgroup/cpuset.cpus.effective").unwrap_or("".to_string()); + let cpus = cpus.trim(); + if cpus != "" { + let r = cpuset.set_cpus(&cpus); + assert_eq!(true, r.is_ok()); + let set = cpuset.cpuset(); + assert_eq!(1, set.cpus.len()); + assert_eq!(format!("{}-{}", set.cpus[0].0, set.cpus[0].1), cpus); + } + } + cg.delete(); +} - // 0-1 - // FIXME need two cores - let r = cpuset.set_cpus("0-1"); - assert_eq!(true, r.is_ok()); +#[test] +fn test_cpuset_set_cpus_add_task() { + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus_add_task/sub-dir")); - let set = cpuset.cpuset(); - assert_eq!(1, set.cpus.len()); - assert_eq!((0,1), set.cpus[0]); + let cpuset: &CpuSetController = cg.controller_of().unwrap(); + let set = cpuset.cpuset(); + if cg.v2() { + assert_eq!(0, set.cpus.len()); + } else { + // for cgroup v1, cpuset is copied from parent. + assert_eq!(true, set.cpus.len() > 0); + } + // Add a task to the control group. + let pid_i = libc::pid_t::from(nix::unistd::getpid()) as u64; + let _ = cg.add_task(CgroupPid::from(pid_i)); + let tasks = cg.tasks(); + assert_eq!(true, tasks.len() > 0); + println!("tasks after added: {:?}", tasks); + // remove task + let _ = cg.remove_task(CgroupPid::from(pid_i)); + let tasks = cg.tasks(); + println!("tasks after deleted: {:?}", tasks); + assert_eq!(0, tasks.len()); - } cg.delete(); } \ No newline at end of file diff --git a/tests/devices.rs b/tests/devices.rs index 891c8a95..e87fa7f5 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -5,6 +5,11 @@ use cgroups::{Cgroup, DeviceResource, Hierarchy}; #[test] fn test_devices_parsing() { + // no only v2 + if cgroups::hierarchies::is_cgroup2_unified_mode() { + return + } + let h = cgroups::hierarchies::auto(); let h = Box::new(&*h); let cg = Cgroup::new(h, String::from("test_devices_parsing")); diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index f7b0afb4..b0a54334 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -8,6 +8,11 @@ use cgroups::error::*; #[test] fn test_hugetlb_sizes() { + // no only v2 + if cgroups::hierarchies::is_cgroup2_unified_mode() { + return + } + let h = cgroups::hierarchies::auto(); let h = Box::new(&*h); let cg = Cgroup::new(h, String::from("test_hugetlb_sizes")); diff --git a/tests/pids.rs b/tests/pids.rs index 74dd7929..ead4c465 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -65,13 +65,13 @@ fn test_pid_events_is_not_zero() { match fork() { Ok(ForkResult::Parent { child, .. }) => { // move the process into the control group - pids.add_task(&(pid_t::from(child) as u64).into()); + let _ = pids.add_task(&(pid_t::from(child) as u64).into()); println!("added task to cg: {:?}", child); // Set limit to one - pids.set_pid_max(MaxValue::Value(1)); - println!("err = {:?}", pids.get_pid_max()); + let _ = pids.set_pid_max(MaxValue::Value(1)); + println!("current pid.max = {:?}", pids.get_pid_max()); // wait on the child let res = waitpid(child, None); From 86b245076c6a20e8d03d282112515061eb524d1f Mon Sep 17 00:00:00 2001 From: bin liu Date: Mon, 7 Sep 2020 20:28:23 +0800 Subject: [PATCH 09/71] add SPDX-License-Identifier for all source Add SPDX-License-Identifier for all existing codes. Fixes: #2 Signed-off-by: bin liu --- src/blkio.rs | 5 +++++ src/cgroup.rs | 5 +++++ src/cgroup_builder.rs | 5 +++++ src/cpu.rs | 5 +++++ src/cpuacct.rs | 5 +++++ src/cpuset.rs | 5 +++++ src/devices.rs | 5 +++++ src/error.rs | 5 +++++ src/freezer.rs | 5 +++++ src/hierarchies.rs | 5 +++++ src/hugetlb.rs | 5 +++++ src/lib.rs | 5 +++++ src/memory.rs | 5 +++++ src/net_cls.rs | 5 +++++ src/net_prio.rs | 5 +++++ src/perf_event.rs | 5 +++++ src/pid.rs | 5 +++++ src/rdma.rs | 5 +++++ tests/builder.rs | 5 +++++ tests/cgroup.rs | 5 +++++ tests/cpuset.rs | 5 +++++ tests/devices.rs | 5 +++++ tests/pids.rs | 5 +++++ tools/create_cgroup.sh | 5 +++++ tools/delete_cgroup.sh | 5 +++++ 25 files changed, 125 insertions(+) diff --git a/src/blkio.rs b/src/blkio.rs index fa55f64e..5e4cf3d9 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `blkio` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/cgroup.rs b/src/cgroup.rs index 140a4f4a..45b47dbd 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module handles cgroup operations. Start here! use crate::error::*; diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index 31999c88..7f5f455b 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module allows the user to create a control group using the Builder pattern. //! # Example //! diff --git a/src/cpu.rs b/src/cpu.rs index 3e43ea8e..c4fc7923 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `cpu` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/cpuacct.rs b/src/cpuacct.rs index ec3b967f..0325723c 100644 --- a/src/cpuacct.rs +++ b/src/cpuacct.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `cpuacct` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/cpuset.rs b/src/cpuset.rs index b7b679a7..12d757a3 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `cpuset` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/devices.rs b/src/devices.rs index 90c386d1..09628c43 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `devices` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/error.rs b/src/error.rs index 70eb4eca..59f3cca0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + use std::error::Error as StdError; use std::fmt; diff --git a/src/freezer.rs b/src/freezer.rs index 632ee272..53e2d9d3 100644 --- a/src/freezer.rs +++ b/src/freezer.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `freezer` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 368251a5..43b7fe90 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module represents the various control group hierarchies the Linux kernel supports. //! //! Currently, we only support the cgroupv1 hierarchy, but in the future we will add support for diff --git a/src/hugetlb.rs b/src/hugetlb.rs index 5c3b1b73..7269b30b 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `hugetlb` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/lib.rs b/src/lib.rs index e6ed6459..15c4ceea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + use log::*; use std::fs::File; diff --git a/src/memory.rs b/src/memory.rs index d7acaf81..0e3e6fbf 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `memory` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/net_cls.rs b/src/net_cls.rs index c3057f96..13a23664 100644 --- a/src/net_cls.rs +++ b/src/net_cls.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `net_cls` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/net_prio.rs b/src/net_prio.rs index 6c2ed7bc..6d4cbe0d 100644 --- a/src/net_prio.rs +++ b/src/net_prio.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `net_prio` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/perf_event.rs b/src/perf_event.rs index 4f52b1be..e7ffe6db 100644 --- a/src/perf_event.rs +++ b/src/perf_event.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `perf_event` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/pid.rs b/src/pid.rs index d7f42d2c..e4c4100c 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `pids` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/src/rdma.rs b/src/rdma.rs index fb9dcc61..0611bb64 100644 --- a/src/rdma.rs +++ b/src/rdma.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `rdma` cgroup subsystem. //! //! See the Kernel's documentation for more information about this subsystem, found at: diff --git a/tests/builder.rs b/tests/builder.rs index 45c11128..05e2919d 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! Some simple tests covering the builder pattern for control groups. use cgroups::*; use cgroups::cpu::*; diff --git a/tests/cgroup.rs b/tests/cgroup.rs index 8b15d9a4..83b5ebed 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! Simple unit tests about the control groups system. use cgroups::{Cgroup, CgroupPid}; diff --git a/tests/cpuset.rs b/tests/cpuset.rs index c7a8fb0c..2f5ff934 100644 --- a/tests/cpuset.rs +++ b/tests/cpuset.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + use cgroups::cpuset::CpuSetController; use cgroups::error::ErrorKind; use cgroups::Cgroup; diff --git a/tests/devices.rs b/tests/devices.rs index 2fbb3058..b79c6268 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! Integration tests about the devices subsystem use cgroups::devices::{DevicePermissions, DeviceType, DevicesController}; diff --git a/tests/pids.rs b/tests/pids.rs index 4c91e54b..0cc0a954 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2018 Levente Kurusa +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! Integration tests about the pids subsystem use cgroups::pid::{PidController, PidMax}; use cgroups::Controller; diff --git a/tools/create_cgroup.sh b/tools/create_cgroup.sh index 49dbfa0c..96407ad3 100755 --- a/tools/create_cgroup.sh +++ b/tools/create_cgroup.sh @@ -1,4 +1,9 @@ #!/bin/sh +# +# Copyright (c) 2018 Levente Kurusa +# +# SPDX-License-Identifier: Apache-2.0 or MIT +# CONTROL_GROUPS=`cargo test -- --list 2>/dev/null | egrep 'test$' | egrep -v '^src' | cut -d':' -f1` diff --git a/tools/delete_cgroup.sh b/tools/delete_cgroup.sh index f3f83a3f..e728cb56 100755 --- a/tools/delete_cgroup.sh +++ b/tools/delete_cgroup.sh @@ -1,4 +1,9 @@ #!/bin/sh +# +# Copyright (c) 2018 Levente Kurusa +# +# SPDX-License-Identifier: Apache-2.0 or MIT +# CONTROL_GROUPS=`cargo test -- --list 2>/dev/null | egrep 'test$' | egrep -v '^src' | cut -d':' -f1` From 5d51e50bec794736e4d6c7e464557cc82480a8fe Mon Sep 17 00:00:00 2001 From: bin liu Date: Mon, 7 Sep 2020 17:50:02 +0800 Subject: [PATCH 10/71] get relative paths at new/load func default. Signed-off-by: bin liu --- src/cgroup.rs | 72 ++++++++++++++++++++++++++++++++----------------- tests/cgroup.rs | 21 +++++++++------ 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/cgroup.rs b/src/cgroup.rs index 429681a3..899195ce 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -1,6 +1,7 @@ //! This module handles cgroup operations. Start here! use crate::error::*; +use crate::error::ErrorKind::*; use crate::libc_rmdir; @@ -37,7 +38,7 @@ impl<'b> Cgroup<'b> { fn create(&self) { if self.hier.v2() { create_v2_cgroup(self.hier.root().clone(), &self.path); - }else{ + } else { for subsystem in &self.subsystems { subsystem.to_controller().create(); } @@ -55,9 +56,8 @@ impl<'b> Cgroup<'b> { /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. pub fn new>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup<'b> { - let cg = Cgroup::load(hier, path); - cg.create(); - cg + let relative_paths = get_cgroups_relative_paths().unwrap(); + Cgroup::new_with_relative_paths(hier, path, relative_paths) } /// Create a handle for a control group in the hierarchy `hier`, with name `path`. @@ -68,30 +68,31 @@ impl<'b> Cgroup<'b> { /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. pub fn load>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup<'b> { - let path = path.as_ref(); - let mut subsystems = hier.subsystems(); - if path.as_os_str() != "" { - subsystems = subsystems - .into_iter() - .map(|x| x.enter(path)) - .collect::>(); - } - - let cg = Cgroup { - subsystems: subsystems, - hier: hier, - path: path.to_str().unwrap().to_string(), - }; - - cg + let relative_paths = get_cgroups_relative_paths().unwrap(); + Cgroup::load_with_relative_paths(hier, path, relative_paths) } + /// Create a new control group in the hierarchy `hier`, with name `path`. + /// and relative paths from `/proc/self/cgroup` + /// + /// Returns a handle to the control group that can be used to manipulate it. + /// + /// Note that if the handle goes out of scope and is dropped, the control group is _not_ + /// destroyed. pub fn new_with_relative_paths>(hier: Box<&'b dyn Hierarchy>, path: P, relative_paths: HashMap) -> Cgroup<'b> { let cg = Cgroup::load_with_relative_paths(hier, path, relative_paths); cg.create(); cg } + /// Create a handle for a control group in the hierarchy `hier`, with name `path`, + /// and relative paths from `/proc/self/cgroup` + /// + /// Returns a handle to the control group (that possibly does not exist until `create()` has + /// been called on the cgroup. + /// + /// Note that if the handle goes out of scope and is dropped, the control group is _not_ + /// destroyed. pub fn load_with_relative_paths>(hier: Box<&'b dyn Hierarchy>, path: P, relative_paths: HashMap) -> Cgroup<'b> { let path = path.as_ref(); let mut subsystems = hier.subsystems(); @@ -206,7 +207,7 @@ impl<'b> Cgroup<'b> { if subsystems.len() > 0 { let c = subsystems[0].to_controller(); c.add_task(&pid) - } else{ + } else { Ok(()) } } else { @@ -252,7 +253,6 @@ fn enable_controllers(controllers: &Vec, path: &PathBuf) { f.push("cgroup.subtree_control"); for c in controllers{ let body = format!("+{}", c); - // FIXME set mode to 0644 let _rest = fs::write(f.as_path(), body.as_bytes()); } } @@ -265,7 +265,7 @@ fn supported_controllers(p: &PathBuf) -> Vec{ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { // controler list ["memory", "cpu"] - let controllers = supported_controllers(&root); + let controllers = supported_controllers(&root); let mut fp = root; // enable for root @@ -279,7 +279,6 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { fp.push(ele); // create dir, need not check if is a file or directory if !fp.exists(){ - // FIXME set mode to 0755 match ::std::fs::create_dir(fp.clone()) { Err(e) => return Err(Error::with_cause(ErrorKind::FsError, e)), Ok(_) => {}, @@ -293,4 +292,27 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { } Ok(()) -} \ No newline at end of file +} + +pub fn get_cgroups_relative_paths() -> Result> { + let mut m = HashMap::new(); + let content = fs::read_to_string("/proc/self/cgroup").map_err(|e| Error::with_cause(ReadFailed, e))?; + for l in content.lines() { + let fl: Vec<&str> = l.split(':').collect(); + if fl.len() != 3 { + continue; + } + + let keys: Vec<&str> = fl[1].split(',').collect(); + for key in &keys { + // this is a workaround, cgroup file are using `name=systemd`, + // but if file system the name is `systemd` + if *key == "name=systemd" { + m.insert("systemd".to_string(), fl[2].to_string()); + } else { + m.insert(key.to_string(), fl[2].to_string()); + } + } + } + Ok(m) +} diff --git a/tests/cgroup.rs b/tests/cgroup.rs index c5c29496..f78c20b4 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -39,22 +39,27 @@ fn test_cgroup_with_relative_paths() { return } let h = cgroups::hierarchies::auto(); + let cgroup_root = h.root(); let h = Box::new(&*h); let mut relative_paths = HashMap::new(); - relative_paths.insert("memory".to_string(), "/mmm/abc/def".to_string()); - let cg = Cgroup::new_with_relative_paths(h, String::from("test_cgroup_with_prefix"), relative_paths); + let mem_relative_path = "/mmm/abc/def"; + relative_paths.insert("memory".to_string(), mem_relative_path.to_string()); + let cgroup_name = "test_cgroup_with_relative_paths"; + + let cg = Cgroup::new_with_relative_paths(h, String::from(cgroup_name), relative_paths); { let subsystems = cg.subsystems(); subsystems.into_iter().for_each(|sub| match sub { Subsystem::Pid(c) => { - let p = c.path().to_str().unwrap(); - let rel_path = p.trim_start_matches("/sys/fs/cgroup/pids"); - assert_eq!(rel_path, "/test_cgroup_with_prefix") + let cgroup_path = c.path().to_str().unwrap(); + let relative_path = "/pids/"; + // cgroup_path = cgroup_root + relative_path + cgroup_name + assert_eq!(cgroup_path, format!("{}{}{}", cgroup_root.to_str().unwrap(), relative_path, cgroup_name)); }, Subsystem::Mem(c) => { - let p = c.path().to_str().unwrap(); - let rel_path = p.trim_start_matches("/sys/fs/cgroup/memory"); - assert_eq!(rel_path, "/mmm/abc/def/test_cgroup_with_prefix") + let cgroup_path = c.path().to_str().unwrap(); + // cgroup_path = cgroup_root + relative_path + cgroup_name + assert_eq!(cgroup_path, format!("{}/memory{}/{}", cgroup_root.to_str().unwrap(), mem_relative_path, cgroup_name)); }, _ => {}, }); From c3912223d0b8e3a99225ef85e301419c05ec7ad6 Mon Sep 17 00:00:00 2001 From: bin liu Date: Wed, 9 Sep 2020 13:23:36 +0800 Subject: [PATCH 11/71] use let Some() instead of is_some() to make codes clear Signed-off-by: bin liu --- src/blkio.rs | 23 ++++++++++++----------- src/cgroup.rs | 8 +++++--- tests/devices.rs | 2 +- tests/hugetlb.rs | 2 +- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/blkio.rs b/src/blkio.rs index 6ef41481..5d00ade5 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -338,19 +338,19 @@ impl ControllerInternal for BlkIoController { let res: &BlkIoResources = &res.blkio; if res.update_values { - if res.weight.is_some() { - let _ = self.set_weight(res.weight.unwrap() as u64); + if let Some(weight) = res.weight { + let _ = self.set_weight(weight as u64); } - if res.leaf_weight.is_some() { - let _ = self.set_leaf_weight(res.leaf_weight.unwrap() as u64); + if let Some(leaf_weight) = res.leaf_weight { + let _ = self.set_leaf_weight(leaf_weight as u64); } for dev in &res.weight_device { - if dev.weight.is_some(){ - let _ = self.set_weight_for_device(dev.major, dev.minor, dev.weight.unwrap() as u64); + if let Some(weight) = dev.weight { + let _ = self.set_weight_for_device(dev.major, dev.minor, weight as u64); } - if dev.leaf_weight.is_some(){ - let _ = self.set_leaf_weight_for_device(dev.major, dev.minor, dev.leaf_weight.unwrap() as u64); + if let Some(leaf_weight) = dev.leaf_weight { + let _ = self.set_leaf_weight_for_device(dev.major, dev.minor, leaf_weight as u64); } } @@ -774,7 +774,7 @@ impl BlkIoController { let mut content = format!("{}:{} {}", major, minor, iops); if self.v2 { file = "io.max"; - content = format!("{}:{} riops={}", major, minor, iops); + content = format!("{}:{} wiops={}", major, minor, iops); } self.open_path(file, true) .and_then(|mut file| { @@ -785,7 +785,7 @@ impl BlkIoController { /// Set the weight of the control group's tasks. pub fn set_weight(&self, w: u64) -> Result<()> { - // FIXME: not find in high kernel version. + // Attation: may not find in high kernel version. let mut file = "blkio.weight"; if self.v2 { file = "io.bfq.weight"; @@ -806,8 +806,9 @@ impl BlkIoController { ) -> Result<()> { let mut file = "blkio.weight_device"; if self.v2 { - // FIXME why is there no weight for device in runc ? + // Attation: there is no weight for device in runc // https://github.com/opencontainers/runc/blob/46be7b612e2533c494e6a251111de46d8e286ed5/libcontainer/cgroups/fs2/io.go#L30 + // may depends on IO schedulers https://wiki.ubuntu.com/Kernel/Reference/IOSchedulers file = "io.bfq.weight"; } self.open_path(file, true) diff --git a/src/cgroup.rs b/src/cgroup.rs index 899195ce..ece6609a 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -136,9 +136,11 @@ impl<'b> Cgroup<'b> { /// will change. pub fn delete(self) { if self.v2() { - let mut p = self.hier.root().clone(); - p.push(self.path); - libc_rmdir(p.to_str().unwrap()); + if self.path != "" { + let mut p = self.hier.root().clone(); + p.push(self.path); + libc_rmdir(p.to_str().unwrap()); + } return } diff --git a/tests/devices.rs b/tests/devices.rs index e87fa7f5..235351a9 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -5,7 +5,7 @@ use cgroups::{Cgroup, DeviceResource, Hierarchy}; #[test] fn test_devices_parsing() { - // no only v2 + // now only v2 if cgroups::hierarchies::is_cgroup2_unified_mode() { return } diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index b0a54334..9e3ff2cc 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -8,7 +8,7 @@ use cgroups::error::*; #[test] fn test_hugetlb_sizes() { - // no only v2 + // now only v2 if cgroups::hierarchies::is_cgroup2_unified_mode() { return } From ff6a0ea82aef3286726530a0ef75dc75885c5afb Mon Sep 17 00:00:00 2001 From: bin liu Date: Wed, 9 Sep 2020 13:35:46 +0800 Subject: [PATCH 12/71] add SPDX-License-Identifier for modified files Signed-off-by: bin liu --- src/blkio.rs | 1 + src/cgroup.rs | 1 + src/cgroup_builder.rs | 1 + src/cpu.rs | 1 + src/cpuset.rs | 1 + src/error.rs | 1 + src/events.rs | 5 +++++ src/freezer.rs | 1 + src/hierarchies.rs | 1 + src/hugetlb.rs | 1 + src/lib.rs | 1 + src/memory.rs | 1 + src/pid.rs | 1 + src/systemd.rs | 5 +++++ tests/builder.rs | 1 + tests/cgroup.rs | 1 + tests/cpuset.rs | 1 + tests/devices.rs | 1 + tests/hugetlb.rs | 5 +++++ tests/memory.rs | 5 +++++ tests/pids.rs | 1 + tests/resources.rs | 6 ++++++ 22 files changed, 43 insertions(+) diff --git a/src/blkio.rs b/src/blkio.rs index 8ddcbd2f..1ac968ee 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 And Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/cgroup.rs b/src/cgroup.rs index 4ce9ce5a..51fdf609 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index e32d7657..318f8856 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/cpu.rs b/src/cpu.rs index e02e9ebb..fe942f41 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/cpuset.rs b/src/cpuset.rs index 2f04ecf8..c3180d7d 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/error.rs b/src/error.rs index 759d1a88..741e60f5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/events.rs b/src/events.rs index 0b1576dc..592ec7f3 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2020 Ant Group +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + use eventfd::{eventfd, EfdFlags}; use nix::sys::eventfd; use std::fs::{self, File}; diff --git a/src/freezer.rs b/src/freezer.rs index f8729adb..064d5368 100644 --- a/src/freezer.rs +++ b/src/freezer.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/hierarchies.rs b/src/hierarchies.rs index c6e1b1e3..9400237d 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/hugetlb.rs b/src/hugetlb.rs index 5aa8edf0..2fc53521 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/lib.rs b/src/lib.rs index 546581b1..41cb2d75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/memory.rs b/src/memory.rs index 461c50c9..c8c2ff17 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/pid.rs b/src/pid.rs index 2fadbea3..353e3488 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 Ant Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/src/systemd.rs b/src/systemd.rs index 5dff8e48..e0a57a41 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2020 Ant Group +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! This module contains the implementation of the `systemd` cgroup subsystem. //! use std::path::PathBuf; diff --git a/tests/builder.rs b/tests/builder.rs index 69a187c9..69a187fa 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 And Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/tests/cgroup.rs b/tests/cgroup.rs index 6833f6f3..92a28e90 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 And Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/tests/cpuset.rs b/tests/cpuset.rs index 30a61767..4be3a57f 100644 --- a/tests/cpuset.rs +++ b/tests/cpuset.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 And Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/tests/devices.rs b/tests/devices.rs index 2714666d..220add99 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 And Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index 9e3ff2cc..30abd4ae 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2020 And Group +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! Integration tests about the hugetlb subsystem use cgroups::hugetlb::HugeTlbController; use cgroups::{Cgroup, Hierarchy}; diff --git a/tests/memory.rs b/tests/memory.rs index 8838afec..4283ea6c 100644 --- a/tests/memory.rs +++ b/tests/memory.rs @@ -1,3 +1,8 @@ +// Copyright (c) 2020 And Group +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! Integration tests about the hugetlb subsystem use cgroups::memory::{MemController, SetMemory}; use cgroups::{Cgroup, Hierarchy, MaxValue}; diff --git a/tests/pids.rs b/tests/pids.rs index a33ecb35..88a2fc04 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -1,4 +1,5 @@ // Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 And Group // // SPDX-License-Identifier: Apache-2.0 or MIT // diff --git a/tests/resources.rs b/tests/resources.rs index d26a896b..964081a1 100644 --- a/tests/resources.rs +++ b/tests/resources.rs @@ -1,3 +1,9 @@ +// Copyright (c) 2018 Levente Kurusa +// Copyright (c) 2020 And Group +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + //! Integration test about setting resources using `apply()` use cgroups::pid::{PidController}; use cgroups::{Cgroup, Hierarchy, MaxValue, PidResources, Resources}; From 250ada183a33f2df248cd452208c86ee1951e37d Mon Sep 17 00:00:00 2001 From: bin liu Date: Wed, 9 Sep 2020 16:42:55 +0800 Subject: [PATCH 13/71] cargo fmt Signed-off-by: bin liu --- src/blkio.rs | 135 +++++++++++----------------- src/cgroup.rs | 43 +++++---- src/cgroup_builder.rs | 198 ++++++++++++++++++++++++------------------ src/cpu.rs | 37 ++++---- src/cpuacct.rs | 8 +- src/cpuset.rs | 80 ++++++++++------- src/devices.rs | 5 +- src/error.rs | 5 +- src/events.rs | 16 ++-- src/freezer.rs | 6 +- src/hierarchies.rs | 66 ++++++++++---- src/hugetlb.rs | 47 +++++----- src/lib.rs | 59 +++++++------ src/memory.rs | 66 +++++++------- src/net_cls.rs | 13 +-- src/net_prio.rs | 10 ++- src/pid.rs | 14 +-- src/rdma.rs | 2 +- src/systemd.rs | 9 +- tests/builder.rs | 71 +++++++-------- tests/cgroup.rs | 35 +++++--- tests/cpuset.rs | 8 +- tests/devices.rs | 2 +- tests/hugetlb.rs | 4 +- tests/memory.rs | 35 ++++---- tests/pids.rs | 2 +- tests/resources.rs | 2 +- 27 files changed, 532 insertions(+), 446 deletions(-) diff --git a/src/blkio.rs b/src/blkio.rs index 1ac968ee..153a68e7 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -12,8 +12,8 @@ use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ BlkIoResources, ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem, @@ -27,7 +27,7 @@ use crate::{ pub struct BlkIoController { base: PathBuf, path: PathBuf, - v2: bool, + v2: bool, } #[derive(Eq, PartialEq, Debug)] @@ -124,7 +124,7 @@ fn parse_io_service(s: String) -> Result> { } fn get_value(s: &str) -> String { - let arr = s.split(':').collect::>(); + let arr = s.split(':').collect::>(); if arr.len() != 2 { return "0".to_string(); } @@ -134,7 +134,8 @@ fn get_value(s: &str) -> String { fn parse_io_stat(s: String) -> Result> { // line: // 8:0 rbytes=180224 wbytes=0 rios=3 wios=0 dbytes=0 dios=0 - let v = s.lines() + let v = s + .lines() .filter(|x| x.split_whitespace().collect::>().len() == 7) .map(|x| { let arr = x.split_whitespace().collect::>(); @@ -356,7 +357,8 @@ impl ControllerInternal for BlkIoController { let _ = self.set_weight_for_device(dev.major, dev.minor, weight as u64); } if let Some(leaf_weight) = dev.leaf_weight { - let _ = self.set_leaf_weight_for_device(dev.major, dev.minor, leaf_weight as u64); + let _ = + self.set_leaf_weight_for_device(dev.major, dev.minor, leaf_weight as u64); } } @@ -412,7 +414,10 @@ fn read_string_from(mut file: File) -> Result { fn read_u64_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { - Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)), + Ok(_) => string + .trim() + .parse() + .map_err(|e| Error::with_cause(ParseError, e)), Err(e) => Err(Error::with_cause(ReadFailed, e)), } } @@ -421,23 +426,23 @@ impl BlkIoController { /// Constructs a new `BlkIoController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf, v2: bool) -> Self { let mut root = oroot; - if !v2{ + if !v2 { root.push(Self::controller_type().to_string()); } Self { base: root.clone(), path: root, - v2: v2, + v2: v2, } } fn blkio_v2(&self) -> BlkIo { let mut blkio: BlkIo = Default::default(); blkio.io_stat = self - .open_path("io.stat", false) - .and_then(read_string_from) - .and_then(parse_io_stat) - .unwrap_or(Vec::new()); + .open_path("io.stat", false) + .and_then(read_string_from) + .and_then(parse_io_stat) + .unwrap_or(Vec::new()); blkio } @@ -684,12 +689,7 @@ impl BlkIoController { } /// Same as `set_leaf_weight()`, but settable per each block device. - pub fn set_leaf_weight_for_device( - &self, - major: u64, - minor: u64, - weight: u64, - ) -> Result<()> { + pub fn set_leaf_weight_for_device(&self, major: u64, minor: u64, weight: u64) -> Result<()> { self.open_path("blkio.leaf_weight_device", true) .and_then(|mut file| { file.write_all(format!("{}:{} {}", major, minor, weight).as_ref()) @@ -708,85 +708,61 @@ impl BlkIoController { /// Throttle the bytes per second rate of read operation affecting the block device /// `major:minor` to `bps`. - pub fn throttle_read_bps_for_device( - &self, - major: u64, - minor: u64, - bps: u64, - ) -> Result<()> { + pub fn throttle_read_bps_for_device(&self, major: u64, minor: u64, bps: u64) -> Result<()> { let mut file = "blkio.throttle.read_bps_device"; let mut content = format!("{}:{} {}", major, minor, bps); if self.v2 { file = "io.max"; content = format!("{}:{} rbps={}", major, minor, bps); } - self.open_path(file, true) - .and_then(|mut file| { - file.write_all(content.as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path(file, true).and_then(|mut file| { + file.write_all(content.as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } /// Throttle the I/O operations per second rate of read operation affecting the block device /// `major:minor` to `bps`. - pub fn throttle_read_iops_for_device( - &self, - major: u64, - minor: u64, - iops: u64, - ) -> Result<()> { + pub fn throttle_read_iops_for_device(&self, major: u64, minor: u64, iops: u64) -> Result<()> { let mut file = "blkio.throttle.read_iops_device"; let mut content = format!("{}:{} {}", major, minor, iops); if self.v2 { file = "io.max"; content = format!("{}:{} riops={}", major, minor, iops); } - self.open_path(file, true) - .and_then(|mut file| { - file.write_all(content.as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path(file, true).and_then(|mut file| { + file.write_all(content.as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } /// Throttle the bytes per second rate of write operation affecting the block device /// `major:minor` to `bps`. - pub fn throttle_write_bps_for_device( - &self, - major: u64, - minor: u64, - bps: u64, - ) -> Result<()> { + pub fn throttle_write_bps_for_device(&self, major: u64, minor: u64, bps: u64) -> Result<()> { let mut file = "blkio.throttle.write_bps_device"; let mut content = format!("{}:{} {}", major, minor, bps); if self.v2 { file = "io.max"; content = format!("{}:{} wbps={}", major, minor, bps); } - self.open_path(file, true) - .and_then(|mut file| { - file.write_all(content.as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path(file, true).and_then(|mut file| { + file.write_all(content.as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } /// Throttle the I/O operations per second rate of write operation affecting the block device /// `major:minor` to `bps`. - pub fn throttle_write_iops_for_device( - &self, - major: u64, - minor: u64, - iops: u64, - ) -> Result<()> { + pub fn throttle_write_iops_for_device(&self, major: u64, minor: u64, iops: u64) -> Result<()> { let mut file = "blkio.throttle.write_iops_device"; let mut content = format!("{}:{} {}", major, minor, iops); if self.v2 { file = "io.max"; content = format!("{}:{} wiops={}", major, minor, iops); } - self.open_path(file, true) - .and_then(|mut file| { - file.write_all(content.as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path(file, true).and_then(|mut file| { + file.write_all(content.as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } /// Set the weight of the control group's tasks. @@ -796,20 +772,14 @@ impl BlkIoController { if self.v2 { file = "io.bfq.weight"; } - self.open_path(file, true) - .and_then(|mut file| { - file.write_all(w.to_string().as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path(file, true).and_then(|mut file| { + file.write_all(w.to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } /// Same as `set_weight()`, but settable per each block device. - pub fn set_weight_for_device( - &self, - major: u64, - minor: u64, - weight: u64, - ) -> Result<()> { + pub fn set_weight_for_device(&self, major: u64, minor: u64, weight: u64) -> Result<()> { let mut file = "blkio.weight_device"; if self.v2 { // Attation: there is no weight for device in runc @@ -817,11 +787,10 @@ impl BlkIoController { // may depends on IO schedulers https://wiki.ubuntu.com/Kernel/Reference/IOSchedulers file = "io.bfq.weight"; } - self.open_path(file, true) - .and_then(|mut file| { - file.write_all(format!("{}:{} {}", major, minor, weight).as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path(file, true).and_then(|mut file| { + file.write_all(format!("{}:{} {}", major, minor, weight).as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } } @@ -887,10 +856,7 @@ Total 61823067136 #[test] fn test_parse_io_service_total() { let ok = parse_io_service_total(TEST_VALUE.to_string()).unwrap(); - assert_eq!( - ok, - 61823067136 - ); + assert_eq!(ok, 61823067136); } #[test] @@ -938,10 +904,7 @@ Total 61823067136 ] ); let err = parse_io_service(TEST_WRONG_VALUE.to_string()).unwrap_err(); - assert_eq!( - err.kind(), - &ErrorKind::ParseError, - ); + assert_eq!(err.kind(), &ErrorKind::ParseError,); } #[test] diff --git a/src/cgroup.rs b/src/cgroup.rs index 51fdf609..4fada605 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -6,8 +6,8 @@ //! This module handles cgroup operations. Start here! -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::libc_rmdir; @@ -85,7 +85,11 @@ impl<'b> Cgroup<'b> { /// /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. - pub fn new_with_relative_paths>(hier: Box<&'b dyn Hierarchy>, path: P, relative_paths: HashMap) -> Cgroup<'b> { + pub fn new_with_relative_paths>( + hier: Box<&'b dyn Hierarchy>, + path: P, + relative_paths: HashMap, + ) -> Cgroup<'b> { let cg = Cgroup::load_with_relative_paths(hier, path, relative_paths); cg.create(); cg @@ -99,7 +103,11 @@ impl<'b> Cgroup<'b> { /// /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. - pub fn load_with_relative_paths>(hier: Box<&'b dyn Hierarchy>, path: P, relative_paths: HashMap) -> Cgroup<'b> { + pub fn load_with_relative_paths>( + hier: Box<&'b dyn Hierarchy>, + path: P, + relative_paths: HashMap, + ) -> Cgroup<'b> { let path = path.as_ref(); let mut subsystems = hier.subsystems(); if path.as_os_str() != "" { @@ -147,7 +155,7 @@ impl<'b> Cgroup<'b> { p.push(self.path); libc_rmdir(p.to_str().unwrap()); } - return + return; } self.subsystems.into_iter().for_each(|sub| match sub { @@ -220,8 +228,8 @@ impl<'b> Cgroup<'b> { } } else { self.subsystems() - .iter() - .try_for_each(|sub| sub.to_controller().add_task(&pid)) + .iter() + .try_for_each(|sub| sub.to_controller().add_task(&pid)) } } @@ -238,8 +246,7 @@ impl<'b> Cgroup<'b> { vec![] } } else { - self - .subsystems() + self.subsystems() .iter() .map(|x| x.to_controller().tasks()) .fold(vec![], |mut acc, mut x| { @@ -259,16 +266,19 @@ pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; fn enable_controllers(controllers: &Vec, path: &PathBuf) { let mut f = path.clone(); f.push("cgroup.subtree_control"); - for c in controllers{ + for c in controllers { let body = format!("+{}", c); let _rest = fs::write(f.as_path(), body.as_bytes()); } } -fn supported_controllers(p: &PathBuf) -> Vec{ +fn supported_controllers(p: &PathBuf) -> Vec { let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers"); let ret = fs::read_to_string(p.as_str()); - ret.unwrap_or(String::new()).split(" ").map(|x| x.to_string() ).collect::>() + ret.unwrap_or(String::new()) + .split(" ") + .map(|x| x.to_string()) + .collect::>() } fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { @@ -281,16 +291,16 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { // path: "a/b/c" let elements = path.split("/").collect::>(); - let last_index = elements.len() - 1 ; + let last_index = elements.len() - 1; for (i, ele) in elements.iter().enumerate() { // ROOT/a fp.push(ele); // create dir, need not check if is a file or directory - if !fp.exists(){ + if !fp.exists() { match ::std::fs::create_dir(fp.clone()) { Err(e) => return Err(Error::with_cause(ErrorKind::FsError, e)), - Ok(_) => {}, - } + Ok(_) => {} + } } if i < last_index { @@ -304,7 +314,8 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { pub fn get_cgroups_relative_paths() -> Result> { let mut m = HashMap::new(); - let content = fs::read_to_string("/proc/self/cgroup").map_err(|e| Error::with_cause(ReadFailed, e))?; + let content = + fs::read_to_string("/proc/self/cgroup").map_err(|e| Error::with_cause(ReadFailed, e))?; for l in content.lines() { let fl: Vec<&str> = l.split(':').collect(); if fl.len() != 3 { diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index 318f8856..094535c7 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -62,7 +62,10 @@ //! ``` use crate::error::*; -use crate::{pid, BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy, HugePageResource, MaxValue, NetworkPriority, Resources}; +use crate::{ + pid, BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy, + HugePageResource, MaxValue, NetworkPriority, Resources, +}; macro_rules! gen_setter { ($res:ident, $cont:ident, $func:ident, $name:ident, $ty:ty) => { @@ -72,7 +75,7 @@ macro_rules! gen_setter { self.cgroup.resources.$res.$name = $name; self } - } + }; } /// A control group builder instance @@ -97,46 +100,34 @@ impl<'a> CgroupBuilder<'a> { /// Builds the memory resources of the control group. pub fn memory(self) -> MemoryResourceBuilder<'a> { - MemoryResourceBuilder { - cgroup: self, - } + MemoryResourceBuilder { cgroup: self } } /// Builds the pid resources of the control group. pub fn pid(self) -> PidResourceBuilder<'a> { - PidResourceBuilder { - cgroup: self, - } + PidResourceBuilder { cgroup: self } } /// Builds the cpu resources of the control group. pub fn cpu(self) -> CpuResourceBuilder<'a> { - CpuResourceBuilder { - cgroup: self, - } + CpuResourceBuilder { cgroup: self } } /// Builds the devices resources of the control group, disallowing or /// allowing access to certain devices in the system. pub fn devices(self) -> DeviceResourceBuilder<'a> { - DeviceResourceBuilder { - cgroup: self, - } + DeviceResourceBuilder { cgroup: self } } /// Builds the network resources of the control group, setting class id, or /// various priorities on networking interfaces. pub fn network(self) -> NetworkResourceBuilder<'a> { - NetworkResourceBuilder { - cgroup: self, - } + NetworkResourceBuilder { cgroup: self } } /// Builds the hugepage/hugetlb resources available to the control group. pub fn hugepages(self) -> HugepagesResourceBuilder<'a> { - HugepagesResourceBuilder { - cgroup: self, - } + HugepagesResourceBuilder { cgroup: self } } /// Builds the block I/O resources available for the control group. @@ -161,12 +152,35 @@ pub struct MemoryResourceBuilder<'a> { } impl<'a> MemoryResourceBuilder<'a> { - - gen_setter!(memory, MemController, set_kmem_limit, kernel_memory_limit, i64); + gen_setter!( + memory, + MemController, + set_kmem_limit, + kernel_memory_limit, + i64 + ); gen_setter!(memory, MemController, set_limit, memory_hard_limit, i64); - gen_setter!(memory, MemController, set_soft_limit, memory_soft_limit, i64); - gen_setter!(memory, MemController, set_tcp_limit, kernel_tcp_memory_limit, i64); - gen_setter!(memory, MemController, set_memswap_limit, memory_swap_limit, i64); + gen_setter!( + memory, + MemController, + set_soft_limit, + memory_soft_limit, + i64 + ); + gen_setter!( + memory, + MemController, + set_tcp_limit, + kernel_tcp_memory_limit, + i64 + ); + gen_setter!( + memory, + MemController, + set_memswap_limit, + memory_swap_limit, + i64 + ); gen_setter!(memory, MemController, set_swappiness, swappiness, u64); /// Finish the construction of the memory resources of a control group. @@ -181,8 +195,13 @@ pub struct PidResourceBuilder<'a> { } impl<'a> PidResourceBuilder<'a> { - - gen_setter!(pid, PidController, set_pid_max, maximum_number_of_processes, MaxValue); + gen_setter!( + pid, + PidController, + set_pid_max, + maximum_number_of_processes, + MaxValue + ); /// Finish the construction of the pid resources of a control group. pub fn done(self) -> CgroupBuilder<'a> { @@ -196,7 +215,6 @@ pub struct CpuResourceBuilder<'a> { } impl<'a> CpuResourceBuilder<'a> { - // FIXME this should all changed to options. gen_setter!(cpu, CpuSetController, set_cpus, cpus, Option); gen_setter!(cpu, CpuSetController, set_mems, mems, String); @@ -218,22 +236,22 @@ pub struct DeviceResourceBuilder<'a> { } impl<'a> DeviceResourceBuilder<'a> { - /// Restrict (or allow) a device to the tasks inside the control group. - pub fn device(mut self, - major: i64, - minor: i64, - devtype: crate::devices::DeviceType, - allow: bool, - access: Vec) - -> DeviceResourceBuilder<'a> { + pub fn device( + mut self, + major: i64, + minor: i64, + devtype: crate::devices::DeviceType, + allow: bool, + access: Vec, + ) -> DeviceResourceBuilder<'a> { self.cgroup.resources.devices.update_values = true; self.cgroup.resources.devices.devices.push(DeviceResource { major, minor, devtype, allow, - access + access, }); self } @@ -250,18 +268,17 @@ pub struct NetworkResourceBuilder<'a> { } impl<'a> NetworkResourceBuilder<'a> { - gen_setter!(network, NetclsController, set_class, class_id, u64); /// Set the priority of the tasks when operating on a networking device defined by `name` to be /// `priority`. - pub fn priority(mut self, name: String, priority: u64) - -> NetworkResourceBuilder<'a> { + pub fn priority(mut self, name: String, priority: u64) -> NetworkResourceBuilder<'a> { self.cgroup.resources.network.update_values = true; - self.cgroup.resources.network.priorities.push(NetworkPriority { - name, - priority, - }); + self.cgroup + .resources + .network + .priorities + .push(NetworkPriority { name, priority }); self } @@ -277,15 +294,14 @@ pub struct HugepagesResourceBuilder<'a> { } impl<'a> HugepagesResourceBuilder<'a> { - /// Limit the usage of certain hugepages (determined by `size`) to be at most `limit` bytes. - pub fn limit(mut self, size: String, limit: u64) - -> HugepagesResourceBuilder<'a> { + pub fn limit(mut self, size: String, limit: u64) -> HugepagesResourceBuilder<'a> { self.cgroup.resources.hugepages.update_values = true; - self.cgroup.resources.hugepages.limits.push(HugePageResource { - size, - limit, - }); + self.cgroup + .resources + .hugepages + .limits + .push(HugePageResource { size, limit }); self } @@ -302,24 +318,34 @@ pub struct BlkIoResourcesBuilder<'a> { } impl<'a> BlkIoResourcesBuilder<'a> { - gen_setter!(blkio, BlkIoController, set_weight, weight, Option); - gen_setter!(blkio, BlkIoController, set_leaf_weight, leaf_weight, Option); + gen_setter!( + blkio, + BlkIoController, + set_leaf_weight, + leaf_weight, + Option + ); /// Set the weight of a certain device. - pub fn weight_device(mut self, - major: u64, - minor: u64, - weight: Option, - leaf_weight: Option) - -> BlkIoResourcesBuilder<'a> { + pub fn weight_device( + mut self, + major: u64, + minor: u64, + weight: Option, + leaf_weight: Option, + ) -> BlkIoResourcesBuilder<'a> { self.cgroup.resources.blkio.update_values = true; - self.cgroup.resources.blkio.weight_device.push(BlkIoDeviceResource { - major, - minor, - weight, - leaf_weight, - }); + self.cgroup + .resources + .blkio + .weight_device + .push(BlkIoDeviceResource { + major, + minor, + weight, + leaf_weight, + }); self } @@ -336,35 +362,41 @@ impl<'a> BlkIoResourcesBuilder<'a> { } /// Limit the read rate of the current metric for a certain device. - pub fn read(mut self, major: u64, minor: u64, rate: u64) - -> BlkIoResourcesBuilder<'a> { + pub fn read(mut self, major: u64, minor: u64, rate: u64) -> BlkIoResourcesBuilder<'a> { self.cgroup.resources.blkio.update_values = true; - let throttle = BlkIoDeviceThrottleResource { - major, - minor, - rate, - }; + let throttle = BlkIoDeviceThrottleResource { major, minor, rate }; if self.throttling_iops { - self.cgroup.resources.blkio.throttle_read_iops_device.push(throttle); + self.cgroup + .resources + .blkio + .throttle_read_iops_device + .push(throttle); } else { - self.cgroup.resources.blkio.throttle_read_bps_device.push(throttle); + self.cgroup + .resources + .blkio + .throttle_read_bps_device + .push(throttle); } self } /// Limit the write rate of the current metric for a certain device. - pub fn write(mut self, major: u64, minor: u64, rate: u64) - -> BlkIoResourcesBuilder<'a> { + pub fn write(mut self, major: u64, minor: u64, rate: u64) -> BlkIoResourcesBuilder<'a> { self.cgroup.resources.blkio.update_values = true; - let throttle = BlkIoDeviceThrottleResource { - major, - minor, - rate, - }; + let throttle = BlkIoDeviceThrottleResource { major, minor, rate }; if self.throttling_iops { - self.cgroup.resources.blkio.throttle_write_iops_device.push(throttle); + self.cgroup + .resources + .blkio + .throttle_write_iops_device + .push(throttle); } else { - self.cgroup.resources.blkio.throttle_write_bps_device.push(throttle); + self.cgroup + .resources + .blkio + .throttle_write_bps_device + .push(throttle); } self } diff --git a/src/cpu.rs b/src/cpu.rs index fe942f41..ad8f3bfb 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -13,8 +13,8 @@ use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ ControllIdentifier, ControllerInternal, Controllers, CpuResources, Resources, Subsystem, @@ -29,7 +29,7 @@ use crate::{ pub struct CpuController { base: PathBuf, path: PathBuf, - v2: bool, + v2: bool, } /// The current state of the control group and its processes. @@ -112,7 +112,10 @@ impl<'a> From<&'a Subsystem> for &'a CpuController { fn read_u64_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { - Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)), + Ok(_) => string + .trim() + .parse() + .map_err(|e| Error::with_cause(ParseError, e)), Err(e) => Err(Error::with_cause(ReadFailed, e)), } } @@ -127,7 +130,7 @@ impl CpuController { Self { base: root.clone(), path: root, - v2: v2, + v2: v2, } } @@ -143,7 +146,8 @@ impl CpuController { Ok(_) => Ok(s), Err(e) => Err(Error::with_cause(ReadFailed, e)), } - }).unwrap_or("".to_string()), + }) + .unwrap_or("".to_string()), } } @@ -215,22 +219,21 @@ impl CpuController { return self.set_cfs_period(period); } let mut line = "max".to_string(); - if quota > 0 { - line = quota.to_string(); + if quota > 0 { + line = quota.to_string(); } let mut p = period; - if period == 0 { - // This default value is documented in - // https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html - p = 100000 - } + if period == 0 { + // This default value is documented in + // https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html + p = 100000 + } line = format!("{} {}", line, p); - self.open_path("cpu.max", true) - .and_then(|mut file| { - file.write_all(line.as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path("cpu.max", true).and_then(|mut file| { + file.write_all(line.as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } pub fn set_rt_runtime(&self, us: i64) -> Result<()> { diff --git a/src/cpuacct.rs b/src/cpuacct.rs index 0325723c..4171c6d1 100644 --- a/src/cpuacct.rs +++ b/src/cpuacct.rs @@ -11,8 +11,8 @@ use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem}; @@ -167,7 +167,9 @@ impl CpuAcctController { /// Reset the statistics the kernel has gathered about the control group. pub fn reset(&self) -> Result<()> { - self.open_path("cpuacct.usage", true) - .and_then(|mut file| file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e))) + self.open_path("cpuacct.usage", true).and_then(|mut file| { + file.write_all(b"0") + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } } diff --git a/src/cpuset.rs b/src/cpuset.rs index c3180d7d..92754c00 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -14,8 +14,8 @@ use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ ControllIdentifier, ControllerInternal, Controllers, CpuResources, Resources, Subsystem, @@ -29,7 +29,7 @@ use crate::{ pub struct CpuSetController { base: PathBuf, path: PathBuf, - v2: bool, + v2: bool, } /// The current state of the `cpuset` controller for this control group. @@ -111,7 +111,7 @@ impl ControllerInternal for CpuSetController { let res: &CpuResources = &res.cpu; if res.update_values { - if res.cpus.is_some(){ + if res.cpus.is_some() { let _ = self.set_cpus(res.cpus.as_ref().unwrap().as_str()); } let _ = self.set_mems(&res.mems); @@ -120,9 +120,9 @@ impl ControllerInternal for CpuSetController { Ok(()) } - fn post_create(&self){ - if self.is_v2(){ - return + fn post_create(&self) { + if self.is_v2() { + return; } let current = self.get_path(); let parent = match current.parent() { @@ -132,11 +132,11 @@ impl ControllerInternal for CpuSetController { if current != self.get_base() { match copy_from_parent(current.to_str().unwrap(), "cpuset.cpus") { - Ok(_)=>(), + Ok(_) => (), Err(err) => error!("error create_dir for cpuset.cpus {:?}", err), } match copy_from_parent(current.to_str().unwrap(), "cpuset.mems") { - Ok(_)=>(), + Ok(_) => (), Err(err) => error!("error create_dir for cpuset.mems {:?}", err), } } @@ -148,10 +148,11 @@ fn find_no_empty_parent(from: &str, file: &str) -> Result<(String, Vec) let mut v = vec![]; loop { - let current_value = match ::std::fs::read_to_string(current_path.clone().join(file).to_str().unwrap()) { - Ok(cpus) => String::from(cpus.trim()), - Err(e) => return Err(Error::with_cause(ReadFailed, e)), - }; + let current_value = + match ::std::fs::read_to_string(current_path.clone().join(file).to_str().unwrap()) { + Ok(cpus) => String::from(cpus.trim()), + Err(e) => return Err(Error::with_cause(ReadFailed, e)), + }; if current_value != "" { return Ok((current_value, v)); @@ -221,7 +222,10 @@ fn read_string_from(mut file: File) -> Result { fn read_u64_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { - Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)), + Ok(_) => string + .trim() + .parse() + .map_err(|e| Error::with_cause(ParseError, e)), Err(e) => Err(Error::with_cause(ReadFailed, e)), } } @@ -267,7 +271,7 @@ impl CpuSetController { /// Contructs a new `CpuSetController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf, v2: bool) -> Self { let mut root = oroot; - if !v2{ + if !v2 { root.push(Self::controller_type().to_string()); } Self { @@ -372,9 +376,11 @@ impl CpuSetController { self.open_path("cpuset.cpu_exclusive", true) .and_then(|mut file| { if b { - file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"1") + .map_err(|e| Error::with_cause(WriteFailed, e)) } else { - file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"0") + .map_err(|e| Error::with_cause(WriteFailed, e)) } }) } @@ -385,9 +391,11 @@ impl CpuSetController { self.open_path("cpuset.mem_exclusive", true) .and_then(|mut file| { if b { - file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"1") + .map_err(|e| Error::with_cause(WriteFailed, e)) } else { - file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"0") + .map_err(|e| Error::with_cause(WriteFailed, e)) } }) } @@ -422,9 +430,11 @@ impl CpuSetController { self.open_path("cpuset.mem_hardwall", true) .and_then(|mut file| { if b { - file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"1") + .map_err(|e| Error::with_cause(WriteFailed, e)) } else { - file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"0") + .map_err(|e| Error::with_cause(WriteFailed, e)) } }) } @@ -435,9 +445,11 @@ impl CpuSetController { self.open_path("cpuset.sched_load_balance", true) .and_then(|mut file| { if b { - file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"1") + .map_err(|e| Error::with_cause(WriteFailed, e)) } else { - file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"0") + .map_err(|e| Error::with_cause(WriteFailed, e)) } }) } @@ -459,9 +471,11 @@ impl CpuSetController { self.open_path("cpuset.memory_migrate", true) .and_then(|mut file| { if b { - file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"1") + .map_err(|e| Error::with_cause(WriteFailed, e)) } else { - file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"0") + .map_err(|e| Error::with_cause(WriteFailed, e)) } }) } @@ -472,9 +486,11 @@ impl CpuSetController { self.open_path("cpuset.memory_spread_page", true) .and_then(|mut file| { if b { - file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"1") + .map_err(|e| Error::with_cause(WriteFailed, e)) } else { - file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"0") + .map_err(|e| Error::with_cause(WriteFailed, e)) } }) } @@ -485,9 +501,11 @@ impl CpuSetController { self.open_path("cpuset.memory_spread_slab", true) .and_then(|mut file| { if b { - file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"1") + .map_err(|e| Error::with_cause(WriteFailed, e)) } else { - file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"0") + .map_err(|e| Error::with_cause(WriteFailed, e)) } }) } @@ -504,9 +522,11 @@ impl CpuSetController { self.open_path("cpuset.memory_pressure_enabled", true) .and_then(|mut file| { if b { - file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"1") + .map_err(|e| Error::with_cause(WriteFailed, e)) } else { - file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(b"0") + .map_err(|e| Error::with_cause(WriteFailed, e)) } }) } diff --git a/src/devices.rs b/src/devices.rs index 09628c43..5e6efb99 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -12,8 +12,8 @@ use std::path::PathBuf; use log::*; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ ControllIdentifier, ControllerInternal, Controllers, DeviceResource, DeviceResources, @@ -129,8 +129,7 @@ impl DevicePermissions { return Ok(v); } for e in s.chars() { - let perm = DevicePermissions::from_char(e) - .ok_or_else(|| Error::new(ParseError))?; + let perm = DevicePermissions::from_char(e).ok_or_else(|| Error::new(ParseError))?; v.push(perm); } diff --git a/src/error.rs b/src/error.rs index 741e60f5..ff5549c2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -83,10 +83,7 @@ impl Error { } } pub(crate) fn new(kind: ErrorKind) -> Self { - Self { - kind, - cause: None, - } + Self { kind, cause: None } } pub(crate) fn with_cause(kind: ErrorKind, cause: E) -> Self diff --git a/src/events.rs b/src/events.rs index 592ec7f3..da0b718e 100644 --- a/src/events.rs +++ b/src/events.rs @@ -12,9 +12,8 @@ use std::path::{Path, PathBuf}; use std::sync::mpsc::{self, Receiver}; use std::thread; -use crate::error::*; use crate::error::ErrorKind::*; - +use crate::error::*; // notify_on_oom returns channel on which you can expect event about OOM, // if process died without OOM this channel will be closed. @@ -31,7 +30,10 @@ pub fn notify_on_oom_v1(key: &str, dir: &PathBuf) -> Result> { // level is one of "low", "medium", or "critical" pub fn notify_memory_pressure(key: &str, dir: &PathBuf, level: &str) -> Result> { if level != "low" && level != "medium" && level != "critical" { - return Err(Error::from_string(format!("invalid pressure level {}", level))); + return Err(Error::from_string(format!( + "invalid pressure level {}", + level + ))); } register_memory_event(key, dir, "memory.pressure_level", level) @@ -46,7 +48,8 @@ fn register_memory_event( let path = cg_dir.join(event_name); let event_file = File::open(path).map_err(|e| Error::with_cause(ReadFailed, e))?; - let eventfd = eventfd(0, EfdFlags::EFD_CLOEXEC).map_err(|e| Error::with_cause(ReadFailed, e))?; + let eventfd = + eventfd(0, EfdFlags::EFD_CLOEXEC).map_err(|e| Error::with_cause(ReadFailed, e))?; let event_control_path = cg_dir.join("cgroup.event_control"); let data; @@ -71,8 +74,7 @@ fn register_memory_event( Err(err) => { return; } - Ok(_) => { - } + Ok(_) => {} } // When a cgroup is destroyed, an event is sent to eventfd. @@ -85,4 +87,4 @@ fn register_memory_event( }); Ok(receiver) -} \ No newline at end of file +} diff --git a/src/freezer.rs b/src/freezer.rs index 064d5368..92d8c2cd 100644 --- a/src/freezer.rs +++ b/src/freezer.rs @@ -11,8 +11,8 @@ use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem}; @@ -28,7 +28,7 @@ use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subs pub struct FreezerController { base: PathBuf, path: PathBuf, - v2: bool, + v2: bool, } /// The current state of the control group @@ -90,7 +90,7 @@ impl FreezerController { Self { base: root.clone(), path: root, - v2: v2, + v2: v2, } } diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 9400237d..4b8f1eb0 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -45,7 +45,6 @@ pub struct V2 { } impl Hierarchy for V1 { - fn v2(&self) -> bool { false } @@ -71,7 +70,10 @@ impl Hierarchy for V1 { subs.push(Subsystem::Devices(DevicesController::new(self.root()))); } if self.check_support(Controllers::Freezer) { - subs.push(Subsystem::Freezer(FreezerController::new(self.root(), false))); + subs.push(Subsystem::Freezer(FreezerController::new( + self.root(), + false, + ))); } if self.check_support(Controllers::NetCls) { subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); @@ -86,20 +88,26 @@ impl Hierarchy for V1 { subs.push(Subsystem::NetPrio(NetPrioController::new(self.root()))); } if self.check_support(Controllers::HugeTlb) { - subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root(), false))); + subs.push(Subsystem::HugeTlb(HugeTlbController::new( + self.root(), + false, + ))); } if self.check_support(Controllers::Rdma) { subs.push(Subsystem::Rdma(RdmaController::new(self.root()))); } if self.check_support(Controllers::Systemd) { - subs.push(Subsystem::Systemd(SystemdController::new(self.root(), false))); + subs.push(Subsystem::Systemd(SystemdController::new( + self.root(), + false, + ))); } subs } fn root_control_group(&self) -> Cgroup { - let b : &Hierarchy = self as &Hierarchy; + let b: &Hierarchy = self as &Hierarchy; Cgroup::load(Box::new(&*b), "".to_string()) } @@ -136,17 +144,37 @@ impl Hierarchy for V2 { let controllers = ret.unwrap().trim().to_string(); let controller_list: Vec<&str> = controllers.split(' ').collect(); - + for s in controller_list { match s { - "cpu" => {subs.push(Subsystem::Cpu(CpuController::new(self.root(), true)));}, - "io" => {subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), true)));}, - "cpuset" => {subs.push(Subsystem::CpuSet(CpuSetController::new(self.root(), true)));}, - "memory" => {subs.push(Subsystem::Mem(MemController::new(self.root(), true)));}, - "pids" => {subs.push(Subsystem::Pid(PidController::new(self.root(), true)));}, - "freezer" => {subs.push(Subsystem::Freezer(FreezerController::new(self.root(), true)));}, - "hugetlb" => {subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root(), true)));}, - _ => {}, + "cpu" => { + subs.push(Subsystem::Cpu(CpuController::new(self.root(), true))); + } + "io" => { + subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), true))); + } + "cpuset" => { + subs.push(Subsystem::CpuSet(CpuSetController::new(self.root(), true))); + } + "memory" => { + subs.push(Subsystem::Mem(MemController::new(self.root(), true))); + } + "pids" => { + subs.push(Subsystem::Pid(PidController::new(self.root(), true))); + } + "freezer" => { + subs.push(Subsystem::Freezer(FreezerController::new( + self.root(), + true, + ))); + } + "hugetlb" => { + subs.push(Subsystem::HugeTlb(HugeTlbController::new( + self.root(), + true, + ))); + } + _ => {} } } @@ -154,7 +182,7 @@ impl Hierarchy for V2 { } fn root_control_group(&self) -> Cgroup { - let b : &Hierarchy = self as &Hierarchy; + let b: &Hierarchy = self as &Hierarchy; Cgroup::load(Box::new(&*b), "".to_string()) } @@ -195,7 +223,7 @@ pub fn is_cgroup2_unified_mode() -> bool { let path = Path::new(UNIFIED_MOUNTPOINT); let fs_stat = statfs::statfs(path); if fs_stat.is_err() { - return false + return false; } // FIXME notwork, nix will not compile CGROUP2_SUPER_MAGIC because not(target_env = "musl") @@ -208,10 +236,10 @@ pub const INIT_CGROUP_PATHS: &'static str = "/proc/1/cgroup"; pub fn is_cgroup2_unified_mode() -> bool { let lines = fs::read_to_string(INIT_CGROUP_PATHS); if lines.is_err() { - return false + return false; } - for line in lines.unwrap().lines(){ + for line in lines.unwrap().lines() { let fields: Vec<&str> = line.split(':').collect(); if fields.len() != 3 { continue; @@ -227,7 +255,7 @@ pub fn is_cgroup2_unified_mode() -> bool { pub fn auto() -> Box { if is_cgroup2_unified_mode() { Box::new(V2::new()) - }else{ + } else { Box::new(V1::new()) } } diff --git a/src/hugetlb.rs b/src/hugetlb.rs index 2fc53521..4237c116 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -12,13 +12,12 @@ use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::flat_keyed_to_vec; use crate::{ - ControllIdentifier, ControllerInternal, Controllers, HugePageResources, Resources, - Subsystem, + ControllIdentifier, ControllerInternal, Controllers, HugePageResources, Resources, Subsystem, }; /// A controller that allows controlling the `hugetlb` subsystem of a Cgroup. @@ -27,10 +26,10 @@ use crate::{ /// the control group. #[derive(Debug, Clone)] pub struct HugeTlbController { - base: PathBuf, - path: PathBuf, + base: PathBuf, + path: PathBuf, sizes: Vec, - v2: bool, + v2: bool, } impl ControllerInternal for HugeTlbController { @@ -90,7 +89,10 @@ impl<'a> From<&'a Subsystem> for &'a HugeTlbController { fn read_u64_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { - Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)), + Ok(_) => string + .trim() + .parse() + .map_err(|e| Error::with_cause(ParseError, e)), Err(e) => Err(Error::with_cause(ReadFailed, e)), } } @@ -107,7 +109,7 @@ impl HugeTlbController { base: root.clone(), path: root, sizes: sizes, - v2: v2, + v2: v2, } } @@ -115,7 +117,7 @@ impl HugeTlbController { pub fn size_supported(&self, hugetlb_size: &str) -> bool { for s in &self.sizes { if s == hugetlb_size { - return true + return true; } } false @@ -130,7 +132,10 @@ impl HugeTlbController { .and_then(flat_keyed_to_vec) .and_then(|x| { if x.len() == 0 { - return Err(Error::from_string(format!("get empty from hugetlb.{}.events", hugetlb_size))); + return Err(Error::from_string(format!( + "get empty from hugetlb.{}.events", + hugetlb_size + ))); } Ok(x[0].1 as u64) }) @@ -168,7 +173,8 @@ impl HugeTlbController { self.open_path( &format!("hugetlb.{}.max_usage_in_bytes", hugetlb_size), false, - ).and_then(read_u64_from) + ) + .and_then(read_u64_from) } /// Set the limit (in bytes) of how much memory can be backed by hugepages of a certain size @@ -178,15 +184,13 @@ impl HugeTlbController { if self.v2 { file = format!("hugetlb.{}.max", hugetlb_size); } - self.open_path(&file, true) - .and_then(|mut file| { - file.write_all(limit.to_string().as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path(&file, true).and_then(|mut file| { + file.write_all(limit.to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } } - pub const HUGEPAGESIZE_DIR: &'static str = "/sys/kernel/mm/hugepages"; use regex::Regex; use std::collections::HashMap; @@ -206,7 +210,7 @@ fn get_hugepage_sizes() -> Result> { if parts.len() != 2 { continue; } - let bmap= get_binary_size_map(); + let bmap = get_binary_size_map(); let size = parse_size(parts[1], &bmap)?; let dabbrs = get_decimal_abbrs(); m.push(custom_size(size as f64, 1024.0, &dabbrs)); @@ -215,7 +219,6 @@ fn get_hugepage_sizes() -> Result> { Ok(m) } - pub const KB: u128 = 1000; pub const MB: u128 = 1000 * KB; pub const GB: u128 = 1000 * MB; @@ -228,7 +231,6 @@ pub const GiB: u128 = 1024 * MiB; pub const TiB: u128 = 1024 * GiB; pub const PiB: u128 = 1024 * TiB; - pub fn get_binary_size_map() -> HashMap { let mut m = HashMap::new(); m.insert("k".to_string(), KiB); @@ -249,7 +251,7 @@ pub fn get_decimal_size_map() -> HashMap { m } -pub fn get_decimal_abbrs() -> Vec { +pub fn get_decimal_abbrs() -> Vec { let m = vec![ "B".to_string(), "KB".to_string(), @@ -275,7 +277,7 @@ fn parse_size(s: &str, m: &HashMap) -> Result { let num = caps.name("num"); let size: u128 = if num.is_some() { let n = num.unwrap().as_str().trim().parse::(); - if n.is_err(){ + if n.is_err() { return Err(Error::new(InvalidBytesSize)); } n.unwrap() @@ -307,4 +309,3 @@ fn custom_size(mut size: f64, base: f64, m: &Vec) -> String { format!("{}{}", size, m[i].as_str()) } - diff --git a/src/lib.rs b/src/lib.rs index 41cb2d75..e48b9d46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,11 +8,12 @@ use log::*; use std::collections::HashMap; use std::fs::File; -use std::io::{Read, BufRead, BufReader, Write}; +use std::io::{BufRead, BufReader, Read, Write}; use std::path::{Path, PathBuf}; pub mod blkio; pub mod cgroup; +pub mod cgroup_builder; pub mod cpu; pub mod cpuacct; pub mod cpuset; @@ -29,15 +30,14 @@ pub mod perf_event; pub mod pid; pub mod rdma; pub mod systemd; -pub mod cgroup_builder; use crate::blkio::BlkIoController; use crate::cpu::CpuController; use crate::cpuacct::CpuAcctController; use crate::cpuset::CpuSetController; use crate::devices::DevicesController; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::freezer::FreezerController; use crate::hugetlb::HugeTlbController; use crate::memory::MemController; @@ -136,8 +136,7 @@ mod sealed { fn get_base(&self) -> &PathBuf; /// Hooks running after controller crated, if have - fn post_create(&self){ - } + fn post_create(&self) {} fn is_v2(&self) -> bool { false @@ -189,7 +188,6 @@ mod sealed { std::path::Path::new(p).exists() } - } } @@ -227,7 +225,10 @@ pub trait Controller { fn v2(&self) -> bool; } -impl Controller for T where T: ControllerInternal { +impl Controller for T +where + T: ControllerInternal, +{ fn control_type(&self) -> Controllers { ControllerInternal::control_type(self) } @@ -244,7 +245,8 @@ impl Controller for T where T: ControllerInternal { /// Create this controller fn create(&self) { - self.verify_path().expect(format!("path should be valid: {:?}", self.path()).as_str()); + self.verify_path() + .expect(format!("path should be valid: {:?}", self.path()).as_str()); match ::std::fs::create_dir_all(self.get_path()) { Ok(_) => self.post_create(), @@ -293,13 +295,13 @@ impl Controller for T where T: ControllerInternal { } } Ok(v.into_iter().map(CgroupPid::from).collect()) - }).unwrap_or(vec![]) + }) + .unwrap_or(vec![]) } fn v2(&self) -> bool { self.is_v2() } - } #[doc(hidden)] @@ -641,8 +643,6 @@ impl Subsystem { } } - - /// The values for `memory.hight` or `pids.max` #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum MaxValue { @@ -676,7 +676,7 @@ impl MaxValue { pub fn parse_max_value(s: &String) -> Result { if s.trim() == "max" { - return Ok(MaxValue::Max) + return Ok(MaxValue::Max); } match s.trim().parse() { Ok(val) => Ok(MaxValue::Value(val)), @@ -689,18 +689,20 @@ pub fn parse_max_value(s: &String) -> Result { // KEY1 VAL1\n pub fn flat_keyed_to_vec(mut file: File) -> Result> { let mut content = String::new(); - file.read_to_string(&mut content).map_err(|e| Error::with_cause(ReadFailed, e))?; + file.read_to_string(&mut content) + .map_err(|e| Error::with_cause(ReadFailed, e))?; let mut v = Vec::new(); for line in content.lines() { let parts: Vec<&str> = line.split(' ').collect(); if parts.len() == 2 { match parts[1].parse::() { - Ok(i) => { v.push((parts[0].to_string(), i)); } , - Err(_) => {}, + Ok(i) => { + v.push((parts[0].to_string(), i)); + } + Err(_) => {} } } - } Ok(v) } @@ -710,18 +712,20 @@ pub fn flat_keyed_to_vec(mut file: File) -> Result> { // KEY1 VAL1\n pub fn flat_keyed_to_hashmap(mut file: File) -> Result> { let mut content = String::new(); - file.read_to_string(&mut content).map_err(|e| Error::with_cause(ReadFailed, e))?; + file.read_to_string(&mut content) + .map_err(|e| Error::with_cause(ReadFailed, e))?; let mut h = HashMap::new(); for line in content.lines() { let parts: Vec<&str> = line.split(' ').collect(); if parts.len() == 2 { match parts[1].parse::() { - Ok(i) => { h.insert(parts[0].to_string(), i); } , - Err(_) => {}, + Ok(i) => { + h.insert(parts[0].to_string(), i); + } + Err(_) => {} } } - } Ok(h) } @@ -731,7 +735,8 @@ pub fn flat_keyed_to_hashmap(mut file: File) -> Result> { // KEY1 SUB_KEY0=VAL10 SUB_KEY1=VAL11... pub fn nested_keyed_to_hashmap(mut file: File) -> Result>> { let mut content = String::new(); - file.read_to_string(&mut content).map_err(|e| Error::with_cause(ReadFailed, e))?; + file.read_to_string(&mut content) + .map_err(|e| Error::with_cause(ReadFailed, e))?; let mut h = HashMap::new(); for line in content.lines() { @@ -744,8 +749,10 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result = item.split('=').collect(); if fields.len() == 2 { match fields[1].parse::() { - Ok(i) => { th.insert(fields[0].to_string(), i); } , - Err(_) => {}, + Ok(i) => { + th.insert(fields[0].to_string(), i); + } + Err(_) => {} } } } @@ -759,7 +766,5 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result, @@ -476,25 +476,29 @@ impl MemController { Self { base: root.clone(), path: root, - v2: v2, + v2: v2, } } // for v2 - pub fn set_mem(&self, m: SetMemory) -> Result<()> { - let values = vec![(m.high, "memory.high"),(m.low, "memory.low"),(m.max, "memory.max"),(m.min, "memory.min")]; - for value in values{ + pub fn set_mem(&self, m: SetMemory) -> Result<()> { + let values = vec![ + (m.high, "memory.high"), + (m.low, "memory.low"), + (m.max, "memory.max"), + (m.min, "memory.min"), + ]; + for value in values { let v = value.0; let f = value.1; if v.is_some() { let v = v.unwrap().to_string(); - self.open_path(f, true) - .and_then(|mut file| { + self.open_path(f, true).and_then(|mut file| { file.write_all(v.as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) })?; } - } + } Ok(()) } @@ -652,9 +656,8 @@ impl MemController { fail_cnt: self .open_path("memory.swap.events", false) .and_then(flat_keyed_to_hashmap) - .and_then(|x| { - Ok(*x.get("fail").unwrap_or(&0) as u64) - }).unwrap(), + .and_then(|x| Ok(*x.get("fail").unwrap_or(&0) as u64)) + .unwrap(), limit_in_bytes: self .open_path("memory.swap.max", false) .and_then(read_i64_from) @@ -735,11 +738,10 @@ impl MemController { if self.v2 { file = "memory.max"; } - self.open_path(file, true) - .and_then(|mut file| { - file.write_all(limit.to_string().as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path(file, true).and_then(|mut file| { + file.write_all(limit.to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } /// Set the kernel memory limit of the control group, in bytes. @@ -757,11 +759,10 @@ impl MemController { if self.v2 { file = "memory.swap.max"; } - self.open_path(file, true) - .and_then(|mut file| { - file.write_all(limit.to_string().as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path(file, true).and_then(|mut file| { + file.write_all(limit.to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } /// Set how much kernel memory can be used for TCP-related buffers by the control group. @@ -782,11 +783,10 @@ impl MemController { if self.v2 { file = "memory.low" } - self.open_path(file, true) - .and_then(|mut file| { - file.write_all(limit.to_string().as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + self.open_path(file, true).and_then(|mut file| { + file.write_all(limit.to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } /// Set how likely the kernel is to swap out parts of the address space used by the control @@ -809,10 +809,10 @@ impl MemController { }) } - pub fn register_oom_event(&self, key: &str) -> Result>{ - if self.v2{ + pub fn register_oom_event(&self, key: &str) -> Result> { + if self.v2 { events::notify_on_oom_v2(key, self.get_path()) - }else { + } else { events::notify_on_oom_v1(key, self.get_path()) } } @@ -870,10 +870,10 @@ fn read_string_from(mut file: File) -> Result { #[cfg(test)] mod tests { - use std::collections::HashMap; use crate::memory::{ parse_memory_stat, parse_numa_stat, parse_oom_control, MemoryStat, NumaStat, OomControl, }; + use std::collections::HashMap; static GOOD_VALUE: &str = "\ total=51189 N0=51189 N1=123 diff --git a/src/net_cls.rs b/src/net_cls.rs index 13a23664..4d923ffa 100644 --- a/src/net_cls.rs +++ b/src/net_cls.rs @@ -11,12 +11,11 @@ use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ - ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, - Subsystem, + ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, Subsystem, }; /// A controller that allows controlling the `net_cls` subsystem of a Cgroup. @@ -81,7 +80,10 @@ impl<'a> From<&'a Subsystem> for &'a NetClsController { fn read_u64_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { - Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)), + Ok(_) => string + .trim() + .parse() + .map_err(|e| Error::with_cause(ParseError, e)), Err(e) => Err(Error::with_cause(ReadFailed, e)), } } @@ -102,7 +104,8 @@ impl NetClsController { self.open_path("net_cls.classid", true) .and_then(|mut file| { let s = format!("{:#08X}", class); - file.write_all(s.as_ref()).map_err(|e| Error::with_cause(WriteFailed, e)) + file.write_all(s.as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) }) } diff --git a/src/net_prio.rs b/src/net_prio.rs index 6d4cbe0d..a4d0b6e0 100644 --- a/src/net_prio.rs +++ b/src/net_prio.rs @@ -12,12 +12,11 @@ use std::fs::File; use std::io::{BufRead, BufReader, Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ - ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, - Subsystem, + ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, Subsystem, }; /// A controller that allows controlling the `net_prio` subsystem of a Cgroup. @@ -82,7 +81,10 @@ impl<'a> From<&'a Subsystem> for &'a NetPrioController { fn read_u64_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { - Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)), + Ok(_) => string + .trim() + .parse() + .map_err(|e| Error::with_cause(ParseError, e)), Err(e) => Err(Error::with_cause(ReadFailed, e)), } } diff --git a/src/pid.rs b/src/pid.rs index 353e3488..f1ed8453 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -12,11 +12,12 @@ use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ - ControllIdentifier, ControllerInternal, Controllers, MaxValue, parse_max_value, PidResources, Resources, Subsystem, + parse_max_value, ControllIdentifier, ControllerInternal, Controllers, MaxValue, PidResources, + Resources, Subsystem, }; /// A controller that allows controlling the `pids` subsystem of a Cgroup. @@ -24,7 +25,7 @@ use crate::{ pub struct PidController { base: PathBuf, path: PathBuf, - v2: bool, + v2: bool, } impl ControllerInternal for PidController { @@ -94,7 +95,10 @@ impl<'a> From<&'a Subsystem> for &'a PidController { fn read_u64_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { - Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)), + Ok(_) => string + .trim() + .parse() + .map_err(|e| Error::with_cause(ParseError, e)), Err(e) => Err(Error::with_cause(ReadFailed, e)), } } @@ -110,7 +114,7 @@ impl PidController { Self { base: root.clone(), path: root, - v2: v2, + v2: v2, } } diff --git a/src/rdma.rs b/src/rdma.rs index 0611bb64..1de74585 100644 --- a/src/rdma.rs +++ b/src/rdma.rs @@ -11,8 +11,8 @@ use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem}; diff --git a/src/systemd.rs b/src/systemd.rs index e0a57a41..9c9d36d8 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -7,8 +7,8 @@ //! use std::path::PathBuf; -use crate::error::*; use crate::error::ErrorKind::*; +use crate::error::*; use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem}; @@ -18,7 +18,7 @@ use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subs pub struct SystemdController { base: PathBuf, path: PathBuf, - v2: bool, + v2: bool, } impl ControllerInternal for SystemdController { @@ -64,14 +64,13 @@ impl SystemdController { /// Constructs a new `SystemdController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf, v2: bool) -> Self { let mut root = oroot; - if !v2{ + if !v2 { root.push(Self::controller_type().to_string()); } Self { base: root.clone(), path: root, - v2: v2, + v2: v2, } } - } diff --git a/tests/builder.rs b/tests/builder.rs index 69a187fa..fced12ae 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -5,15 +5,15 @@ // //! Some simple tests covering the builder pattern for control groups. -use cgroups::*; +use cgroups::blkio::*; +use cgroups::cgroup_builder::*; use cgroups::cpu::*; use cgroups::devices::*; -use cgroups::pid::*; +use cgroups::hugetlb::*; use cgroups::memory::*; use cgroups::net_cls::*; -use cgroups::hugetlb::*; -use cgroups::blkio::*; -use cgroups::cgroup_builder::*; +use cgroups::pid::*; +use cgroups::*; #[test] pub fn test_cpu_res_build() { @@ -21,8 +21,8 @@ pub fn test_cpu_res_build() { let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_cpu_res_build", h) .cpu() - .shares(85) - .done() + .shares(85) + .done() .build(); { @@ -40,10 +40,10 @@ pub fn test_memory_res_build() { let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_memory_res_build", h) .memory() - .kernel_memory_limit(128 * 1024 * 1024) - .swappiness(70) - .memory_hard_limit(1024 * 1024 * 1024) - .done() + .kernel_memory_limit(128 * 1024 * 1024) + .swappiness(70) + .memory_hard_limit(1024 * 1024 * 1024) + .done() .build(); { @@ -64,8 +64,8 @@ pub fn test_pid_res_build() { let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_pid_res_build", h) .pid() - .maximum_number_of_processes(MaxValue::Value(123)) - .done() + .maximum_number_of_processes(MaxValue::Value(123)) + .done() .build(); { @@ -84,23 +84,23 @@ pub fn test_devices_res_build() { let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_devices_res_build", h) .devices() - .device(1, 6, DeviceType::Char, true, - vec![DevicePermissions::Read]) - .done() + .device(1, 6, DeviceType::Char, true, vec![DevicePermissions::Read]) + .done() .build(); { let c: &DevicesController = cg.controller_of().unwrap(); assert!(c.allowed_devices().is_ok()); - assert_eq!(c.allowed_devices().unwrap(), vec![ - DeviceResource { - allow: true, - devtype: DeviceType::Char, - major: 1, - minor: 6, - access: vec![DevicePermissions::Read], - } - ]); + assert_eq!( + c.allowed_devices().unwrap(), + vec![DeviceResource { + allow: true, + devtype: DeviceType::Char, + major: 1, + minor: 6, + access: vec![DevicePermissions::Read], + }] + ); } cg.delete(); } @@ -110,13 +110,13 @@ pub fn test_network_res_build() { let h = cgroups::hierarchies::auto(); if h.v2() { // FIXME add cases for v2 - return + return; } let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_network_res_build", h) .network() - .class_id(1337) - .done() + .class_id(1337) + .done() .build(); { @@ -132,19 +132,22 @@ pub fn test_hugepages_res_build() { let h = cgroups::hierarchies::auto(); if h.v2() { // FIXME add cases for v2 - return + return; } let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_hugepages_res_build", h) .hugepages() - .limit("2MB".to_string(), 4 * 2 * 1024 * 1024) - .done() + .limit("2MB".to_string(), 4 * 2 * 1024 * 1024) + .done() .build(); { let c: &HugeTlbController = cg.controller_of().unwrap(); assert!(c.limit_in_bytes(&"2MB".to_string()).is_ok()); - assert_eq!(c.limit_in_bytes(&"2MB".to_string()).unwrap(), 4 * 2 * 1024 * 1024); + assert_eq!( + c.limit_in_bytes(&"2MB".to_string()).unwrap(), + 4 * 2 * 1024 * 1024 + ); } cg.delete(); } @@ -156,8 +159,8 @@ pub fn test_blkio_res_build() { let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build", h) .blkio() - .weight(Some(100)) - .done() + .weight(Some(100)) + .done() .build(); { diff --git a/tests/cgroup.rs b/tests/cgroup.rs index 92a28e90..915a5f97 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -5,9 +5,9 @@ // //! Simple unit tests about the control groups system. -use cgroups::{Cgroup, CgroupPid, Hierarchy, Subsystem}; use cgroups::memory::{MemController, SetMemory}; use cgroups::Controller; +use cgroups::{Cgroup, CgroupPid, Hierarchy, Subsystem}; use std::collections::HashMap; #[test] @@ -38,11 +38,10 @@ fn test_tasks_iterator() { cg.delete(); } - #[test] fn test_cgroup_with_relative_paths() { if cgroups::hierarchies::is_cgroup2_unified_mode() { - return + return; } let h = cgroups::hierarchies::auto(); let cgroup_root = h.root(); @@ -60,14 +59,30 @@ fn test_cgroup_with_relative_paths() { let cgroup_path = c.path().to_str().unwrap(); let relative_path = "/pids/"; // cgroup_path = cgroup_root + relative_path + cgroup_name - assert_eq!(cgroup_path, format!("{}{}{}", cgroup_root.to_str().unwrap(), relative_path, cgroup_name)); - }, + assert_eq!( + cgroup_path, + format!( + "{}{}{}", + cgroup_root.to_str().unwrap(), + relative_path, + cgroup_name + ) + ); + } Subsystem::Mem(c) => { let cgroup_path = c.path().to_str().unwrap(); // cgroup_path = cgroup_root + relative_path + cgroup_name - assert_eq!(cgroup_path, format!("{}/memory{}/{}", cgroup_root.to_str().unwrap(), mem_relative_path, cgroup_name)); - }, - _ => {}, + assert_eq!( + cgroup_path, + format!( + "{}/memory{}/{}", + cgroup_root.to_str().unwrap(), + mem_relative_path, + cgroup_name + ) + ); + } + _ => {} }); } cg.delete(); @@ -76,14 +91,14 @@ fn test_cgroup_with_relative_paths() { #[test] fn test_cgroup_v2() { if !cgroups::hierarchies::is_cgroup2_unified_mode() { - return + return; } let h = cgroups::hierarchies::auto(); let h = Box::new(&*h); let cg = Cgroup::new_with_relative_paths(h, String::from("test_v2"), HashMap::new()); let mem_controller: &MemController = cg.controller_of().unwrap(); - let (mem, swp, rev) = (4 * 1024 * 1000, 2 * 1024* 1000, 1024 * 1000); + let (mem, swp, rev) = (4 * 1024 * 1000, 2 * 1024 * 1000, 1024 * 1000); let _ = mem_controller.set_limit(mem); let _ = mem_controller.set_memswap_limit(swp); diff --git a/tests/cpuset.rs b/tests/cpuset.rs index 4be3a57f..35633548 100644 --- a/tests/cpuset.rs +++ b/tests/cpuset.rs @@ -25,7 +25,6 @@ fn test_cpuset_memory_pressure_root_cg() { cg.delete(); } - #[test] fn test_cpuset_set_cpus() { let h = cgroups::hierarchies::auto(); @@ -48,10 +47,11 @@ fn test_cpuset_set_cpus() { let set = cpuset.cpuset(); assert_eq!(1, set.cpus.len()); - assert_eq!((0,0), set.cpus[0]); + assert_eq!((0, 0), set.cpus[0]); // all cpus in system - let cpus = fs::read_to_string("/sys/fs/cgroup/cpuset.cpus.effective").unwrap_or("".to_string()); + let cpus = + fs::read_to_string("/sys/fs/cgroup/cpuset.cpus.effective").unwrap_or("".to_string()); let cpus = cpus.trim(); if cpus != "" { let r = cpuset.set_cpus(&cpus); @@ -93,4 +93,4 @@ fn test_cpuset_set_cpus_add_task() { assert_eq!(0, tasks.len()); cg.delete(); -} \ No newline at end of file +} diff --git a/tests/devices.rs b/tests/devices.rs index 220add99..adb7e13e 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -13,7 +13,7 @@ use cgroups::{Cgroup, DeviceResource, Hierarchy}; fn test_devices_parsing() { // now only v2 if cgroups::hierarchies::is_cgroup2_unified_mode() { - return + return; } let h = cgroups::hierarchies::auto(); diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index 30abd4ae..c90c6153 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -5,8 +5,8 @@ //! Integration tests about the hugetlb subsystem use cgroups::hugetlb::HugeTlbController; -use cgroups::{Cgroup, Hierarchy}; use cgroups::Controller; +use cgroups::{Cgroup, Hierarchy}; use cgroups::error::ErrorKind::*; use cgroups::error::*; @@ -15,7 +15,7 @@ use cgroups::error::*; fn test_hugetlb_sizes() { // now only v2 if cgroups::hierarchies::is_cgroup2_unified_mode() { - return + return; } let h = cgroups::hierarchies::auto(); diff --git a/tests/memory.rs b/tests/memory.rs index 4283ea6c..47b70990 100644 --- a/tests/memory.rs +++ b/tests/memory.rs @@ -5,8 +5,8 @@ //! Integration tests about the hugetlb subsystem use cgroups::memory::{MemController, SetMemory}; -use cgroups::{Cgroup, Hierarchy, MaxValue}; use cgroups::Controller; +use cgroups::{Cgroup, Hierarchy, MaxValue}; use cgroups::error::ErrorKind::*; use cgroups::error::*; @@ -24,7 +24,7 @@ fn test_disable_oom_killer() { assert_eq!(m.oom_control.oom_kill_disable, false); // FIXME only v1 - if !mem_controller.v2(){ + if !mem_controller.v2() { // disable oom killer let r = mem_controller.disable_oom_killer(); assert_eq!(r.is_err(), false); @@ -33,7 +33,6 @@ fn test_disable_oom_killer() { let m = mem_controller.memory_stat(); assert_eq!(m.oom_control.oom_kill_disable, true); } - } cg.delete(); } @@ -42,7 +41,7 @@ fn test_disable_oom_killer() { fn set_mem_v2() { let h = cgroups::hierarchies::auto(); if !h.v2() { - return + return; } let h = Box::new(&*h); @@ -59,10 +58,10 @@ fn set_mem_v2() { assert_eq!(m.max, Some(MaxValue::Max)); // case 2: set parts - let m = SetMemory{ - low: Some(MaxValue::Value(1024*1024* 2)), - high: Some(MaxValue::Value(1024*1024*1024* 2)), - min: Some(MaxValue::Value(1024*1024* 3)), + let m = SetMemory { + low: Some(MaxValue::Value(1024 * 1024 * 2)), + high: Some(MaxValue::Value(1024 * 1024 * 1024 * 2)), + min: Some(MaxValue::Value(1024 * 1024 * 3)), max: None, }; let r = mem_controller.set_mem(m); @@ -70,17 +69,15 @@ fn set_mem_v2() { let m = mem_controller.get_mem().unwrap(); // get - assert_eq!(m.low, Some(MaxValue::Value(1024*1024* 2))); - assert_eq!(m.min, Some(MaxValue::Value(1024*1024* 3))); - assert_eq!(m.high, Some(MaxValue::Value(1024*1024*1024* 2))); + assert_eq!(m.low, Some(MaxValue::Value(1024 * 1024 * 2))); + assert_eq!(m.min, Some(MaxValue::Value(1024 * 1024 * 3))); + assert_eq!(m.high, Some(MaxValue::Value(1024 * 1024 * 1024 * 2))); assert_eq!(m.max, Some(MaxValue::Max)); - - // case 3: set parts - let m = SetMemory{ - max: Some(MaxValue::Value(1024*1024*1024* 2)), - min: Some(MaxValue::Value(1024*1024* 4)), + let m = SetMemory { + max: Some(MaxValue::Value(1024 * 1024 * 1024 * 2)), + min: Some(MaxValue::Value(1024 * 1024 * 4)), high: Some(MaxValue::Max), low: None, }; @@ -89,9 +86,9 @@ fn set_mem_v2() { let m = mem_controller.get_mem().unwrap(); // get - assert_eq!(m.low, Some(MaxValue::Value(1024*1024* 2))); - assert_eq!(m.min, Some(MaxValue::Value(1024*1024* 4))); - assert_eq!(m.max, Some(MaxValue::Value(1024*1024*1024* 2))); + assert_eq!(m.low, Some(MaxValue::Value(1024 * 1024 * 2))); + assert_eq!(m.min, Some(MaxValue::Value(1024 * 1024 * 4))); + assert_eq!(m.max, Some(MaxValue::Value(1024 * 1024 * 1024 * 2))); assert_eq!(m.high, Some(MaxValue::Max)); } diff --git a/tests/pids.rs b/tests/pids.rs index 88a2fc04..0449a0d5 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -5,7 +5,7 @@ // //! Integration tests about the pids subsystem -use cgroups::pid::{PidController}; +use cgroups::pid::PidController; use cgroups::Controller; use cgroups::{Cgroup, CgroupPid, Hierarchy, MaxValue, PidResources, Resources}; diff --git a/tests/resources.rs b/tests/resources.rs index 964081a1..665e4d08 100644 --- a/tests/resources.rs +++ b/tests/resources.rs @@ -5,7 +5,7 @@ // //! Integration test about setting resources using `apply()` -use cgroups::pid::{PidController}; +use cgroups::pid::PidController; use cgroups::{Cgroup, Hierarchy, MaxValue, PidResources, Resources}; #[test] From be617190c76796c6fd6e471e2c2f7576da5ea013 Mon Sep 17 00:00:00 2001 From: bin liu Date: Wed, 9 Sep 2020 17:09:12 +0800 Subject: [PATCH 14/71] hugetlb: update test to avoid depending on test env Signed-off-by: bin liu --- tests/hugetlb.rs | 26 +++++++++++++++----------- tests/memory.rs | 7 ++----- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index c90c6153..095243e8 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -4,12 +4,13 @@ // //! Integration tests about the hugetlb subsystem -use cgroups::hugetlb::HugeTlbController; +use cgroups::hugetlb::{self, HugeTlbController}; use cgroups::Controller; use cgroups::{Cgroup, Hierarchy}; use cgroups::error::ErrorKind::*; use cgroups::error::*; +use std::fs; #[test] fn test_hugetlb_sizes() { @@ -25,16 +26,19 @@ fn test_hugetlb_sizes() { let hugetlb_controller: &HugeTlbController = cg.controller_of().unwrap(); let sizes = hugetlb_controller.get_sizes(); - let size = "2MB"; - assert_eq!(sizes, vec![size.to_string()]); - - let supported = hugetlb_controller.size_supported(size); - assert_eq!(supported, true); - - assert_no_error(hugetlb_controller.failcnt(size)); - assert_no_error(hugetlb_controller.limit_in_bytes(size)); - assert_no_error(hugetlb_controller.usage_in_bytes(size)); - assert_no_error(hugetlb_controller.max_usage_in_bytes(size)); + // test sizes count + let sizes = hugetlb_controller.get_sizes(); + let sizes_count = fs::read_dir(hugetlb::HUGEPAGESIZE_DIR).unwrap().count(); + assert_eq!(sizes.len(), sizes_count); + + for size in sizes { + let supported = hugetlb_controller.size_supported(&size); + assert_eq!(supported, true); + assert_no_error(hugetlb_controller.failcnt(&size)); + assert_no_error(hugetlb_controller.limit_in_bytes(&size)); + assert_no_error(hugetlb_controller.usage_in_bytes(&size)); + assert_no_error(hugetlb_controller.max_usage_in_bytes(&size)); + } } cg.delete(); } diff --git a/tests/memory.rs b/tests/memory.rs index 47b70990..2d649068 100644 --- a/tests/memory.rs +++ b/tests/memory.rs @@ -6,10 +6,7 @@ //! Integration tests about the hugetlb subsystem use cgroups::memory::{MemController, SetMemory}; use cgroups::Controller; -use cgroups::{Cgroup, Hierarchy, MaxValue}; - -use cgroups::error::ErrorKind::*; -use cgroups::error::*; +use cgroups::{Cgroup, MaxValue}; #[test] fn test_disable_oom_killer() { @@ -23,7 +20,7 @@ fn test_disable_oom_killer() { let m = mem_controller.memory_stat(); assert_eq!(m.oom_control.oom_kill_disable, false); - // FIXME only v1 + // now only v1 if !mem_controller.v2() { // disable oom killer let r = mem_controller.disable_oom_killer(); From f8d653e98747c34a8d56e9bcc135164d7babb97a Mon Sep 17 00:00:00 2001 From: bin liu Date: Mon, 14 Sep 2020 13:00:40 +0800 Subject: [PATCH 15/71] cpu: change cfs_quota from u64 to i64 cfs_quota can be set to -1 to indicate no limit Fixes: #5 Signed-off-by: bin liu --- src/cpu.rs | 113 ++++++++++++++++++++++++++++++++++++++++++--------- src/lib.rs | 12 ++++++ tests/cpu.rs | 61 +++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 20 deletions(-) create mode 100644 tests/cpu.rs diff --git a/src/cpu.rs b/src/cpu.rs index ad8f3bfb..b222db89 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -15,9 +15,11 @@ use std::path::PathBuf; use crate::error::ErrorKind::*; use crate::error::*; +use crate::{parse_max_value, read_i64_from}; use crate::{ - ControllIdentifier, ControllerInternal, Controllers, CpuResources, Resources, Subsystem, + ControllIdentifier, ControllerInternal, Controllers, CpuResources, MaxValue, Resources, + Subsystem, }; /// A controller that allows controlling the `cpu` subsystem of a Cgroup. @@ -41,6 +43,13 @@ pub struct Cpu { pub stat: String, } +/// The current state of the control group and its processes. +#[derive(Debug)] +struct CFSQuotaAndPeriod { + quota: MaxValue, + period: u64, +} + impl ControllerInternal for CpuController { fn control_type(&self) -> Controllers { Controllers::Cpu @@ -77,8 +86,8 @@ impl ControllerInternal for CpuController { return Err(Error::new(ErrorKind::Other)); } - let _ = self.set_cfs_quota(res.quota as u64); - if self.cfs_quota()? != res.quota as u64 { + let _ = self.set_cfs_quota(res.quota); + if self.cfs_quota()? != res.quota { return Err(Error::new(ErrorKind::Other)); } @@ -182,6 +191,9 @@ impl CpuController { /// Specify a period (when using the CFS scheduler) of time in microseconds for how often this /// control group's access to the CPU should be reallocated. pub fn set_cfs_period(&self, us: u64) -> Result<()> { + if self.v2 { + return self.set_cfs_quota_and_period(None, Some(us)); + } self.open_path("cpu.cfs_period_us", true) .and_then(|mut file| { file.write_all(us.to_string().as_ref()) @@ -192,13 +204,22 @@ impl CpuController { /// Retrieve the period of time of how often this cgroup's access to the CPU should be /// reallocated in microseconds. pub fn cfs_period(&self) -> Result { + if self.v2 { + let current_value = self + .open_path("cpu.max", false) + .and_then(parse_cfs_quota_and_period)?; + return Ok(current_value.period); + } self.open_path("cpu.cfs_period_us", false) .and_then(read_u64_from) } /// Specify a quota (when using the CFS scheduler) of time in microseconds for which all tasks /// in this control group can run during one period (see: `set_cfs_period()`). - pub fn set_cfs_quota(&self, us: u64) -> Result<()> { + pub fn set_cfs_quota(&self, us: i64) -> Result<()> { + if self.v2 { + return self.set_cfs_quota_and_period(Some(us), None); + } self.open_path("cpu.cfs_quota_us", true) .and_then(|mut file| { file.write_all(us.to_string().as_ref()) @@ -208,28 +229,59 @@ impl CpuController { /// Retrieve the quota of time for which all tasks in this cgroup can run during one period, in /// microseconds. - pub fn cfs_quota(&self) -> Result { + pub fn cfs_quota(&self) -> Result { + if self.v2 { + let current_value = self + .open_path("cpu.max", false) + .and_then(parse_cfs_quota_and_period)?; + return Ok(current_value.quota.to_i64()); + } + self.open_path("cpu.cfs_quota_us", false) - .and_then(read_u64_from) + .and_then(read_i64_from) } - pub fn set_cfs_quota_and_period(&self, quota: u64, period: u64) -> Result<()> { + pub fn set_cfs_quota_and_period(&self, quota: Option, period: Option) -> Result<()> { if !self.v2 { - self.set_cfs_quota(quota)?; - return self.set_cfs_period(period); - } - let mut line = "max".to_string(); - if quota > 0 { - line = quota.to_string(); + if let Some(q) = quota { + self.set_cfs_quota(q)?; + } + if let Some(p) = period { + self.set_cfs_period(p)?; + } + return Ok(()); } - let mut p = period; - if period == 0 { - // This default value is documented in - // https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html - p = 100000 - } - line = format!("{} {}", line, p); + // https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html + + // cpu.max + // A read-write two value file which exists on non-root cgroups. The default is “max 100000”. + // The maximum bandwidth limit. It’s in the following format: + // $MAX $PERIOD + // which indicates that the group may consume upto $MAX in each $PERIOD duration. + // “max” for $MAX indicates no limit. If only one number is written, $MAX is updated. + + let current_value = self + .open_path("cpu.max", false) + .and_then(parse_cfs_quota_and_period)?; + + let new_quota = if let Some(q) = quota { + if q > 0 { + q.to_string() + } else { + "max".to_string() + } + } else { + current_value.quota.to_string() + }; + + let new_period = if let Some(p) = period { + p.to_string() + } else { + current_value.period.to_string() + }; + + let line = format!("{} {}", new_quota, new_period); self.open_path("cpu.max", true).and_then(|mut file| { file.write_all(line.as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) @@ -252,3 +304,24 @@ impl CpuController { }) } } + +fn parse_cfs_quota_and_period(mut file: File) -> Result { + let mut content = String::new(); + file.read_to_string(&mut content) + .map_err(|e| Error::with_cause(ReadFailed, e))?; + + let fields = content.trim().split(' ').collect::>(); + if fields.len() != 2 { + return Err(Error::from_string(format!("invaild format: {}", content))); + } + + let quota = parse_max_value(&fields[0].to_string())?; + let period = fields[1] + .parse::() + .map_err(|e| Error::with_cause(ParseError, e))?; + + Ok(CFSQuotaAndPeriod { + quota: quota, + period: period, + }) +} diff --git a/src/lib.rs b/src/lib.rs index e48b9d46..222dbc22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -768,3 +768,15 @@ pub fn libc_rmdir(p: &str) { // with int return value let _ = unsafe { libc::rmdir(p.as_ptr() as *const i8) }; } + +/// read and parse an i64 data +pub fn read_i64_from(mut file: File) -> Result { + let mut string = String::new(); + match file.read_to_string(&mut string) { + Ok(_) => string + .trim() + .parse() + .map_err(|e| Error::with_cause(ParseError, e)), + Err(e) => Err(Error::with_cause(ReadFailed, e)), + } +} diff --git a/tests/cpu.rs b/tests/cpu.rs new file mode 100644 index 00000000..cbaad33b --- /dev/null +++ b/tests/cpu.rs @@ -0,0 +1,61 @@ +// Copyright (c) 2020 And Group +// +// SPDX-License-Identifier: Apache-2.0 or MIT +// + +//! Simple unit tests about the CPU control groups system. +use cgroups::cpu::CpuController; +use cgroups::error::ErrorKind; +use cgroups::{Cgroup, CgroupPid, CpuResources, Hierarchy, Resources}; + +use std::fs; + +#[test] +fn test_cfs_quota_and_periods() { + let h = cgroups::hierarchies::auto(); + let h = Box::new(&*h); + let cg = Cgroup::new(h, String::from("test_cfs_quota_and_periods")); + + let cpu_controller: &CpuController = cg.controller_of().unwrap(); + + let current_quota = cpu_controller.cfs_quota().unwrap(); + let current_peroid = cpu_controller.cfs_period().unwrap(); + + // verify default value + // The default is “max 100000”. + assert_eq!(-1, current_quota); + assert_eq!(100000, current_peroid); + + // case 1 set quota + let r = cpu_controller.set_cfs_quota(2000); + + let current_quota = cpu_controller.cfs_quota().unwrap(); + let current_peroid = cpu_controller.cfs_period().unwrap(); + assert_eq!(2000, current_quota); + assert_eq!(100000, current_peroid); + + // case 2 set period + cpu_controller.set_cfs_period(1000000); + let current_quota = cpu_controller.cfs_quota().unwrap(); + let current_peroid = cpu_controller.cfs_period().unwrap(); + assert_eq!(2000, current_quota); + assert_eq!(1000000, current_peroid); + + // case 3 set both quota and period + cpu_controller.set_cfs_quota_and_period(Some(5000), Some(100000)); + + let current_quota = cpu_controller.cfs_quota().unwrap(); + let current_peroid = cpu_controller.cfs_period().unwrap(); + assert_eq!(5000, current_quota); + assert_eq!(100000, current_peroid); + + // case 4 set both quota and period, set quota to -1 + cpu_controller.set_cfs_quota_and_period(Some(-1), None); + + let current_quota = cpu_controller.cfs_quota().unwrap(); + let current_peroid = cpu_controller.cfs_period().unwrap(); + assert_eq!(-1, current_quota); + assert_eq!(100000, current_peroid); + + cg.delete(); +} From 42685bbfe9c1abbfdba31c07b77479fd1fbb6cd8 Mon Sep 17 00:00:00 2001 From: bin liu Date: Mon, 14 Sep 2020 15:22:55 +0800 Subject: [PATCH 16/71] errors: add sync marker to error cause Errors cause should be shared to let anyhow to wrap it. Fixes: #7 Signed-off-by: bin liu --- src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index ff5549c2..0e4f69c0 100644 --- a/src/error.rs +++ b/src/error.rs @@ -45,7 +45,7 @@ pub enum ErrorKind { #[derive(Debug)] pub struct Error { kind: ErrorKind, - cause: Option>, + cause: Option>, } impl fmt::Display for Error { @@ -88,7 +88,7 @@ impl Error { pub(crate) fn with_cause(kind: ErrorKind, cause: E) -> Self where - E: 'static + Send + StdError, + E: 'static + Send + Sync + StdError, { Self { kind, From cd7e737149f67a46e9ace5bc6dee95bbb614909d Mon Sep 17 00:00:00 2001 From: zhanghj Date: Mon, 21 Sep 2020 05:40:57 -0400 Subject: [PATCH 17/71] lib: fix compiling error for type i8 in aarch64 environment c_char is equal to i8 on x86, but it is equal to u8 on arm arch, so we need to use type c_char instead of i8 to avoid compiling error. Fixes: #9 Signed-off-by: zhanghj --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 222dbc22..c9103710 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -766,7 +766,7 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result Date: Tue, 22 Sep 2020 11:22:56 +0800 Subject: [PATCH 18/71] update Travis configs Fixes: #11 Signed-off-by: bin liu --- .travis.yml | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 20eb418b..0a028bc4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,31 @@ +# Copyright (c) 2018 Levente Kurusa +# Copyright (c) 2020 Ant Group +# +# SPDX-License-Identifier: Apache-2.0 +# + +dist: bionic +os: linux language: rust +cache: cargo + +arch: + - amd64 + - arm64 + +install: + - rustup component add rustfmt + +script: + - cargo build + - if [ "$TRAVIS_CPU_ARCH" == "amd64" ]; then cargo test -- --color always --nocapture ; fi + - cargo fmt -- --check + rust: - - stable - - beta + - 1.44.1 - nightly -matrix: + +jobs: allow_failures: - rust: nightly fast_finish: true -script: - - cargo build --verbose --all From 414fa281cc0694f855c15e13e969d89a0c79b8d0 Mon Sep 17 00:00:00 2001 From: bin liu Date: Wed, 23 Sep 2020 15:58:38 +0800 Subject: [PATCH 19/71] add basic github workflow for basic checks Basic checks includes: - Must have commit title/body - Must have DCO(SoC) - Title/Body line length are limited 75/72 - Add wip/do-not-merge to label PRs that could be merged Fixes: #15 Signed-off-by: bin liu --- .github/workflows/PR-wip-checks.yaml | 21 ++++++++ .github/workflows/commit-message-check.yaml | 53 +++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 .github/workflows/PR-wip-checks.yaml create mode 100644 .github/workflows/commit-message-check.yaml diff --git a/.github/workflows/PR-wip-checks.yaml b/.github/workflows/PR-wip-checks.yaml new file mode 100644 index 00000000..16f8167b --- /dev/null +++ b/.github/workflows/PR-wip-checks.yaml @@ -0,0 +1,21 @@ +name: Pull request WIP checks +on: + pull_request: + types: + - opened + - synchronize + - reopened + - edited + - labeled + - unlabeled + +jobs: + pr_wip_check: + runs-on: ubuntu-latest + name: WIP Check + steps: + - name: WIP Check + uses: tim-actions/wip-check@1c2a1ca6c110026b3e2297bb2ef39e1747b5a755 + with: + labels: '["do-not-merge", "wip", "rfc"]' + keywords: '["WIP", "wip", "RFC", "rfc", "dnm", "DNM", "do-not-merge"]' diff --git a/.github/workflows/commit-message-check.yaml b/.github/workflows/commit-message-check.yaml new file mode 100644 index 00000000..4d1c57ef --- /dev/null +++ b/.github/workflows/commit-message-check.yaml @@ -0,0 +1,53 @@ +name: Commit Message Check +on: + pull_request: + types: + - opened + - reopened + - synchronize + +env: + error_msg: |+ + See the document below for help on formatting commits for the project. + + https://github.com/kata-containers/community/blob/master/CONTRIBUTING.md#patch-forma + +jobs: + commit-message-check: + runs-on: ubuntu-latest + name: Commit Message Check + steps: + - name: Get PR Commits + id: 'get-pr-commits' + uses: tim-actions/get-pr-commits@v1.0.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: DCO Check + uses: tim-actions/dco@2fd0504dc0d27b33f542867c300c60840c6dcb20 + with: + commits: ${{ steps.get-pr-commits.outputs.commits }} + + - name: Commit Body Missing Check + if: ${{ success() || failure() }} + uses: tim-actions/commit-body-check@v1.0.2 + with: + commits: ${{ steps.get-pr-commits.outputs.commits }} + + - name: Check Subject Line Length + if: ${{ success() || failure() }} + uses: tim-actions/commit-message-checker-with-regex@v0.3.1 + with: + commits: ${{ steps.get-pr-commits.outputs.commits }} + pattern: '^.{0,75}(\n.*)*$' + error: 'Subject too long (max 75)' + post_error: ${{ env.error_msg }} + + - name: Check Body Line Length + if: ${{ success() || failure() }} + uses: tim-actions/commit-message-checker-with-regex@v0.3.1 + with: + commits: ${{ steps.get-pr-commits.outputs.commits }} + pattern: '^.+(\n.{0,72})*$|^.+\n\s*[^a-zA-Z\s\n]|^.+\n\S+$' + error: 'Body line too long (max 72)' + post_error: ${{ env.error_msg }} From 152af17f8f2abe4cfef28e143470a6fff783be06 Mon Sep 17 00:00:00 2001 From: bin liu Date: Wed, 23 Sep 2020 15:43:05 +0800 Subject: [PATCH 20/71] fix build warnings And in Travis CI, treat warnings as error to keep from merging codes with warning. Fixes: #13 Signed-off-by: bin liu --- .travis.yml | 2 +- src/blkio.rs | 3 ++- src/cgroup.rs | 6 +++--- src/cgroup_builder.rs | 5 ++--- src/cpu.rs | 3 ++- src/cpuacct.rs | 3 ++- src/cpuset.rs | 7 ++----- src/devices.rs | 3 ++- src/error.rs | 4 ++-- src/events.rs | 4 ++-- src/freezer.rs | 3 ++- src/hierarchies.rs | 4 ++-- src/hugetlb.rs | 8 +++++++- src/memory.rs | 12 +++++++----- src/net_cls.rs | 3 ++- src/net_prio.rs | 3 ++- src/perf_event.rs | 3 ++- src/pid.rs | 3 ++- src/rdma.rs | 3 ++- src/systemd.rs | 4 ++-- 20 files changed, 50 insertions(+), 36 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0a028bc4..298cd6aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ install: - rustup component add rustfmt script: - - cargo build + - RUSTFLAGS="--deny warnings" cargo build - if [ "$TRAVIS_CPU_ARCH" == "amd64" ]; then cargo test -- --color always --nocapture ; fi - cargo fmt -- --check diff --git a/src/blkio.rs b/src/blkio.rs index 153a68e7..f648343b 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -396,7 +396,8 @@ impl<'a> From<&'a Subsystem> for &'a BlkIoController { Subsystem::BlkIo(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/cgroup.rs b/src/cgroup.rs index 4fada605..13308a88 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -43,7 +43,7 @@ impl<'b> Cgroup<'b> { /// Create this control group. fn create(&self) { if self.hier.v2() { - create_v2_cgroup(self.hier.root().clone(), &self.path); + let _ret = create_v2_cgroup(self.hier.root().clone(), &self.path); } else { for subsystem in &self.subsystems { subsystem.to_controller().create(); @@ -272,7 +272,7 @@ fn enable_controllers(controllers: &Vec, path: &PathBuf) { } } -fn supported_controllers(p: &PathBuf) -> Vec { +fn supported_controllers() -> Vec { let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers"); let ret = fs::read_to_string(p.as_str()); ret.unwrap_or(String::new()) @@ -283,7 +283,7 @@ fn supported_controllers(p: &PathBuf) -> Vec { fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { // controler list ["memory", "cpu"] - let controllers = supported_controllers(&root); + let controllers = supported_controllers(); let mut fp = root; // enable for root diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index 094535c7..0432fa52 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -60,10 +60,9 @@ //! .done() //! .build(); //! ``` -use crate::error::*; use crate::{ - pid, BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy, + BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy, HugePageResource, MaxValue, NetworkPriority, Resources, }; @@ -141,7 +140,7 @@ impl<'a> CgroupBuilder<'a> { /// Finalize the control group, consuming the builder and creating the control group. pub fn build(self) -> Cgroup<'a> { let cg = Cgroup::new(self.hierarchy, self.name); - cg.apply(&self.resources); + let _ret = cg.apply(&self.resources); cg } } diff --git a/src/cpu.rs b/src/cpu.rs index b222db89..535de668 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -111,7 +111,8 @@ impl<'a> From<&'a Subsystem> for &'a CpuController { Subsystem::Cpu(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/cpuacct.rs b/src/cpuacct.rs index 4171c6d1..0924d957 100644 --- a/src/cpuacct.rs +++ b/src/cpuacct.rs @@ -89,7 +89,8 @@ impl<'a> From<&'a Subsystem> for &'a CpuAcctController { Subsystem::CpuAcct(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/cpuset.rs b/src/cpuset.rs index 92754c00..28de1eba 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -125,10 +125,6 @@ impl ControllerInternal for CpuSetController { return; } let current = self.get_path(); - let parent = match current.parent() { - Some(p) => p, - None => return, - }; if current != self.get_base() { match copy_from_parent(current.to_str().unwrap(), "cpuset.cpus") { @@ -204,7 +200,8 @@ impl<'a> From<&'a Subsystem> for &'a CpuSetController { Subsystem::CpuSet(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/devices.rs b/src/devices.rs index 5e6efb99..605e7351 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -182,7 +182,8 @@ impl<'a> From<&'a Subsystem> for &'a DevicesController { Subsystem::Devices(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/error.rs b/src/error.rs index 0e4f69c0..1a273ab5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -45,7 +45,7 @@ pub enum ErrorKind { #[derive(Debug)] pub struct Error { kind: ErrorKind, - cause: Option>, + cause: Option>, } impl fmt::Display for Error { @@ -67,7 +67,7 @@ impl fmt::Display for Error { } impl StdError for Error { - fn cause(&self) -> Option<&StdError> { + fn cause(&self) -> Option<&dyn StdError> { match self.cause { Some(ref x) => Some(&**x), None => None, diff --git a/src/events.rs b/src/events.rs index da0b718e..b06f3c03 100644 --- a/src/events.rs +++ b/src/events.rs @@ -60,7 +60,7 @@ fn register_memory_event( } // write to file and set mode to 0700(FIXME) - fs::write(&event_control_path, data).map_err(|e| Error::with_cause(WriteFailed, e)); + fs::write(&event_control_path, data).map_err(|e| Error::with_cause(WriteFailed, e))?; let mut eventfd_file = unsafe { File::from_raw_fd(eventfd) }; @@ -71,7 +71,7 @@ fn register_memory_event( loop { let mut buf = [0; 8]; match eventfd_file.read(&mut buf) { - Err(err) => { + Err(_err) => { return; } Ok(_) => {} diff --git a/src/freezer.rs b/src/freezer.rs index 92d8c2cd..c9da3792 100644 --- a/src/freezer.rs +++ b/src/freezer.rs @@ -73,7 +73,8 @@ impl<'a> From<&'a Subsystem> for &'a FreezerController { Subsystem::Freezer(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 4b8f1eb0..b47451da 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -107,7 +107,7 @@ impl Hierarchy for V1 { } fn root_control_group(&self) -> Cgroup { - let b: &Hierarchy = self as &Hierarchy; + let b: &dyn Hierarchy = self as &dyn Hierarchy; Cgroup::load(Box::new(&*b), "".to_string()) } @@ -182,7 +182,7 @@ impl Hierarchy for V2 { } fn root_control_group(&self) -> Cgroup { - let b: &Hierarchy = self as &Hierarchy; + let b: &dyn Hierarchy = self as &dyn Hierarchy; Cgroup::load(Box::new(&*b), "".to_string()) } diff --git a/src/hugetlb.rs b/src/hugetlb.rs index 4237c116..c65b4f45 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -79,7 +79,8 @@ impl<'a> From<&'a Subsystem> for &'a HugeTlbController { Subsystem::HugeTlb(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } @@ -225,10 +226,15 @@ pub const GB: u128 = 1000 * MB; pub const TB: u128 = 1000 * GB; pub const PB: u128 = 1000 * TB; +#[allow(non_upper_case_globals)] pub const KiB: u128 = 1024; +#[allow(non_upper_case_globals)] pub const MiB: u128 = 1024 * KiB; +#[allow(non_upper_case_globals)] pub const GiB: u128 = 1024 * MiB; +#[allow(non_upper_case_globals)] pub const TiB: u128 = 1024 * GiB; +#[allow(non_upper_case_globals)] pub const PiB: u128 = 1024 * TiB; pub fn get_binary_size_map() -> HashMap { diff --git a/src/memory.rs b/src/memory.rs index 0f193f30..9f641e85 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -505,10 +505,11 @@ impl MemController { // for v2 pub fn get_mem(&self) -> Result { let mut m: SetMemory = Default::default(); - self.get_max_value("memory.high").map(|x| m.high = Some(x)); - self.get_max_value("memory.low").map(|x| m.low = Some(x)); - self.get_max_value("memory.max").map(|x| m.max = Some(x)); - self.get_max_value("memory.min").map(|x| m.min = Some(x)); + self.get_max_value("memory.high") + .map(|x| m.high = Some(x))?; + self.get_max_value("memory.low").map(|x| m.low = Some(x))?; + self.get_max_value("memory.max").map(|x| m.max = Some(x))?; + self.get_max_value("memory.min").map(|x| m.min = Some(x))?; Ok(m) } @@ -831,7 +832,8 @@ impl<'a> From<&'a Subsystem> for &'a MemController { Subsystem::Mem(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/net_cls.rs b/src/net_cls.rs index 4d923ffa..860ae8db 100644 --- a/src/net_cls.rs +++ b/src/net_cls.rs @@ -70,7 +70,8 @@ impl<'a> From<&'a Subsystem> for &'a NetClsController { Subsystem::NetCls(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/net_prio.rs b/src/net_prio.rs index a4d0b6e0..ed16ed97 100644 --- a/src/net_prio.rs +++ b/src/net_prio.rs @@ -71,7 +71,8 @@ impl<'a> From<&'a Subsystem> for &'a NetPrioController { Subsystem::NetPrio(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/perf_event.rs b/src/perf_event.rs index e7ffe6db..09eefc6f 100644 --- a/src/perf_event.rs +++ b/src/perf_event.rs @@ -55,7 +55,8 @@ impl<'a> From<&'a Subsystem> for &'a PerfEventController { Subsystem::PerfEvent(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/pid.rs b/src/pid.rs index f1ed8453..d08ba303 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -85,7 +85,8 @@ impl<'a> From<&'a Subsystem> for &'a PidController { Subsystem::Pid(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/rdma.rs b/src/rdma.rs index 1de74585..9d366d25 100644 --- a/src/rdma.rs +++ b/src/rdma.rs @@ -58,7 +58,8 @@ impl<'a> From<&'a Subsystem> for &'a RdmaController { Subsystem::Rdma(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } diff --git a/src/systemd.rs b/src/systemd.rs index 9c9d36d8..545c4116 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -7,7 +7,6 @@ //! use std::path::PathBuf; -use crate::error::ErrorKind::*; use crate::error::*; use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem}; @@ -53,7 +52,8 @@ impl<'a> From<&'a Subsystem> for &'a SystemdController { Subsystem::Systemd(c) => c, _ => { assert_eq!(1, 0); - ::std::mem::uninitialized() + let v = std::mem::MaybeUninit::uninit(); + v.assume_init() } } } From efb98108fcd23b655fbb7a329d91d35f0c65d1e4 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 29 Oct 2020 19:31:27 +0800 Subject: [PATCH 21/71] Fix warnings Got: cargo build --target x86_64-unknown-linux-musl Compiling cgroups v0.1.1-alpha.0 (/home/tim/project/cgroups-rs) warning: unused import: `nix::sys::statfs` --> src/hierarchies.rs:220:5 | 220 | use nix::sys::statfs; | ^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default warning: 1 warning emitted Signed-off-by: Tim Zhang --- src/hierarchies.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hierarchies.rs b/src/hierarchies.rs index b47451da..e498f709 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -8,7 +8,6 @@ //! //! Currently, we only support the cgroupv1 hierarchy, but in the future we will add support for //! the Unified Hierarchy. -use nix::sys::statfs; use std::fs::{self, File}; use std::io::BufRead; @@ -220,6 +219,8 @@ pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; #[cfg(all(target_os = "linux", not(target_env = "musl")))] pub fn is_cgroup2_unified_mode() -> bool { + use nix::sys::statfs; + let path = Path::new(UNIFIED_MOUNTPOINT); let fs_stat = statfs::statfs(path); if fs_stat.is_err() { From 42eb32765bdef575eba3719abbd966958bd17671 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 29 Oct 2020 19:32:55 +0800 Subject: [PATCH 22/71] Make methods to_controller and controller_name of Subsystem public We need these functions to detect whether subsystem path exists. Signed-off-by: Tim Zhang --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c9103710..0761631e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -619,7 +619,7 @@ impl Subsystem { } } - fn to_controller(&self) -> &dyn Controller { + pub fn to_controller(&self) -> &dyn Controller { match self { Subsystem::Pid(cont) => cont, Subsystem::Mem(cont) => cont, @@ -638,7 +638,7 @@ impl Subsystem { } } - fn controller_name(&self) -> String { + pub fn controller_name(&self) -> String { self.to_controller().control_type().to_string() } } From 6f9e89572e917a58305051f50dd8875ff173af03 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 29 Oct 2020 19:35:39 +0800 Subject: [PATCH 23/71] MemController: add method reset_max_usage We need a method to reset the max memory usage recorded. Signed-off-by: Tim Zhang --- src/memory.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/memory.rs b/src/memory.rs index 9f641e85..9b1e8040 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -733,6 +733,15 @@ impl MemController { }) } + /// Reset the max memory usage recorded + pub fn reset_max_usage(&self) -> Result<()> { + self.open_path("memory.max_usage_in_bytes", true) + .and_then(|mut file| { + file.write_all("0".to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) + } + /// Set the memory usage limit of the control group, in bytes. pub fn set_limit(&self, limit: i64) -> Result<()> { let mut file = "memory.limit_in_bytes"; From ca610bb57e8872680264ad89164bdd5a3b3b2e4e Mon Sep 17 00:00:00 2001 From: "Yang, Wei" Date: Fri, 24 Jul 2020 19:14:40 +0800 Subject: [PATCH 24/71] add add_task_by_tgid Add task by writing thread group id to cgroup.procs. Signed-off-by: Yang, Wei Signed-off-by: Tim Zhang --- src/cgroup.rs | 7 +++++++ src/lib.rs | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/cgroup.rs b/src/cgroup.rs index 13308a88..8e6dd970 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -233,6 +233,13 @@ impl<'b> Cgroup<'b> { } } + /// Attach a task to the control group by thread group id. + pub fn add_task_by_tgid(&self, pid: CgroupPid) -> Result<()> { + self.subsystems() + .iter() + .try_for_each(|sub| sub.to_controller().add_task_by_tgid(&pid)) + } + /// Returns an Iterator that can be used to iterate over the tasks that are currently in the /// control group. pub fn tasks(&self) -> Vec { diff --git a/src/lib.rs b/src/lib.rs index 0761631e..c94f73e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -219,6 +219,9 @@ pub trait Controller { /// Attach a task to this controller. fn add_task(&self, pid: &CgroupPid) -> Result<()>; + /// Attach a task to this controller. + fn add_task_by_tgid(&self, pid: &CgroupPid) -> Result<()>; + /// Get the list of tasks that this controller has. fn tasks(&self) -> Vec; @@ -278,6 +281,14 @@ where }) } + /// Attach a task to this controller by thread group id. + fn add_task_by_tgid(&self, pid: &CgroupPid) -> Result<()> { + self.open_path("cgroup.procs", true).and_then(|mut file| { + file.write_all(pid.pid.to_string().as_ref()) + .map_err(|e| Error::with_cause(ErrorKind::WriteFailed, e)) + }) + } + /// Get the list of tasks that this controller has. fn tasks(&self) -> Vec { let mut file = "tasks"; From 0c18b0855e27ceb3e7840259e544490361bf9bce Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 4 Nov 2020 18:03:42 +0800 Subject: [PATCH 25/71] Support customized attributes for CpuController and MemController Customized attributes are useful for customized kernels. Usage: let resource = &mut cgroups::Resources::default(); resource.cpu.attrs.insert("cpu.cfs_init_buffer_us", "10".to_string()); // apply here Signed-off-by: Tim Zhang --- src/cpu.rs | 10 ++++++++-- src/lib.rs | 39 ++++++++++++++++++++++++++++++++++++++- src/memory.rs | 6 ++++-- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 535de668..9f349112 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -18,8 +18,8 @@ use crate::error::*; use crate::{parse_max_value, read_i64_from}; use crate::{ - ControllIdentifier, ControllerInternal, Controllers, CpuResources, MaxValue, Resources, - Subsystem, + ControllIdentifier, ControllerInternal, Controllers, CpuResources, CustomizedAttribute, + MaxValue, Resources, Subsystem, }; /// A controller that allows controlling the `cpu` subsystem of a Cgroup. @@ -91,6 +91,10 @@ impl ControllerInternal for CpuController { return Err(Error::new(ErrorKind::Other)); } + res.attrs.iter().for_each(|(k, v)| { + let _ = self.set(k, v); + }) + // TODO: rt properties (CONFIG_RT_GROUP_SCHED) are not yet supported } @@ -306,6 +310,8 @@ impl CpuController { } } +impl CustomizedAttribute for CpuController {} + fn parse_cfs_quota_and_period(mut file: File) -> Result { let mut content = String::new(); file.read_to_string(&mut content) diff --git a/src/lib.rs b/src/lib.rs index c94f73e2..d1aa71fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -189,9 +189,22 @@ mod sealed { std::path::Path::new(p).exists() } } + + pub trait CustomizedAttribute: ControllerInternal { + fn set(&self, key: &str, value: &str) -> Result<()> { + self.open_path(key, true).and_then(|mut file| { + file.write_all(value.as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) + } + + fn get(&self, key: &str) -> Result { + self.open_path(key, false).and_then(read_str_from) + } + } } -pub(crate) use crate::sealed::ControllerInternal; +pub(crate) use crate::sealed::{ControllerInternal, CustomizedAttribute}; /// A Controller is a subsystem attached to the control group. /// @@ -363,6 +376,14 @@ pub struct MemoryResources { /// Note, however, that a value of zero does not mean the process is never swapped out. Use the /// traditional `mlock(2)` system call for that purpose. pub swappiness: u64, + /// Customized key-value attributes + /// + /// # Usage: + /// ``` + /// let resource = &mut cgroups::Resources::default(); + /// resource.memory.attrs.insert("memory.numa_balancing", "true".to_string()); + /// // apply here + pub attrs: std::collections::HashMap<&'static str, String>, } /// Resources limits on the number of processes. @@ -402,6 +423,14 @@ pub struct CpuResources { pub realtime_runtime: i64, /// This is currently a no-operation. pub realtime_period: u64, + /// Customized key-value attributes + /// # Usage: + /// ``` + /// let resource = &mut cgroups::Resources::default(); + /// resource.cpu.attrs.insert("cpu.cfs_init_buffer_us", "10".to_string()); + /// // apply here + /// ``` + pub attrs: std::collections::HashMap<&'static str, String>, } /// A device resource that can be allowed or denied access to. @@ -791,3 +820,11 @@ pub fn read_i64_from(mut file: File) -> Result { Err(e) => Err(Error::with_cause(ReadFailed, e)), } } + +pub fn read_str_from(mut file: File) -> Result { + let mut string = String::new(); + match file.read_to_string(&mut string) { + Ok(_) => Ok(string.trim().to_owned()), + Err(e) => Err(Error::with_cause(ReadFailed, e)), + } +} diff --git a/src/memory.rs b/src/memory.rs index 9b1e8040..0e3ea8c7 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -21,8 +21,8 @@ use crate::events; use crate::flat_keyed_to_hashmap; use crate::{ - ControllIdentifier, ControllerInternal, Controllers, MaxValue, MemoryResources, Resources, - Subsystem, + ControllIdentifier, ControllerInternal, Controllers, CustomizedAttribute, MaxValue, + MemoryResources, Resources, Subsystem, }; /// A controller that allows controlling the `memory` subsystem of a Cgroup. @@ -834,6 +834,8 @@ impl ControllIdentifier for MemController { } } +impl CustomizedAttribute for MemController {} + impl<'a> From<&'a Subsystem> for &'a MemController { fn from(sub: &'a Subsystem) -> &'a MemController { unsafe { From 567cdb43b3cbc58f45fed900b139ccc41d6332ee Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 5 Nov 2020 11:18:39 +0800 Subject: [PATCH 26/71] Use Option as resource fields, remove the update switch: update_values Use idiomatic Option::None to represent optional fields. This enables updates where not all fields need to be specified. Signed-off-by: Tim Zhang --- src/blkio.rs | 51 +++++++++++++++++------------------- src/cgroup_builder.rs | 26 +++++------------- src/cpu.rs | 27 +++++-------------- src/cpuset.rs | 8 ++---- src/devices.rs | 12 ++++----- src/hugetlb.rs | 11 ++++---- src/lib.rs | 61 +++++++++++++++++++++++-------------------- src/memory.rs | 14 +++++----- src/net_cls.rs | 8 ++---- src/net_prio.rs | 6 ++--- src/pid.rs | 18 +++++-------- 11 files changed, 99 insertions(+), 143 deletions(-) diff --git a/src/blkio.rs b/src/blkio.rs index f648343b..b0f78a2b 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -344,39 +344,36 @@ impl ControllerInternal for BlkIoController { // get the resources that apply to this controller let res: &BlkIoResources = &res.blkio; - if res.update_values { - if let Some(weight) = res.weight { - let _ = self.set_weight(weight as u64); - } - if let Some(leaf_weight) = res.leaf_weight { - let _ = self.set_leaf_weight(leaf_weight as u64); - } + if let Some(weight) = res.weight { + let _ = self.set_weight(weight as u64); + } + if let Some(leaf_weight) = res.leaf_weight { + let _ = self.set_leaf_weight(leaf_weight as u64); + } - for dev in &res.weight_device { - if let Some(weight) = dev.weight { - let _ = self.set_weight_for_device(dev.major, dev.minor, weight as u64); - } - if let Some(leaf_weight) = dev.leaf_weight { - let _ = - self.set_leaf_weight_for_device(dev.major, dev.minor, leaf_weight as u64); - } + for dev in &res.weight_device { + if let Some(weight) = dev.weight { + let _ = self.set_weight_for_device(dev.major, dev.minor, weight as u64); } - - for dev in &res.throttle_read_bps_device { - let _ = self.throttle_read_bps_for_device(dev.major, dev.minor, dev.rate); + if let Some(leaf_weight) = dev.leaf_weight { + let _ = self.set_leaf_weight_for_device(dev.major, dev.minor, leaf_weight as u64); } + } - for dev in &res.throttle_write_bps_device { - let _ = self.throttle_write_bps_for_device(dev.major, dev.minor, dev.rate); - } + for dev in &res.throttle_read_bps_device { + let _ = self.throttle_read_bps_for_device(dev.major, dev.minor, dev.rate); + } - for dev in &res.throttle_read_iops_device { - let _ = self.throttle_read_iops_for_device(dev.major, dev.minor, dev.rate); - } + for dev in &res.throttle_write_bps_device { + let _ = self.throttle_write_bps_for_device(dev.major, dev.minor, dev.rate); + } - for dev in &res.throttle_write_iops_device { - let _ = self.throttle_write_iops_for_device(dev.major, dev.minor, dev.rate); - } + for dev in &res.throttle_read_iops_device { + let _ = self.throttle_read_iops_for_device(dev.major, dev.minor, dev.rate); + } + + for dev in &res.throttle_write_iops_device { + let _ = self.throttle_write_iops_for_device(dev.major, dev.minor, dev.rate); } Ok(()) diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index 0432fa52..174b8eca 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -47,8 +47,8 @@ //! .limit("2G".to_string(), 2 * 1024 * 1024 * 1024) //! .done() //! .blkio() -//! .weight(Some(123)) -//! .leaf_weight(Some(99)) +//! .weight(123) +//! .leaf_weight(99) //! .weight_device(6, 1, Some(100), Some(55)) //! .weight_device(6, 1, Some(100), Some(55)) //! .throttle_iops() @@ -70,8 +70,7 @@ macro_rules! gen_setter { ($res:ident, $cont:ident, $func:ident, $name:ident, $ty:ty) => { /// See the similarly named function in the respective controller. pub fn $name(mut self, $name: $ty) -> Self { - self.cgroup.resources.$res.update_values = true; - self.cgroup.resources.$res.$name = $name; + self.cgroup.resources.$res.$name = Some($name); self } }; @@ -214,8 +213,7 @@ pub struct CpuResourceBuilder<'a> { } impl<'a> CpuResourceBuilder<'a> { - // FIXME this should all changed to options. - gen_setter!(cpu, CpuSetController, set_cpus, cpus, Option); + gen_setter!(cpu, CpuSetController, set_cpus, cpus, String); gen_setter!(cpu, CpuSetController, set_mems, mems, String); gen_setter!(cpu, CpuController, set_shares, shares, u64); gen_setter!(cpu, CpuController, set_cfs_quota, quota, i64); @@ -244,7 +242,6 @@ impl<'a> DeviceResourceBuilder<'a> { allow: bool, access: Vec, ) -> DeviceResourceBuilder<'a> { - self.cgroup.resources.devices.update_values = true; self.cgroup.resources.devices.devices.push(DeviceResource { major, minor, @@ -272,7 +269,6 @@ impl<'a> NetworkResourceBuilder<'a> { /// Set the priority of the tasks when operating on a networking device defined by `name` to be /// `priority`. pub fn priority(mut self, name: String, priority: u64) -> NetworkResourceBuilder<'a> { - self.cgroup.resources.network.update_values = true; self.cgroup .resources .network @@ -295,7 +291,6 @@ pub struct HugepagesResourceBuilder<'a> { impl<'a> HugepagesResourceBuilder<'a> { /// Limit the usage of certain hugepages (determined by `size`) to be at most `limit` bytes. pub fn limit(mut self, size: String, limit: u64) -> HugepagesResourceBuilder<'a> { - self.cgroup.resources.hugepages.update_values = true; self.cgroup .resources .hugepages @@ -317,14 +312,8 @@ pub struct BlkIoResourcesBuilder<'a> { } impl<'a> BlkIoResourcesBuilder<'a> { - gen_setter!(blkio, BlkIoController, set_weight, weight, Option); - gen_setter!( - blkio, - BlkIoController, - set_leaf_weight, - leaf_weight, - Option - ); + gen_setter!(blkio, BlkIoController, set_weight, weight, u16); + gen_setter!(blkio, BlkIoController, set_leaf_weight, leaf_weight, u16); /// Set the weight of a certain device. pub fn weight_device( @@ -334,7 +323,6 @@ impl<'a> BlkIoResourcesBuilder<'a> { weight: Option, leaf_weight: Option, ) -> BlkIoResourcesBuilder<'a> { - self.cgroup.resources.blkio.update_values = true; self.cgroup .resources .blkio @@ -362,7 +350,6 @@ impl<'a> BlkIoResourcesBuilder<'a> { /// Limit the read rate of the current metric for a certain device. pub fn read(mut self, major: u64, minor: u64, rate: u64) -> BlkIoResourcesBuilder<'a> { - self.cgroup.resources.blkio.update_values = true; let throttle = BlkIoDeviceThrottleResource { major, minor, rate }; if self.throttling_iops { self.cgroup @@ -382,7 +369,6 @@ impl<'a> BlkIoResourcesBuilder<'a> { /// Limit the write rate of the current metric for a certain device. pub fn write(mut self, major: u64, minor: u64, rate: u64) -> BlkIoResourcesBuilder<'a> { - self.cgroup.resources.blkio.update_values = true; let throttle = BlkIoDeviceThrottleResource { major, minor, rate }; if self.throttling_iops { self.cgroup diff --git a/src/cpu.rs b/src/cpu.rs index 9f349112..105a4388 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -75,28 +75,15 @@ impl ControllerInternal for CpuController { // get the resources that apply to this controller let res: &CpuResources = &res.cpu; - if res.update_values { - let _ = self.set_shares(res.shares); - if self.shares()? != res.shares as u64 { - return Err(Error::new(ErrorKind::Other)); - } - - let _ = self.set_cfs_period(res.period); - if self.cfs_period()? != res.period as u64 { - return Err(Error::new(ErrorKind::Other)); - } + update_and_test!(self, set_shares, res.shares, shares); + update_and_test!(self, set_cfs_period, res.period, cfs_period); + update_and_test!(self, set_cfs_quota, res.quota, cfs_quota); - let _ = self.set_cfs_quota(res.quota); - if self.cfs_quota()? != res.quota { - return Err(Error::new(ErrorKind::Other)); - } + res.attrs.iter().for_each(|(k, v)| { + let _ = self.set(k, v); + }); - res.attrs.iter().for_each(|(k, v)| { - let _ = self.set(k, v); - }) - - // TODO: rt properties (CONFIG_RT_GROUP_SCHED) are not yet supported - } + // TODO: rt properties (CONFIG_RT_GROUP_SCHED) are not yet supported Ok(()) } diff --git a/src/cpuset.rs b/src/cpuset.rs index 28de1eba..4d4427d1 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -110,12 +110,8 @@ impl ControllerInternal for CpuSetController { // get the resources that apply to this controller let res: &CpuResources = &res.cpu; - if res.update_values { - if res.cpus.is_some() { - let _ = self.set_cpus(res.cpus.as_ref().unwrap().as_str()); - } - let _ = self.set_mems(&res.mems); - } + update!(self, set_cpus, res.cpus.as_ref()); + update!(self, set_mems, res.mems.as_ref()); Ok(()) } diff --git a/src/devices.rs b/src/devices.rs index 605e7351..5a78a2ef 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -155,13 +155,11 @@ impl ControllerInternal for DevicesController { // get the resources that apply to this controller let res: &DeviceResources = &res.devices; - if res.update_values { - for i in &res.devices { - if i.allow { - let _ = self.allow_device(i.devtype, i.major, i.minor, &i.access); - } else { - let _ = self.deny_device(i.devtype, i.major, i.minor, &i.access); - } + for i in &res.devices { + if i.allow { + let _ = self.allow_device(i.devtype, i.major, i.minor, &i.access); + } else { + let _ = self.deny_device(i.devtype, i.major, i.minor, &i.access); } } diff --git a/src/hugetlb.rs b/src/hugetlb.rs index c65b4f45..d9e8d3cf 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -54,14 +54,13 @@ impl ControllerInternal for HugeTlbController { // get the resources that apply to this controller let res: &HugePageResources = &res.hugepages; - if res.update_values { - for i in &res.limits { - let _ = self.set_limit_in_bytes(&i.size, i.limit); - if self.limit_in_bytes(&i.size)? != i.limit { - return Err(Error::new(Other)); - } + for i in &res.limits { + let _ = self.set_limit_in_bytes(&i.size, i.limit); + if self.limit_in_bytes(&i.size)? != i.limit { + return Err(Error::new(Other)); } } + Ok(()) } } diff --git a/src/lib.rs b/src/lib.rs index d1aa71fd..9fe2befb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,25 @@ use std::fs::File; use std::io::{BufRead, BufReader, Read, Write}; use std::path::{Path, PathBuf}; +macro_rules! update_and_test { + ($self: ident, $set_func:ident, $value:expr, $get_func:ident) => { + if let Some(v) = $value { + $self.$set_func(v)?; + if $self.$get_func()? != v { + return Err(Error::new(Other)); + } + } + }; +} + +macro_rules! update { + ($self: ident, $set_func:ident, $value:expr) => { + if let Some(v) = $value { + let _ = $self.$set_func(v); + } + }; +} + pub mod blkio; pub mod cgroup; pub mod cgroup_builder; @@ -357,25 +376,23 @@ pub trait Hierarchy { /// Resource limits for the memory subsystem. #[derive(Debug, Clone, Eq, PartialEq, Default)] pub struct MemoryResources { - /// Whether values should be applied to the controller. - pub update_values: bool, /// How much memory (in bytes) can the kernel consume. - pub kernel_memory_limit: i64, + pub kernel_memory_limit: Option, /// Upper limit of memory usage of the control group's tasks. - pub memory_hard_limit: i64, + pub memory_hard_limit: Option, /// How much memory the tasks in the control group can use when the system is under memory /// pressure. - pub memory_soft_limit: i64, + pub memory_soft_limit: Option, /// How much of the kernel's memory (in bytes) can be used for TCP-related buffers. - pub kernel_tcp_memory_limit: i64, + pub kernel_tcp_memory_limit: Option, /// How much memory and swap together can the tasks in the control group use. - pub memory_swap_limit: i64, + pub memory_swap_limit: Option, /// Controls the tendency of the kernel to swap out parts of the address space of the tasks to /// disk. Lower value implies less likely. /// /// Note, however, that a value of zero does not mean the process is never swapped out. Use the /// traditional `mlock(2)` system call for that purpose. - pub swappiness: u64, + pub swappiness: Option, /// Customized key-value attributes /// /// # Usage: @@ -389,40 +406,36 @@ pub struct MemoryResources { /// Resources limits on the number of processes. #[derive(Debug, Clone, Eq, PartialEq, Default)] pub struct PidResources { - /// Whether values should be applied to the controller. - pub update_values: bool, /// The maximum number of processes that can exist in the control group. /// /// Note that attaching processes to the control group will still succeed _even_ if the limit /// would be violated, however forks/clones inside the control group will have with `EAGAIN` if /// they would violate the limit set here. - pub maximum_number_of_processes: MaxValue, + pub maximum_number_of_processes: Option, } /// Resources limits about how the tasks can use the CPU. #[derive(Debug, Clone, Eq, PartialEq, Default)] pub struct CpuResources { - /// Whether values should be applied to the controller. - pub update_values: bool, // cpuset /// A comma-separated list of CPU IDs where the task in the control group can run. Dashes /// between numbers indicate ranges. pub cpus: Option, /// Same syntax as the `cpus` field of this structure, but applies to memory nodes instead of /// processors. - pub mems: String, + pub mems: Option, // cpu /// Weight of how much of the total CPU time should this control group get. Note that this is /// hierarchical, so this is weighted against the siblings of this control group. - pub shares: u64, + pub shares: Option, /// In one `period`, how much can the tasks run in nanoseconds. - pub quota: i64, + pub quota: Option, /// Period of time in nanoseconds. - pub period: u64, + pub period: Option, /// This is currently a no-operation. - pub realtime_runtime: i64, + pub realtime_runtime: Option, /// This is currently a no-operation. - pub realtime_period: u64, + pub realtime_period: Option, /// Customized key-value attributes /// # Usage: /// ``` @@ -451,8 +464,6 @@ pub struct DeviceResource { /// Limit the usage of devices for the control group's tasks. #[derive(Debug, Clone, Eq, PartialEq, Default)] pub struct DeviceResources { - /// Whether values should be applied to the controller. - pub update_values: bool, /// For each device in the list, the limits in the structure are applied. pub devices: Vec, } @@ -470,12 +481,10 @@ pub struct NetworkPriority { /// control group. #[derive(Debug, Clone, Eq, PartialEq, Default)] pub struct NetworkResources { - /// Whether values should be applied to the controller. - pub update_values: bool, /// The networking class identifier to attach to the packets. /// /// This can then later be used in iptables and such to have special rules. - pub class_id: u64, + pub class_id: Option, /// Priority of the egress traffic for each interface. pub priorities: Vec, } @@ -493,8 +502,6 @@ pub struct HugePageResource { /// Provides the ability to set consumption limit on each type of hugepages. #[derive(Debug, Clone, Eq, PartialEq, Default)] pub struct HugePageResources { - /// Whether values should be applied to the controller. - pub update_values: bool, /// Set a limit of consumption for each hugepages type. pub limits: Vec, } @@ -526,8 +533,6 @@ pub struct BlkIoDeviceThrottleResource { /// General block I/O resource limits. #[derive(Debug, Clone, Eq, PartialEq, Default)] pub struct BlkIoResources { - /// Whether values should be applied to the controller. - pub update_values: bool, /// The weight of the control group against descendant nodes. pub weight: Option, /// The weight of the control group against sibling nodes. diff --git a/src/memory.rs b/src/memory.rs index 0e3ea8c7..3b48289f 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -453,14 +453,12 @@ impl ControllerInternal for MemController { // get the resources that apply to this controller let memres: &MemoryResources = &res.memory; - if memres.update_values { - let _ = self.set_limit(memres.memory_hard_limit); - let _ = self.set_soft_limit(memres.memory_soft_limit); - let _ = self.set_kmem_limit(memres.kernel_memory_limit); - let _ = self.set_memswap_limit(memres.memory_swap_limit); - let _ = self.set_tcp_limit(memres.kernel_tcp_memory_limit); - let _ = self.set_swappiness(memres.swappiness); - } + update!(self, set_limit, memres.memory_hard_limit); + update!(self, set_soft_limit, memres.memory_soft_limit); + update!(self, set_kmem_limit, memres.kernel_memory_limit); + update!(self, set_memswap_limit, memres.memory_swap_limit); + update!(self, set_tcp_limit, memres.kernel_tcp_memory_limit); + update!(self, set_swappiness, memres.swappiness); Ok(()) } diff --git a/src/net_cls.rs b/src/net_cls.rs index 860ae8db..ad2af39d 100644 --- a/src/net_cls.rs +++ b/src/net_cls.rs @@ -47,12 +47,8 @@ impl ControllerInternal for NetClsController { // get the resources that apply to this controller let res: &NetworkResources = &res.network; - if res.update_values { - let _ = self.set_class(res.class_id); - if self.get_class()? != res.class_id { - return Err(Error::new(Other)); - } - } + update_and_test!(self, set_class, res.class_id, get_class); + return Ok(()); } } diff --git a/src/net_prio.rs b/src/net_prio.rs index ed16ed97..37287968 100644 --- a/src/net_prio.rs +++ b/src/net_prio.rs @@ -48,10 +48,8 @@ impl ControllerInternal for NetPrioController { // get the resources that apply to this controller let res: &NetworkResources = &res.network; - if res.update_values { - for i in &res.priorities { - let _ = self.set_if_prio(&i.name, i.priority); - } + for i in &res.priorities { + let _ = self.set_if_prio(&i.name, i.priority); } Ok(()) diff --git a/src/pid.rs b/src/pid.rs index d08ba303..e9c48698 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -50,17 +50,13 @@ impl ControllerInternal for PidController { // get the resources that apply to this controller let pidres: &PidResources = &res.pid; - if pidres.update_values { - // apply pid_max - let _ = self.set_pid_max(pidres.maximum_number_of_processes); - - // now, verify - if self.get_pid_max()? == pidres.maximum_number_of_processes { - return Ok(()); - } else { - return Err(Error::new(Other)); - } - } + // apply pid_max + update_and_test!( + self, + set_pid_max, + pidres.maximum_number_of_processes, + get_pid_max + ); Ok(()) } From 10650e2b1653e50b73b08ed0810bfa273cdb3bfd Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 9 Nov 2020 18:58:05 +0800 Subject: [PATCH 27/71] Update tests to adapt new type of fields in resource The type has been changed to Option type. Signed-off-by: Tim Zhang --- tests/builder.rs | 2 +- tests/resources.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/builder.rs b/tests/builder.rs index fced12ae..cb19bfa7 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -159,7 +159,7 @@ pub fn test_blkio_res_build() { let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build", h) .blkio() - .weight(Some(100)) + .weight(100) .done() .build(); diff --git a/tests/resources.rs b/tests/resources.rs index 665e4d08..40471243 100644 --- a/tests/resources.rs +++ b/tests/resources.rs @@ -16,8 +16,7 @@ fn pid_resources() { { let res = Resources { pid: PidResources { - update_values: true, - maximum_number_of_processes: MaxValue::Value(512), + maximum_number_of_processes: Some(MaxValue::Value(512)), }, ..Default::default() }; From 0f765706778513e4fcc1a2585ed0847d4106ec47 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 5 Nov 2020 19:05:14 +0800 Subject: [PATCH 28/71] Avoid exception caused by cgroup writeback feature The cgroup writeback feature requires cooperation between memcgs and blkcgs. To avoid exceptions, we should add_task for blkcg before memcg(push BlkIo before Mem). For more Information: https://www.alibabacloud.com/help/doc-detail/155509.ht Signed-off-by: Tim Zhang --- src/hierarchies.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/hierarchies.rs b/src/hierarchies.rs index e498f709..50a2bd32 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -50,12 +50,19 @@ impl Hierarchy for V1 { fn subsystems(&self) -> Vec { let mut subs = vec![]; - if self.check_support(Controllers::Pids) { - subs.push(Subsystem::Pid(PidController::new(self.root(), false))); + + // The cgroup writeback feature requires cooperation between memcgs and blkcgs + // To avoid exceptions, we should add_task for blkcg before memcg(push BlkIo before Mem) + // For more Information: https://www.alibabacloud.com/help/doc-detail/155509.htm + if self.check_support(Controllers::BlkIo) { + subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), false))); } if self.check_support(Controllers::Mem) { subs.push(Subsystem::Mem(MemController::new(self.root(), false))); } + if self.check_support(Controllers::Pids) { + subs.push(Subsystem::Pid(PidController::new(self.root(), false))); + } if self.check_support(Controllers::CpuSet) { subs.push(Subsystem::CpuSet(CpuSetController::new(self.root(), false))); } @@ -77,9 +84,6 @@ impl Hierarchy for V1 { if self.check_support(Controllers::NetCls) { subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); } - if self.check_support(Controllers::BlkIo) { - subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), false))); - } if self.check_support(Controllers::PerfEvent) { subs.push(Subsystem::PerfEvent(PerfEventController::new(self.root()))); } From 121f78d8e8c3faf87ce5da9f81bb4ab908355013 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 9 Nov 2020 15:11:36 +0800 Subject: [PATCH 29/71] Expose deletion error So that users can retry or do some aftercare. Fixes: #18 Signed-off-by: Tim Zhang --- src/cgroup.rs | 14 ++++++-------- src/error.rs | 4 ++++ src/lib.rs | 19 +++++++------------ 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/cgroup.rs b/src/cgroup.rs index 8e6dd970..4579204c 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -9,8 +9,6 @@ use crate::error::ErrorKind::*; use crate::error::*; -use crate::libc_rmdir; - use crate::{CgroupPid, ControllIdentifier, Controller, Hierarchy, Resources, Subsystem}; use std::collections::HashMap; @@ -148,17 +146,17 @@ impl<'b> Cgroup<'b> { /// system call will fail if there are any descendants. Thus, one should check whether it was /// actually removed, and remove the descendants first if not. In the future, this behavior /// will change. - pub fn delete(self) { + pub fn delete(&self) -> Result<()> { if self.v2() { if self.path != "" { let mut p = self.hier.root().clone(); - p.push(self.path); - libc_rmdir(p.to_str().unwrap()); + p.push(self.path.clone()); + return fs::remove_dir(p).map_err(|e| Error::with_cause(RemoveFailed, e)); } - return; + return Ok(()); } - self.subsystems.into_iter().for_each(|sub| match sub { + self.subsystems.iter().try_for_each(|sub| match sub { Subsystem::Pid(pidc) => pidc.delete(), Subsystem::Mem(c) => c.delete(), Subsystem::CpuSet(c) => c.delete(), @@ -173,7 +171,7 @@ impl<'b> Cgroup<'b> { Subsystem::HugeTlb(c) => c.delete(), Subsystem::Rdma(c) => c.delete(), Subsystem::Systemd(c) => c.delete(), - }); + }) } /// Apply a set of resource limits to the control group. diff --git a/src/error.rs b/src/error.rs index 1a273ab5..a8cd65ca 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,6 +19,9 @@ pub enum ErrorKind { /// An error occured while trying to read from a control group file. ReadFailed, + /// An error occured while trying to remove a control group. + RemoveFailed, + /// An error occured while trying to parse a value from a control group file. /// /// In the future, there will be some information attached to this field. @@ -55,6 +58,7 @@ impl fmt::Display for Error { ErrorKind::Common(s) => s.clone(), ErrorKind::WriteFailed => "unable to write to a control group file".to_string(), ErrorKind::ReadFailed => "unable to read a control group file".to_string(), + ErrorKind::RemoveFailed => "unable to remove a control group".to_string(), ErrorKind::ParseError => "unable to parse control group file".to_string(), ErrorKind::InvalidOperation => "the requested operation is invalid".to_string(), ErrorKind::InvalidPath => "the given path is invalid".to_string(), diff --git a/src/lib.rs b/src/lib.rs index 9fe2befb..117e88ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ use log::*; use std::collections::HashMap; -use std::fs::File; +use std::fs::{self, File}; use std::io::{BufRead, BufReader, Read, Write}; use std::path::{Path, PathBuf}; @@ -246,7 +246,7 @@ pub trait Controller { fn exists(&self) -> bool; /// Delete the controller. - fn delete(&self); + fn delete(&self) -> Result<()>; /// Attach a task to this controller. fn add_task(&self, pid: &CgroupPid) -> Result<()>; @@ -295,10 +295,12 @@ where } /// Delete the controller. - fn delete(&self) { - if self.get_path().exists() { - libc_rmdir(self.get_path().to_str().unwrap()); + fn delete(&self) -> Result<()> { + if !self.get_path().exists() { + return Ok(()); } + + fs::remove_dir(self.get_path()).map_err(|e| Error::with_cause(ErrorKind::RemoveFailed, e)) } /// Attach a task to this controller. @@ -807,13 +809,6 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result Result { let mut string = String::new(); From 1ac76b69ba0b69c11d12acfa16bafac086be2d2e Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 9 Nov 2020 15:47:25 +0800 Subject: [PATCH 30/71] Make function find_v1_mount pub The function find_v1_mount is useful for customized impl for Hierarchy. Signed-off-by: Tim Zhang --- src/hierarchies.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 50a2bd32..3588039e 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -265,7 +265,7 @@ pub fn auto() -> Box { } } -fn find_v1_mount() -> Option { +pub fn find_v1_mount() -> Option { // Open mountinfo so we can get a parseable mount list let mountinfo_path = Path::new("/proc/self/mountinfo"); From cd998f3f9b8aa4de941db5d0eb2e0fc09454067f Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 11 Nov 2020 19:36:36 +0800 Subject: [PATCH 31/71] Do not place cgroup under relative path read from cgroup by default Add new_with_corresponding_relative_paths to do the original action. Signed-off-by: Tim Zhang --- src/cgroup.rs | 57 +++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/src/cgroup.rs b/src/cgroup.rs index 4579204c..b0a8fb10 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -60,24 +60,12 @@ impl<'b> Cgroup<'b> { /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. pub fn new>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup<'b> { - let relative_paths = get_cgroups_relative_paths().unwrap(); - Cgroup::new_with_relative_paths(hier, path, relative_paths) - } - - /// Create a handle for a control group in the hierarchy `hier`, with name `path`. - /// - /// Returns a handle to the control group (that possibly does not exist until `create()` has - /// been called on the cgroup. - /// - /// Note that if the handle goes out of scope and is dropped, the control group is _not_ - /// destroyed. - pub fn load>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup<'b> { - let relative_paths = get_cgroups_relative_paths().unwrap(); - Cgroup::load_with_relative_paths(hier, path, relative_paths) + let cg = Cgroup::load(hier, path); + cg.create(); + cg } - /// Create a new control group in the hierarchy `hier`, with name `path`. - /// and relative paths from `/proc/self/cgroup` + /// Create a new control group in the hierarchy `hier`, with name `path` and `relative_paths` /// /// Returns a handle to the control group that can be used to manipulate it. /// @@ -93,8 +81,33 @@ impl<'b> Cgroup<'b> { cg } - /// Create a handle for a control group in the hierarchy `hier`, with name `path`, - /// and relative paths from `/proc/self/cgroup` + /// Create a handle for a control group in the hierarchy `hier`, with name `path`. + /// + /// Returns a handle to the control group (that possibly does not exist until `create()` has + /// been called on the cgroup. + /// + /// Note that if the handle goes out of scope and is dropped, the control group is _not_ + /// destroyed. + pub fn load>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup { + let path = path.as_ref(); + let mut subsystems = hier.subsystems(); + if path.as_os_str() != "" { + subsystems = subsystems + .into_iter() + .map(|x| x.enter(path)) + .collect::>(); + } + + let cg = Cgroup { + path: path.to_str().unwrap().to_string(), + subsystems: subsystems, + hier: hier, + }; + + cg + } + + /// Create a handle for a control group in the hierarchy `hier`, with name `path` and `relative_paths` /// /// Returns a handle to the control group (that possibly does not exist until `create()` has /// been called on the cgroup. @@ -329,13 +342,7 @@ pub fn get_cgroups_relative_paths() -> Result> { let keys: Vec<&str> = fl[1].split(',').collect(); for key in &keys { - // this is a workaround, cgroup file are using `name=systemd`, - // but if file system the name is `systemd` - if *key == "name=systemd" { - m.insert("systemd".to_string(), fl[2].to_string()); - } else { - m.insert(key.to_string(), fl[2].to_string()); - } + m.insert(key.to_string(), fl[2].to_string()); } } Ok(m) From f34225411e118540a7e11a9d321dbea60375d8a8 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 11 Nov 2020 20:02:21 +0800 Subject: [PATCH 32/71] Remove Box wrap of Cgroup.hire It's unnecessary. Signed-off-by: Tim Zhang --- src/cgroup.rs | 14 +++++++------- src/cgroup_builder.rs | 2 +- src/hierarchies.rs | 4 ++-- tests/cgroup.rs | 19 ++++--------------- tests/cpu.rs | 3 +-- tests/cpuset.rs | 9 +++------ tests/devices.rs | 3 +-- tests/hugetlb.rs | 3 +-- tests/memory.rs | 6 ++---- tests/pids.rs | 12 ++++-------- tests/resources.rs | 3 +-- 11 files changed, 27 insertions(+), 51 deletions(-) diff --git a/src/cgroup.rs b/src/cgroup.rs index b0a8fb10..9a7e8594 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -33,7 +33,7 @@ pub struct Cgroup<'b> { subsystems: Vec, /// The hierarchy. - hier: Box<&'b dyn Hierarchy>, + hier: &'b dyn Hierarchy, path: String, } @@ -59,7 +59,7 @@ impl<'b> Cgroup<'b> { /// /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. - pub fn new>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup<'b> { + pub fn new>(hier: &dyn Hierarchy, path: P) -> Cgroup { let cg = Cgroup::load(hier, path); cg.create(); cg @@ -72,10 +72,10 @@ impl<'b> Cgroup<'b> { /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. pub fn new_with_relative_paths>( - hier: Box<&'b dyn Hierarchy>, + hier: &dyn Hierarchy, path: P, relative_paths: HashMap, - ) -> Cgroup<'b> { + ) -> Cgroup { let cg = Cgroup::load_with_relative_paths(hier, path, relative_paths); cg.create(); cg @@ -88,7 +88,7 @@ impl<'b> Cgroup<'b> { /// /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. - pub fn load>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup { + pub fn load>(hier: &dyn Hierarchy, path: P) -> Cgroup { let path = path.as_ref(); let mut subsystems = hier.subsystems(); if path.as_os_str() != "" { @@ -115,10 +115,10 @@ impl<'b> Cgroup<'b> { /// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// destroyed. pub fn load_with_relative_paths>( - hier: Box<&'b dyn Hierarchy>, + hier: &dyn Hierarchy, path: P, relative_paths: HashMap, - ) -> Cgroup<'b> { + ) -> Cgroup { let path = path.as_ref(); let mut subsystems = hier.subsystems(); if path.as_os_str() != "" { diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index 174b8eca..afe7387b 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -138,7 +138,7 @@ impl<'a> CgroupBuilder<'a> { /// Finalize the control group, consuming the builder and creating the control group. pub fn build(self) -> Cgroup<'a> { - let cg = Cgroup::new(self.hierarchy, self.name); + let cg = Cgroup::new(*self.hierarchy, self.name); let _ret = cg.apply(&self.resources); cg } diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 3588039e..c0ca8b04 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -111,7 +111,7 @@ impl Hierarchy for V1 { fn root_control_group(&self) -> Cgroup { let b: &dyn Hierarchy = self as &dyn Hierarchy; - Cgroup::load(Box::new(&*b), "".to_string()) + Cgroup::load(&*b, "".to_string()) } fn check_support(&self, sub: Controllers) -> bool { @@ -186,7 +186,7 @@ impl Hierarchy for V2 { fn root_control_group(&self) -> Cgroup { let b: &dyn Hierarchy = self as &dyn Hierarchy; - Cgroup::load(Box::new(&*b), "".to_string()) + Cgroup::load(&*b, "".to_string()) } fn check_support(&self, _sub: Controllers) -> bool { diff --git a/tests/cgroup.rs b/tests/cgroup.rs index 915a5f97..c071fc56 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -13,9 +13,8 @@ use std::collections::HashMap; #[test] fn test_tasks_iterator() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); let pid = libc::pid_t::from(nix::unistd::getpid()) as u64; - let cg = Cgroup::new(h, String::from("test_tasks_iterator")); + let cg = Cgroup::new(&*h, String::from("test_tasks_iterator")); { // Add a task to the control group. cg.add_task(CgroupPid::from(pid)).unwrap(); @@ -45,13 +44,9 @@ fn test_cgroup_with_relative_paths() { } let h = cgroups::hierarchies::auto(); let cgroup_root = h.root(); - let h = Box::new(&*h); - let mut relative_paths = HashMap::new(); - let mem_relative_path = "/mmm/abc/def"; - relative_paths.insert("memory".to_string(), mem_relative_path.to_string()); let cgroup_name = "test_cgroup_with_relative_paths"; - let cg = Cgroup::new_with_relative_paths(h, String::from(cgroup_name), relative_paths); + let cg = Cgroup::load(&*h, String::from(cgroup_name)); { let subsystems = cg.subsystems(); subsystems.into_iter().for_each(|sub| match sub { @@ -74,12 +69,7 @@ fn test_cgroup_with_relative_paths() { // cgroup_path = cgroup_root + relative_path + cgroup_name assert_eq!( cgroup_path, - format!( - "{}/memory{}/{}", - cgroup_root.to_str().unwrap(), - mem_relative_path, - cgroup_name - ) + format!("{}/memory/{}", cgroup_root.to_str().unwrap(), cgroup_name) ); } _ => {} @@ -94,8 +84,7 @@ fn test_cgroup_v2() { return; } let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new_with_relative_paths(h, String::from("test_v2"), HashMap::new()); + let cg = Cgroup::load(&*h, String::from("test_v2")); let mem_controller: &MemController = cg.controller_of().unwrap(); let (mem, swp, rev) = (4 * 1024 * 1000, 2 * 1024 * 1000, 1024 * 1000); diff --git a/tests/cpu.rs b/tests/cpu.rs index cbaad33b..bcd563d4 100644 --- a/tests/cpu.rs +++ b/tests/cpu.rs @@ -13,8 +13,7 @@ use std::fs; #[test] fn test_cfs_quota_and_periods() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("test_cfs_quota_and_periods")); + let cg = Cgroup::new(&*h, String::from("test_cfs_quota_and_periods")); let cpu_controller: &CpuController = cg.controller_of().unwrap(); diff --git a/tests/cpuset.rs b/tests/cpuset.rs index 35633548..efb71416 100644 --- a/tests/cpuset.rs +++ b/tests/cpuset.rs @@ -13,8 +13,7 @@ use std::fs; #[test] fn test_cpuset_memory_pressure_root_cg() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("test_cpuset_memory_pressure_root_cg")); + let cg = Cgroup::new(&*h, String::from("test_cpuset_memory_pressure_root_cg")); { let cpuset: &CpuSetController = cg.controller_of().unwrap(); @@ -28,8 +27,7 @@ fn test_cpuset_memory_pressure_root_cg() { #[test] fn test_cpuset_set_cpus() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus")); + let cg = Cgroup::new(&*h, String::from("test_cpuset_set_cpus")); { let cpuset: &CpuSetController = cg.controller_of().unwrap(); @@ -67,8 +65,7 @@ fn test_cpuset_set_cpus() { #[test] fn test_cpuset_set_cpus_add_task() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus_add_task/sub-dir")); + let cg = Cgroup::new(&*h, String::from("test_cpuset_set_cpus_add_task/sub-dir")); let cpuset: &CpuSetController = cg.controller_of().unwrap(); let set = cpuset.cpuset(); diff --git a/tests/devices.rs b/tests/devices.rs index adb7e13e..85cc6170 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -17,8 +17,7 @@ fn test_devices_parsing() { } let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("test_devices_parsing")); + let cg = Cgroup::new(&*h, String::from("test_devices_parsing")); { let devices: &DevicesController = cg.controller_of().unwrap(); diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index 095243e8..9a2468f4 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -20,8 +20,7 @@ fn test_hugetlb_sizes() { } let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("test_hugetlb_sizes")); + let cg = Cgroup::new(&*h, String::from("test_hugetlb_sizes")); { let hugetlb_controller: &HugeTlbController = cg.controller_of().unwrap(); let sizes = hugetlb_controller.get_sizes(); diff --git a/tests/memory.rs b/tests/memory.rs index 2d649068..f1f6e8a2 100644 --- a/tests/memory.rs +++ b/tests/memory.rs @@ -11,8 +11,7 @@ use cgroups::{Cgroup, MaxValue}; #[test] fn test_disable_oom_killer() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("test_disable_oom_killer")); + let cg = Cgroup::new(&*h, String::from("test_disable_oom_killer")); { let mem_controller: &MemController = cg.controller_of().unwrap(); @@ -41,8 +40,7 @@ fn set_mem_v2() { return; } - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("set_mem_v2")); + let cg = Cgroup::new(&*h, String::from("set_mem_v2")); { let mem_controller: &MemController = cg.controller_of().unwrap(); diff --git a/tests/pids.rs b/tests/pids.rs index 0449a0d5..fadb2e19 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -19,8 +19,7 @@ use std::thread; #[test] fn create_and_delete_cgroup() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("create_and_delete_cgroup")); + let cg = Cgroup::new(&*h, String::from("create_and_delete_cgroup")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); pidcontroller.set_pid_max(MaxValue::Value(1337)); @@ -34,8 +33,7 @@ fn create_and_delete_cgroup() { #[test] fn test_pids_current_is_zero() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("test_pids_current_is_zero")); + let cg = Cgroup::new(&*h, String::from("test_pids_current_is_zero")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); let current = pidcontroller.get_pid_current(); @@ -47,8 +45,7 @@ fn test_pids_current_is_zero() { #[test] fn test_pids_events_is_zero() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("test_pids_events_is_zero")); + let cg = Cgroup::new(&*h, String::from("test_pids_events_is_zero")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); let events = pidcontroller.get_pid_events(); @@ -61,8 +58,7 @@ fn test_pids_events_is_zero() { #[test] fn test_pid_events_is_not_zero() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("test_pid_events_is_not_zero")); + let cg = Cgroup::new(&*h, String::from("test_pid_events_is_not_zero")); { let pids: &PidController = cg.controller_of().unwrap(); let before = pids.get_pid_events(); diff --git a/tests/resources.rs b/tests/resources.rs index 40471243..18c4aefd 100644 --- a/tests/resources.rs +++ b/tests/resources.rs @@ -11,8 +11,7 @@ use cgroups::{Cgroup, Hierarchy, MaxValue, PidResources, Resources}; #[test] fn pid_resources() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg = Cgroup::new(h, String::from("pid_resources")); + let cg = Cgroup::new(&*h, String::from("pid_resources")); { let res = Resources { pid: PidResources { From fbd7164c2969ff50cbcb59cc5221d3d869114fc1 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 11 Nov 2020 20:12:30 +0800 Subject: [PATCH 33/71] Fix warnings in tests Remove following warnings - unused import - unused Result Signed-off-by: Tim Zhang --- src/memory.rs | 2 -- tests/builder.rs | 14 +++++++------- tests/cgroup.rs | 11 +++++------ tests/cpu.rs | 19 ++++++++++--------- tests/cpuset.rs | 8 ++++---- tests/devices.rs | 34 ++++++++++++++++++++-------------- tests/hugetlb.rs | 11 ++++------- tests/memory.rs | 4 ++-- tests/pids.rs | 16 +++++++--------- tests/resources.rs | 6 +++--- 10 files changed, 62 insertions(+), 63 deletions(-) diff --git a/src/memory.rs b/src/memory.rs index 3b48289f..9dcea227 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -884,8 +884,6 @@ mod tests { use crate::memory::{ parse_memory_stat, parse_numa_stat, parse_oom_control, MemoryStat, NumaStat, OomControl, }; - use std::collections::HashMap; - static GOOD_VALUE: &str = "\ total=51189 N0=51189 N1=123 file=50175 N0=50175 N1=123 diff --git a/tests/builder.rs b/tests/builder.rs index cb19bfa7..cf215a34 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -31,7 +31,7 @@ pub fn test_cpu_res_build() { assert_eq!(cpu.shares().unwrap(), 85); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -55,7 +55,7 @@ pub fn test_memory_res_build() { assert_eq!(c.memory_stat().limit_in_bytes, 1024 * 1024 * 1024); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -74,7 +74,7 @@ pub fn test_pid_res_build() { assert_eq!(c.get_pid_max().unwrap(), MaxValue::Value(123)); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -102,7 +102,7 @@ pub fn test_devices_res_build() { }] ); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -124,7 +124,7 @@ pub fn test_network_res_build() { assert!(c.get_class().is_ok()); assert_eq!(c.get_class().unwrap(), 1337); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -149,7 +149,7 @@ pub fn test_hugepages_res_build() { 4 * 2 * 1024 * 1024 ); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -167,5 +167,5 @@ pub fn test_blkio_res_build() { let c: &BlkIoController = cg.controller_of().unwrap(); assert_eq!(c.blkio().weight, 100); } - cg.delete(); + cg.delete().unwrap(); } diff --git a/tests/cgroup.rs b/tests/cgroup.rs index c071fc56..7a6d8dd9 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -5,10 +5,9 @@ // //! Simple unit tests about the control groups system. -use cgroups::memory::{MemController, SetMemory}; +use cgroups::memory::MemController; use cgroups::Controller; -use cgroups::{Cgroup, CgroupPid, Hierarchy, Subsystem}; -use std::collections::HashMap; +use cgroups::{Cgroup, CgroupPid, Subsystem}; #[test] fn test_tasks_iterator() { @@ -34,7 +33,7 @@ fn test_tasks_iterator() { // Verify that it was indeed removed. assert_eq!(tasks.next(), None); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -75,7 +74,7 @@ fn test_cgroup_with_relative_paths() { _ => {} }); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -102,5 +101,5 @@ fn test_cgroup_v2() { println!("memswap {:?}", memswap); assert_eq!(swp, memswap.limit_in_bytes); - cg.delete(); + cg.delete().unwrap(); } diff --git a/tests/cpu.rs b/tests/cpu.rs index bcd563d4..9eb4e99f 100644 --- a/tests/cpu.rs +++ b/tests/cpu.rs @@ -5,10 +5,7 @@ //! Simple unit tests about the CPU control groups system. use cgroups::cpu::CpuController; -use cgroups::error::ErrorKind; -use cgroups::{Cgroup, CgroupPid, CpuResources, Hierarchy, Resources}; - -use std::fs; +use cgroups::Cgroup; #[test] fn test_cfs_quota_and_periods() { @@ -26,7 +23,7 @@ fn test_cfs_quota_and_periods() { assert_eq!(100000, current_peroid); // case 1 set quota - let r = cpu_controller.set_cfs_quota(2000); + let _ = cpu_controller.set_cfs_quota(2000); let current_quota = cpu_controller.cfs_quota().unwrap(); let current_peroid = cpu_controller.cfs_period().unwrap(); @@ -34,14 +31,16 @@ fn test_cfs_quota_and_periods() { assert_eq!(100000, current_peroid); // case 2 set period - cpu_controller.set_cfs_period(1000000); + cpu_controller.set_cfs_period(1000000).unwrap(); let current_quota = cpu_controller.cfs_quota().unwrap(); let current_peroid = cpu_controller.cfs_period().unwrap(); assert_eq!(2000, current_quota); assert_eq!(1000000, current_peroid); // case 3 set both quota and period - cpu_controller.set_cfs_quota_and_period(Some(5000), Some(100000)); + cpu_controller + .set_cfs_quota_and_period(Some(5000), Some(100000)) + .unwrap(); let current_quota = cpu_controller.cfs_quota().unwrap(); let current_peroid = cpu_controller.cfs_period().unwrap(); @@ -49,12 +48,14 @@ fn test_cfs_quota_and_periods() { assert_eq!(100000, current_peroid); // case 4 set both quota and period, set quota to -1 - cpu_controller.set_cfs_quota_and_period(Some(-1), None); + cpu_controller + .set_cfs_quota_and_period(Some(-1), None) + .unwrap(); let current_quota = cpu_controller.cfs_quota().unwrap(); let current_peroid = cpu_controller.cfs_period().unwrap(); assert_eq!(-1, current_quota); assert_eq!(100000, current_peroid); - cg.delete(); + cg.delete().unwrap(); } diff --git a/tests/cpuset.rs b/tests/cpuset.rs index efb71416..0e8aa2a6 100644 --- a/tests/cpuset.rs +++ b/tests/cpuset.rs @@ -6,7 +6,7 @@ use cgroups::cpuset::CpuSetController; use cgroups::error::ErrorKind; -use cgroups::{Cgroup, CgroupPid, CpuResources, Hierarchy, Resources}; +use cgroups::{Cgroup, CgroupPid}; use std::fs; @@ -21,7 +21,7 @@ fn test_cpuset_memory_pressure_root_cg() { let res = cpuset.set_enable_memory_pressure(true); assert_eq!(res.unwrap_err().kind(), &ErrorKind::InvalidOperation); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -59,7 +59,7 @@ fn test_cpuset_set_cpus() { assert_eq!(format!("{}-{}", set.cpus[0].0, set.cpus[0].1), cpus); } } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -89,5 +89,5 @@ fn test_cpuset_set_cpus_add_task() { println!("tasks after deleted: {:?}", tasks); assert_eq!(0, tasks.len()); - cg.delete(); + cg.delete().unwrap(); } diff --git a/tests/devices.rs b/tests/devices.rs index 85cc6170..c8bc33c6 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -7,7 +7,7 @@ //! Integration tests about the devices subsystem use cgroups::devices::{DevicePermissions, DeviceType, DevicesController}; -use cgroups::{Cgroup, DeviceResource, Hierarchy}; +use cgroups::{Cgroup, DeviceResource}; #[test] fn test_devices_parsing() { @@ -22,16 +22,18 @@ fn test_devices_parsing() { let devices: &DevicesController = cg.controller_of().unwrap(); // Deny access to all devices first - devices.deny_device( - DeviceType::All, - -1, - -1, - &vec![ - DevicePermissions::Read, - DevicePermissions::Write, - DevicePermissions::MkNod, - ], - ); + devices + .deny_device( + DeviceType::All, + -1, + -1, + &vec![ + DevicePermissions::Read, + DevicePermissions::Write, + DevicePermissions::MkNod, + ], + ) + .unwrap(); // Acquire the list of allowed devices after we denied all let allowed_devices = devices.allowed_devices(); // Verify that there are no devices that we can access. @@ -39,7 +41,9 @@ fn test_devices_parsing() { assert_eq!(allowed_devices.unwrap(), Vec::new()); // Now add mknod access to /dev/null device - devices.allow_device(DeviceType::Char, 1, 3, &vec![DevicePermissions::MkNod]); + devices + .allow_device(DeviceType::Char, 1, 3, &vec![DevicePermissions::MkNod]) + .unwrap(); let allowed_devices = devices.allowed_devices(); assert!(allowed_devices.is_ok()); let allowed_devices = allowed_devices.unwrap(); @@ -56,12 +60,14 @@ fn test_devices_parsing() { ); // Now deny, this device explicitly. - devices.deny_device(DeviceType::Char, 1, 3, &DevicePermissions::all()); + devices + .deny_device(DeviceType::Char, 1, 3, &DevicePermissions::all()) + .unwrap(); // Finally, check that. let allowed_devices = devices.allowed_devices(); // Verify that there are no devices that we can access. assert!(allowed_devices.is_ok()); assert_eq!(allowed_devices.unwrap(), Vec::new()); } - cg.delete(); + cg.delete().unwrap(); } diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index 9a2468f4..505a6cb1 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -4,12 +4,9 @@ // //! Integration tests about the hugetlb subsystem -use cgroups::hugetlb::{self, HugeTlbController}; -use cgroups::Controller; -use cgroups::{Cgroup, Hierarchy}; - -use cgroups::error::ErrorKind::*; use cgroups::error::*; +use cgroups::hugetlb::{self, HugeTlbController}; +use cgroups::Cgroup; use std::fs; #[test] @@ -23,7 +20,7 @@ fn test_hugetlb_sizes() { let cg = Cgroup::new(&*h, String::from("test_hugetlb_sizes")); { let hugetlb_controller: &HugeTlbController = cg.controller_of().unwrap(); - let sizes = hugetlb_controller.get_sizes(); + let _ = hugetlb_controller.get_sizes(); // test sizes count let sizes = hugetlb_controller.get_sizes(); @@ -39,7 +36,7 @@ fn test_hugetlb_sizes() { assert_no_error(hugetlb_controller.max_usage_in_bytes(&size)); } } - cg.delete(); + cg.delete().unwrap(); } fn assert_no_error(r: Result) { diff --git a/tests/memory.rs b/tests/memory.rs index f1f6e8a2..92b508bd 100644 --- a/tests/memory.rs +++ b/tests/memory.rs @@ -30,7 +30,7 @@ fn test_disable_oom_killer() { assert_eq!(m.oom_control.oom_kill_disable, true); } } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -87,5 +87,5 @@ fn set_mem_v2() { assert_eq!(m.high, Some(MaxValue::Max)); } - cg.delete(); + cg.delete().unwrap(); } diff --git a/tests/pids.rs b/tests/pids.rs index fadb2e19..c756581f 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -7,27 +7,25 @@ //! Integration tests about the pids subsystem use cgroups::pid::PidController; use cgroups::Controller; -use cgroups::{Cgroup, CgroupPid, Hierarchy, MaxValue, PidResources, Resources}; +use cgroups::{Cgroup, MaxValue}; use nix::sys::wait::{waitpid, WaitStatus}; -use nix::unistd::{fork, ForkResult, Pid}; +use nix::unistd::{fork, ForkResult}; use libc::pid_t; -use std::thread; - #[test] fn create_and_delete_cgroup() { let h = cgroups::hierarchies::auto(); let cg = Cgroup::new(&*h, String::from("create_and_delete_cgroup")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); - pidcontroller.set_pid_max(MaxValue::Value(1337)); + pidcontroller.set_pid_max(MaxValue::Value(1337)).unwrap(); let max = pidcontroller.get_pid_max(); assert!(max.is_ok()); assert_eq!(max.unwrap(), MaxValue::Value(1337)); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -39,7 +37,7 @@ fn test_pids_current_is_zero() { let current = pidcontroller.get_pid_current(); assert_eq!(current.unwrap(), 0); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -52,7 +50,7 @@ fn test_pids_events_is_zero() { assert!(events.is_ok()); assert_eq!(events.unwrap(), 0); } - cg.delete(); + cg.delete().unwrap(); } #[test] @@ -101,5 +99,5 @@ fn test_pid_events_is_not_zero() { Err(_) => panic!("failed to fork"), } } - cg.delete(); + cg.delete().unwrap(); } diff --git a/tests/resources.rs b/tests/resources.rs index 18c4aefd..7ceacfe1 100644 --- a/tests/resources.rs +++ b/tests/resources.rs @@ -6,7 +6,7 @@ //! Integration test about setting resources using `apply()` use cgroups::pid::PidController; -use cgroups::{Cgroup, Hierarchy, MaxValue, PidResources, Resources}; +use cgroups::{Cgroup, MaxValue, PidResources, Resources}; #[test] fn pid_resources() { @@ -19,7 +19,7 @@ fn pid_resources() { }, ..Default::default() }; - cg.apply(&res); + cg.apply(&res).unwrap(); // verify let pidcontroller: &PidController = cg.controller_of().unwrap(); @@ -27,5 +27,5 @@ fn pid_resources() { assert_eq!(pid_max.is_ok(), true); assert_eq!(pid_max.unwrap(), MaxValue::Value(512)); } - cg.delete(); + cg.delete().unwrap(); } From 1f188be40593cfed0b0b56173aeb4c13258e58ce Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 12 Nov 2020 20:06:03 +0800 Subject: [PATCH 34/71] Detect subsystems and get root from /proc/self/mountinfo Delete check_support and stop detecting subsystems by finding in the root folders because the detecting method is not accurate. Signed-off-by: Tim Zhang --- Cargo.toml | 1 + src/blkio.rs | 8 +-- src/cpu.rs | 8 +-- src/cpuacct.rs | 6 +- src/cpuset.rs | 8 +-- src/devices.rs | 6 +- src/freezer.rs | 8 +-- src/hierarchies.rs | 154 ++++++++++++++++----------------------------- src/hugetlb.rs | 8 +-- src/lib.rs | 8 +-- src/memory.rs | 8 +-- src/net_cls.rs | 6 +- src/net_prio.rs | 6 +- src/perf_event.rs | 6 +- src/pid.rs | 8 +-- src/rdma.rs | 6 +- src/systemd.rs | 8 +-- 17 files changed, 83 insertions(+), 180 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 156a69ff..5bdbbe66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ log = "0.4" regex = "1.1" nix = "0.18.0" libc = "0.2" +procinfo = "0.4.2" [dev-dependencies] libc = "0.2.76" diff --git a/src/blkio.rs b/src/blkio.rs index b0f78a2b..7e21faf5 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -421,12 +421,8 @@ fn read_u64_from(mut file: File) -> Result { } impl BlkIoController { - /// Constructs a new `BlkIoController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf, v2: bool) -> Self { - let mut root = oroot; - if !v2 { - root.push(Self::controller_type().to_string()); - } + /// Constructs a new `BlkIoController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf, v2: bool) -> Self { Self { base: root.clone(), path: root, diff --git a/src/cpu.rs b/src/cpu.rs index 105a4388..bcf92062 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -122,12 +122,8 @@ fn read_u64_from(mut file: File) -> Result { } impl CpuController { - /// Contructs a new `CpuController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf, v2: bool) -> Self { - let mut root = oroot; - if !v2 { - root.push(Self::controller_type().to_string()); - } + /// Contructs a new `CpuController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf, v2: bool) -> Self { Self { base: root.clone(), path: root, diff --git a/src/cpuacct.rs b/src/cpuacct.rs index 0924d957..6efde64f 100644 --- a/src/cpuacct.rs +++ b/src/cpuacct.rs @@ -118,10 +118,8 @@ fn read_string_from(mut file: File) -> Result { } impl CpuAcctController { - /// Contructs a new `CpuAcctController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { - let mut root = oroot; - root.push(Self::controller_type().to_string()); + /// Contructs a new `CpuAcctController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf) -> Self { Self { base: root.clone(), path: root, diff --git a/src/cpuset.rs b/src/cpuset.rs index 4d4427d1..cef4679c 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -261,12 +261,8 @@ fn parse_range(s: String) -> Result> { } impl CpuSetController { - /// Contructs a new `CpuSetController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf, v2: bool) -> Self { - let mut root = oroot; - if !v2 { - root.push(Self::controller_type().to_string()); - } + /// Contructs a new `CpuSetController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf, v2: bool) -> Self { Self { base: root.clone(), path: root, diff --git a/src/devices.rs b/src/devices.rs index 5a78a2ef..838d17e5 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -189,10 +189,8 @@ impl<'a> From<&'a Subsystem> for &'a DevicesController { } impl DevicesController { - /// Constructs a new `DevicesController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { - let mut root = oroot; - root.push(Self::controller_type().to_string()); + /// Constructs a new `DevicesController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf) -> Self { Self { base: root.clone(), path: root, diff --git a/src/freezer.rs b/src/freezer.rs index c9da3792..93a01854 100644 --- a/src/freezer.rs +++ b/src/freezer.rs @@ -82,12 +82,8 @@ impl<'a> From<&'a Subsystem> for &'a FreezerController { } impl FreezerController { - /// Contructs a new `FreezerController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf, v2: bool) -> Self { - let mut root = oroot; - if !v2 { - root.push(Self::controller_type().to_string()); - } + /// Contructs a new `FreezerController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf, v2: bool) -> Self { Self { base: root.clone(), path: root, diff --git a/src/hierarchies.rs b/src/hierarchies.rs index c0ca8b04..4e0742fa 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -9,12 +9,9 @@ //! Currently, we only support the cgroupv1 hierarchy, but in the future we will add support for //! the Unified Hierarchy. -use std::fs::{self, File}; -use std::io::BufRead; -use std::io::BufReader; -use std::path::{Path, PathBuf}; - -use log::*; +use procinfo::pid::{mountinfo_self, Mountinfo}; +use std::fs; +use std::path::PathBuf; use crate::blkio::BlkIoController; use crate::cpu::CpuController; @@ -36,7 +33,7 @@ use crate::cgroup::Cgroup; /// The standard, original cgroup implementation. Often referred to as "cgroupv1". pub struct V1 { - mount_point: String, + mountinfo: Vec, } pub struct V2 { @@ -54,56 +51,47 @@ impl Hierarchy for V1 { // The cgroup writeback feature requires cooperation between memcgs and blkcgs // To avoid exceptions, we should add_task for blkcg before memcg(push BlkIo before Mem) // For more Information: https://www.alibabacloud.com/help/doc-detail/155509.htm - if self.check_support(Controllers::BlkIo) { - subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), false))); + if let Some(root) = self.get_mount_point(Controllers::BlkIo) { + subs.push(Subsystem::BlkIo(BlkIoController::new(root, false))); } - if self.check_support(Controllers::Mem) { - subs.push(Subsystem::Mem(MemController::new(self.root(), false))); + if let Some(root) = self.get_mount_point(Controllers::Mem) { + subs.push(Subsystem::Mem(MemController::new(root, false))); } - if self.check_support(Controllers::Pids) { - subs.push(Subsystem::Pid(PidController::new(self.root(), false))); + if let Some(root) = self.get_mount_point(Controllers::Pids) { + subs.push(Subsystem::Pid(PidController::new(root, false))); } - if self.check_support(Controllers::CpuSet) { - subs.push(Subsystem::CpuSet(CpuSetController::new(self.root(), false))); + if let Some(root) = self.get_mount_point(Controllers::CpuSet) { + subs.push(Subsystem::CpuSet(CpuSetController::new(root, false))); } - if self.check_support(Controllers::CpuAcct) { - subs.push(Subsystem::CpuAcct(CpuAcctController::new(self.root()))); + if let Some(root) = self.get_mount_point(Controllers::CpuAcct) { + subs.push(Subsystem::CpuAcct(CpuAcctController::new(root))); } - if self.check_support(Controllers::Cpu) { - subs.push(Subsystem::Cpu(CpuController::new(self.root(), false))); + if let Some(root) = self.get_mount_point(Controllers::Cpu) { + subs.push(Subsystem::Cpu(CpuController::new(root, false))); } - if self.check_support(Controllers::Devices) { - subs.push(Subsystem::Devices(DevicesController::new(self.root()))); + if let Some(root) = self.get_mount_point(Controllers::Devices) { + subs.push(Subsystem::Devices(DevicesController::new(root))); } - if self.check_support(Controllers::Freezer) { - subs.push(Subsystem::Freezer(FreezerController::new( - self.root(), - false, - ))); + if let Some(root) = self.get_mount_point(Controllers::Freezer) { + subs.push(Subsystem::Freezer(FreezerController::new(root, false))); } - if self.check_support(Controllers::NetCls) { - subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); + if let Some(root) = self.get_mount_point(Controllers::NetCls) { + subs.push(Subsystem::NetCls(NetClsController::new(root))); } - if self.check_support(Controllers::PerfEvent) { - subs.push(Subsystem::PerfEvent(PerfEventController::new(self.root()))); + if let Some(root) = self.get_mount_point(Controllers::PerfEvent) { + subs.push(Subsystem::PerfEvent(PerfEventController::new(root))); } - if self.check_support(Controllers::NetPrio) { - subs.push(Subsystem::NetPrio(NetPrioController::new(self.root()))); + if let Some(root) = self.get_mount_point(Controllers::NetPrio) { + subs.push(Subsystem::NetPrio(NetPrioController::new(root))); } - if self.check_support(Controllers::HugeTlb) { - subs.push(Subsystem::HugeTlb(HugeTlbController::new( - self.root(), - false, - ))); + if let Some(root) = self.get_mount_point(Controllers::HugeTlb) { + subs.push(Subsystem::HugeTlb(HugeTlbController::new(root, false))); } - if self.check_support(Controllers::Rdma) { - subs.push(Subsystem::Rdma(RdmaController::new(self.root()))); + if let Some(root) = self.get_mount_point(Controllers::Rdma) { + subs.push(Subsystem::Rdma(RdmaController::new(root))); } - if self.check_support(Controllers::Systemd) { - subs.push(Subsystem::Systemd(SystemdController::new( - self.root(), - false, - ))); + if let Some(root) = self.get_mount_point(Controllers::Systemd) { + subs.push(Subsystem::Systemd(SystemdController::new(root, false))); } subs @@ -114,20 +102,17 @@ impl Hierarchy for V1 { Cgroup::load(&*b, "".to_string()) } - fn check_support(&self, sub: Controllers) -> bool { - let root = self.root().read_dir().unwrap(); - for entry in root { - if let Ok(entry) = entry { - if entry.file_name().into_string().unwrap() == sub.to_string() { - return true; - } - } - } - return false; - } - fn root(&self) -> PathBuf { - PathBuf::from(self.mount_point.clone()) + self.mountinfo + .iter() + .find_map(|m| { + if m.fs_type.0 == "cgroup" { + return Some(m.mount_point.parent().unwrap()); + } + None + }) + .unwrap() + .to_path_buf() } } @@ -189,10 +174,6 @@ impl Hierarchy for V2 { Cgroup::load(&*b, "".to_string()) } - fn check_support(&self, _sub: Controllers) -> bool { - return false; - } - fn root(&self) -> PathBuf { PathBuf::from(self.root.clone()) } @@ -202,11 +183,19 @@ impl V1 { /// Finds where control groups are mounted to and returns a hierarchy in which control groups /// can be created. pub fn new() -> V1 { - let mount_point = find_v1_mount().unwrap(); V1 { - mount_point: mount_point, + mountinfo: mountinfo_self().unwrap(), } } + + pub fn get_mount_point(&self, controller: Controllers) -> Option { + self.mountinfo.iter().find_map(|m| { + if m.fs_type.0 == "cgroup" && m.super_opts.contains(&controller.to_string()) { + return Some(m.mount_point.clone()); + } + None + }) + } } impl V2 { @@ -225,7 +214,7 @@ pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; pub fn is_cgroup2_unified_mode() -> bool { use nix::sys::statfs; - let path = Path::new(UNIFIED_MOUNTPOINT); + let path = std::path::Path::new(UNIFIED_MOUNTPOINT); let fs_stat = statfs::statfs(path); if fs_stat.is_err() { return false; @@ -264,40 +253,3 @@ pub fn auto() -> Box { Box::new(V1::new()) } } - -pub fn find_v1_mount() -> Option { - // Open mountinfo so we can get a parseable mount list - let mountinfo_path = Path::new("/proc/self/mountinfo"); - - // If /proc isn't mounted, or something else happens, then bail out - if mountinfo_path.exists() == false { - return None; - } - - let mountinfo_file = File::open(mountinfo_path).unwrap(); - let mountinfo_reader = BufReader::new(&mountinfo_file); - for _line in mountinfo_reader.lines() { - let line = _line.unwrap(); - let mut fields = line.split_whitespace(); - let index = line.find(" - ").unwrap(); - let more_fields = line[index + 3..].split_whitespace().collect::>(); - if more_fields.len() == 0 { - continue; - } - if more_fields[0] == "cgroup" { - if more_fields.len() < 3 { - continue; - } - let cgroups_mount = fields.nth(4).unwrap(); - if let Some(parent) = std::path::Path::new(cgroups_mount).parent() { - if let Some(path) = parent.as_os_str().to_str() { - debug!("found cgroups {:?} from {:?}", path, cgroups_mount); - return Some(path.to_string()); - } - } - continue; - } - } - - None -} diff --git a/src/hugetlb.rs b/src/hugetlb.rs index d9e8d3cf..686a599b 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -98,12 +98,8 @@ fn read_u64_from(mut file: File) -> Result { } impl HugeTlbController { - /// Constructs a new `HugeTlbController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf, v2: bool) -> Self { - let mut root = oroot; - if !v2 { - root.push(Self::controller_type().to_string()); - } + /// Constructs a new `HugeTlbController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf, v2: bool) -> Self { let sizes = get_hugepage_sizes().unwrap(); Self { base: root.clone(), diff --git a/src/lib.rs b/src/lib.rs index 117e88ec..fe5c0c0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -137,7 +137,7 @@ impl Controllers { Controllers::NetPrio => return "net_prio".to_string(), Controllers::HugeTlb => return "hugetlb".to_string(), Controllers::Rdma => return "rdma".to_string(), - Controllers::Systemd => return "systemd".to_string(), + Controllers::Systemd => return "name=systemd".to_string(), } } } @@ -367,12 +367,6 @@ pub trait Hierarchy { fn root_control_group(&self) -> Cgroup; fn v2(&self) -> bool; - - /// Checks whether a certain subsystem is supported in the hierarchy. - /// - /// This is an internal function and should not be used. - #[doc(hidden)] - fn check_support(&self, sub: Controllers) -> bool; } /// Resource limits for the memory subsystem. diff --git a/src/memory.rs b/src/memory.rs index 9dcea227..314de66d 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -465,12 +465,8 @@ impl ControllerInternal for MemController { } impl MemController { - /// Contructs a new `MemController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf, v2: bool) -> Self { - let mut root = oroot; - if !v2 { - root.push(Self::controller_type().to_string()); - } + /// Contructs a new `MemController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf, v2: bool) -> Self { Self { base: root.clone(), path: root, diff --git a/src/net_cls.rs b/src/net_cls.rs index ad2af39d..5328eb14 100644 --- a/src/net_cls.rs +++ b/src/net_cls.rs @@ -86,10 +86,8 @@ fn read_u64_from(mut file: File) -> Result { } impl NetClsController { - /// Constructs a new `NetClsController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { - let mut root = oroot; - root.push(Self::controller_type().to_string()); + /// Constructs a new `NetClsController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf) -> Self { Self { base: root.clone(), path: root, diff --git a/src/net_prio.rs b/src/net_prio.rs index 37287968..d1bbbde6 100644 --- a/src/net_prio.rs +++ b/src/net_prio.rs @@ -89,10 +89,8 @@ fn read_u64_from(mut file: File) -> Result { } impl NetPrioController { - /// Constructs a new `NetPrioController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { - let mut root = oroot; - root.push(Self::controller_type().to_string()); + /// Constructs a new `NetPrioController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf) -> Self { Self { base: root.clone(), path: root, diff --git a/src/perf_event.rs b/src/perf_event.rs index 09eefc6f..f0e9240e 100644 --- a/src/perf_event.rs +++ b/src/perf_event.rs @@ -64,10 +64,8 @@ impl<'a> From<&'a Subsystem> for &'a PerfEventController { } impl PerfEventController { - /// Constructs a new `PerfEventController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { - let mut root = oroot; - root.push(Self::controller_type().to_string()); + /// Constructs a new `PerfEventController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf) -> Self { Self { base: root.clone(), path: root, diff --git a/src/pid.rs b/src/pid.rs index e9c48698..1955828b 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -101,13 +101,9 @@ fn read_u64_from(mut file: File) -> Result { } impl PidController { - /// Constructors a new `PidController` instance, with `oroot` serving as the controller's root + /// Constructors a new `PidController` instance, with `root` serving as the controller's root /// directory. - pub fn new(oroot: PathBuf, v2: bool) -> Self { - let mut root = oroot; - if !v2 { - root.push(Self::controller_type().to_string()); - } + pub fn new(root: PathBuf, v2: bool) -> Self { Self { base: root.clone(), path: root, diff --git a/src/rdma.rs b/src/rdma.rs index 9d366d25..8066c151 100644 --- a/src/rdma.rs +++ b/src/rdma.rs @@ -75,10 +75,8 @@ fn read_string_from(mut file: File) -> Result { } impl RdmaController { - /// Constructs a new `RdmaController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf) -> Self { - let mut root = oroot; - root.push(Self::controller_type().to_string()); + /// Constructs a new `RdmaController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf) -> Self { Self { base: root.clone(), path: root, diff --git a/src/systemd.rs b/src/systemd.rs index 545c4116..3fe02626 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -61,12 +61,8 @@ impl<'a> From<&'a Subsystem> for &'a SystemdController { } impl SystemdController { - /// Constructs a new `SystemdController` with `oroot` serving as the root of the control group. - pub fn new(oroot: PathBuf, v2: bool) -> Self { - let mut root = oroot; - if !v2 { - root.push(Self::controller_type().to_string()); - } + /// Constructs a new `SystemdController` with `root` serving as the root of the control group. + pub fn new(root: PathBuf, v2: bool) -> Self { Self { base: root.clone(), path: root, From abcb5ed031e81326b12ee3cae2ae15b8dfe361db Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 12 Nov 2020 22:05:07 +0800 Subject: [PATCH 35/71] Add more logs for create_dir error in controller.create We need know the path name which failed to create. Signed-off-by: Tim Zhang --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index fe5c0c0c..96b96c20 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -285,7 +285,7 @@ where match ::std::fs::create_dir_all(self.get_path()) { Ok(_) => self.post_create(), - Err(e) => warn!("error create_dir {:?}", e), + Err(e) => warn!("error create_dir: {:?} error: {:?}", self.get_path(), e), } } From d2882b1d85b296d06e430af0981076c028382487 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Fri, 13 Nov 2020 17:03:16 +0800 Subject: [PATCH 36/71] Print cause when println!("{}") > Print like following: unable to write to a control group file caused by: Os { code: 22, kind: InvalidInput, message: "Invalid argument" }) } Signed-off-by: Tim Zhang --- src/error.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index a8cd65ca..26c86a80 100644 --- a/src/error.rs +++ b/src/error.rs @@ -66,7 +66,11 @@ impl fmt::Display for Error { ErrorKind::Other => "an unknown error".to_string(), }; - write!(f, "{}", msg) + if let Some(cause) = &self.cause { + write!(f, "{} caused by: {:?}", msg, cause) + } else { + write!(f, "{}", msg) + } } } From b6bb5ae947166a550014b652ec24e4326c7a59d9 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Tue, 17 Nov 2020 19:10:30 +0800 Subject: [PATCH 37/71] docs: Hide Re-exports Make `pub use crate::cgroup::Cgroup` display as struct in docs. Signed-off-by: Tim Zhang --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 96b96c20..cd53081e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,6 +67,7 @@ use crate::pid::PidController; use crate::rdma::RdmaController; use crate::systemd::SystemdController; +#[doc(inline)] pub use crate::cgroup::Cgroup; /// Contains all the subsystems that are available in this crate. From 42ee1bafbd7ae8bc6448663f6d8897307717346e Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 3 Dec 2020 17:27:50 +0800 Subject: [PATCH 38/71] Make Cgroup can be stored in struct - Change type of hier to remove lifetimes - impl Clone, Default, Debug for Cgroup Signed-off-by: Tim Zhang --- src/cgroup.rs | 51 ++++++++++++---------- src/cgroup_builder.rs | 98 +++++++++++++++++++++---------------------- src/hierarchies.rs | 8 ++-- src/lib.rs | 6 +-- 4 files changed, 85 insertions(+), 78 deletions(-) diff --git a/src/cgroup.rs b/src/cgroup.rs index 9a7e8594..3e927579 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -28,16 +28,37 @@ use std::path::{Path, PathBuf}; /// > specialized behaviour. /// /// This crate is an attempt at providing a Rust-native way of managing these cgroups. -pub struct Cgroup<'b> { +#[derive(Debug)] +pub struct Cgroup { /// The list of subsystems that control this cgroup subsystems: Vec, /// The hierarchy. - hier: &'b dyn Hierarchy, + hier: Box, path: String, } -impl<'b> Cgroup<'b> { +impl Clone for Cgroup { + fn clone(&self) -> Self { + Cgroup { + subsystems: self.subsystems.clone(), + path: self.path.clone(), + hier: crate::hierarchies::auto(), + } + } +} + +impl Default for Cgroup { + fn default() -> Self { + Cgroup { + subsystems: Vec::new(), + hier: crate::hierarchies::auto(), + path: "".to_string(), + } + } +} + +impl Cgroup { /// Create this control group. fn create(&self) { if self.hier.v2() { @@ -56,10 +77,7 @@ impl<'b> Cgroup<'b> { /// Create a new control group in the hierarchy `hier`, with name `path`. /// /// Returns a handle to the control group that can be used to manipulate it. - /// - /// Note that if the handle goes out of scope and is dropped, the control group is _not_ - /// destroyed. - pub fn new>(hier: &dyn Hierarchy, path: P) -> Cgroup { + pub fn new>(hier: Box, path: P) -> Cgroup { let cg = Cgroup::load(hier, path); cg.create(); cg @@ -68,11 +86,8 @@ impl<'b> Cgroup<'b> { /// Create a new control group in the hierarchy `hier`, with name `path` and `relative_paths` /// /// Returns a handle to the control group that can be used to manipulate it. - /// - /// Note that if the handle goes out of scope and is dropped, the control group is _not_ - /// destroyed. pub fn new_with_relative_paths>( - hier: &dyn Hierarchy, + hier: Box, path: P, relative_paths: HashMap, ) -> Cgroup { @@ -85,10 +100,7 @@ impl<'b> Cgroup<'b> { /// /// Returns a handle to the control group (that possibly does not exist until `create()` has /// been called on the cgroup. - /// - /// Note that if the handle goes out of scope and is dropped, the control group is _not_ - /// destroyed. - pub fn load>(hier: &dyn Hierarchy, path: P) -> Cgroup { + pub fn load>(hier: Box, path: P) -> Cgroup { let path = path.as_ref(); let mut subsystems = hier.subsystems(); if path.as_os_str() != "" { @@ -101,7 +113,7 @@ impl<'b> Cgroup<'b> { let cg = Cgroup { path: path.to_str().unwrap().to_string(), subsystems: subsystems, - hier: hier, + hier, }; cg @@ -111,11 +123,8 @@ impl<'b> Cgroup<'b> { /// /// Returns a handle to the control group (that possibly does not exist until `create()` has /// been called on the cgroup. - /// - /// Note that if the handle goes out of scope and is dropped, the control group is _not_ - /// destroyed. pub fn load_with_relative_paths>( - hier: &dyn Hierarchy, + hier: Box, path: P, relative_paths: HashMap, ) -> Cgroup { @@ -141,7 +150,7 @@ impl<'b> Cgroup<'b> { let cg = Cgroup { subsystems: subsystems, - hier: hier, + hier, path: path.to_str().unwrap().to_string(), }; diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index afe7387b..244ca4a9 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -77,59 +77,57 @@ macro_rules! gen_setter { } /// A control group builder instance -pub struct CgroupBuilder<'a> { +pub struct CgroupBuilder { name: String, - hierarchy: Box<&'a dyn Hierarchy>, /// Internal, unsupported field: use the associated builders instead. resources: Resources, } -impl<'a> CgroupBuilder<'a> { +impl CgroupBuilder { /// Start building a control group with the supplied hierarchy and name pair. /// /// Note that this does not actually create the control group until `build()` is called. - pub fn new(name: &'a str, hierarchy: Box<&'a dyn Hierarchy>) -> CgroupBuilder<'a> { + pub fn new(name: &str) -> CgroupBuilder { CgroupBuilder { name: name.to_owned(), - hierarchy: hierarchy, resources: Resources::default(), } } /// Builds the memory resources of the control group. - pub fn memory(self) -> MemoryResourceBuilder<'a> { + pub fn memory(self) -> MemoryResourceBuilder { MemoryResourceBuilder { cgroup: self } } /// Builds the pid resources of the control group. - pub fn pid(self) -> PidResourceBuilder<'a> { + pub fn pid(self) -> PidResourceBuilder { PidResourceBuilder { cgroup: self } } /// Builds the cpu resources of the control group. - pub fn cpu(self) -> CpuResourceBuilder<'a> { + pub fn cpu(self) -> CpuResourceBuilder { CpuResourceBuilder { cgroup: self } } /// Builds the devices resources of the control group, disallowing or /// allowing access to certain devices in the system. - pub fn devices(self) -> DeviceResourceBuilder<'a> { + pub fn devices(self) -> DeviceResourceBuilder { DeviceResourceBuilder { cgroup: self } } /// Builds the network resources of the control group, setting class id, or /// various priorities on networking interfaces. - pub fn network(self) -> NetworkResourceBuilder<'a> { + pub fn network(self) -> NetworkResourceBuilder { NetworkResourceBuilder { cgroup: self } } /// Builds the hugepage/hugetlb resources available to the control group. - pub fn hugepages(self) -> HugepagesResourceBuilder<'a> { + pub fn hugepages(self) -> HugepagesResourceBuilder { HugepagesResourceBuilder { cgroup: self } } /// Builds the block I/O resources available for the control group. - pub fn blkio(self) -> BlkIoResourcesBuilder<'a> { + pub fn blkio(self) -> BlkIoResourcesBuilder { BlkIoResourcesBuilder { cgroup: self, throttling_iops: false, @@ -137,19 +135,19 @@ impl<'a> CgroupBuilder<'a> { } /// Finalize the control group, consuming the builder and creating the control group. - pub fn build(self) -> Cgroup<'a> { - let cg = Cgroup::new(*self.hierarchy, self.name); + pub fn build(self, hier: Box) -> Cgroup { + let cg = Cgroup::new(hier, self.name); let _ret = cg.apply(&self.resources); cg } } /// A builder that configures the memory controller of a control group. -pub struct MemoryResourceBuilder<'a> { - cgroup: CgroupBuilder<'a>, +pub struct MemoryResourceBuilder { + cgroup: CgroupBuilder, } -impl<'a> MemoryResourceBuilder<'a> { +impl MemoryResourceBuilder { gen_setter!( memory, MemController, @@ -182,17 +180,17 @@ impl<'a> MemoryResourceBuilder<'a> { gen_setter!(memory, MemController, set_swappiness, swappiness, u64); /// Finish the construction of the memory resources of a control group. - pub fn done(self) -> CgroupBuilder<'a> { + pub fn done(self) -> CgroupBuilder { self.cgroup } } /// A builder that configures the pid controller of a control group. -pub struct PidResourceBuilder<'a> { - cgroup: CgroupBuilder<'a>, +pub struct PidResourceBuilder { + cgroup: CgroupBuilder, } -impl<'a> PidResourceBuilder<'a> { +impl PidResourceBuilder { gen_setter!( pid, PidController, @@ -202,17 +200,17 @@ impl<'a> PidResourceBuilder<'a> { ); /// Finish the construction of the pid resources of a control group. - pub fn done(self) -> CgroupBuilder<'a> { + pub fn done(self) -> CgroupBuilder { self.cgroup } } /// A builder that configures the cpuset & cpu controllers of a control group. -pub struct CpuResourceBuilder<'a> { - cgroup: CgroupBuilder<'a>, +pub struct CpuResourceBuilder { + cgroup: CgroupBuilder, } -impl<'a> CpuResourceBuilder<'a> { +impl CpuResourceBuilder { gen_setter!(cpu, CpuSetController, set_cpus, cpus, String); gen_setter!(cpu, CpuSetController, set_mems, mems, String); gen_setter!(cpu, CpuController, set_shares, shares, u64); @@ -222,17 +220,17 @@ impl<'a> CpuResourceBuilder<'a> { gen_setter!(cpu, CpuController, set_rt_period, realtime_period, u64); /// Finish the construction of the cpu resources of a control group. - pub fn done(self) -> CgroupBuilder<'a> { + pub fn done(self) -> CgroupBuilder { self.cgroup } } /// A builder that configures the devices controller of a control group. -pub struct DeviceResourceBuilder<'a> { - cgroup: CgroupBuilder<'a>, +pub struct DeviceResourceBuilder { + cgroup: CgroupBuilder, } -impl<'a> DeviceResourceBuilder<'a> { +impl DeviceResourceBuilder { /// Restrict (or allow) a device to the tasks inside the control group. pub fn device( mut self, @@ -241,7 +239,7 @@ impl<'a> DeviceResourceBuilder<'a> { devtype: crate::devices::DeviceType, allow: bool, access: Vec, - ) -> DeviceResourceBuilder<'a> { + ) -> DeviceResourceBuilder { self.cgroup.resources.devices.devices.push(DeviceResource { major, minor, @@ -253,22 +251,22 @@ impl<'a> DeviceResourceBuilder<'a> { } /// Finish the construction of the devices resources of a control group. - pub fn done(self) -> CgroupBuilder<'a> { + pub fn done(self) -> CgroupBuilder { self.cgroup } } /// A builder that configures the net_cls & net_prio controllers of a control group. -pub struct NetworkResourceBuilder<'a> { - cgroup: CgroupBuilder<'a>, +pub struct NetworkResourceBuilder { + cgroup: CgroupBuilder, } -impl<'a> NetworkResourceBuilder<'a> { +impl NetworkResourceBuilder { gen_setter!(network, NetclsController, set_class, class_id, u64); /// Set the priority of the tasks when operating on a networking device defined by `name` to be /// `priority`. - pub fn priority(mut self, name: String, priority: u64) -> NetworkResourceBuilder<'a> { + pub fn priority(mut self, name: String, priority: u64) -> NetworkResourceBuilder { self.cgroup .resources .network @@ -278,19 +276,19 @@ impl<'a> NetworkResourceBuilder<'a> { } /// Finish the construction of the network resources of a control group. - pub fn done(self) -> CgroupBuilder<'a> { + pub fn done(self) -> CgroupBuilder { self.cgroup } } /// A builder that configures the hugepages controller of a control group. -pub struct HugepagesResourceBuilder<'a> { - cgroup: CgroupBuilder<'a>, +pub struct HugepagesResourceBuilder { + cgroup: CgroupBuilder, } -impl<'a> HugepagesResourceBuilder<'a> { +impl HugepagesResourceBuilder { /// Limit the usage of certain hugepages (determined by `size`) to be at most `limit` bytes. - pub fn limit(mut self, size: String, limit: u64) -> HugepagesResourceBuilder<'a> { + pub fn limit(mut self, size: String, limit: u64) -> HugepagesResourceBuilder { self.cgroup .resources .hugepages @@ -300,18 +298,18 @@ impl<'a> HugepagesResourceBuilder<'a> { } /// Finish the construction of the network resources of a control group. - pub fn done(self) -> CgroupBuilder<'a> { + pub fn done(self) -> CgroupBuilder { self.cgroup } } /// A builder that configures the blkio controller of a control group. -pub struct BlkIoResourcesBuilder<'a> { - cgroup: CgroupBuilder<'a>, +pub struct BlkIoResourcesBuilder { + cgroup: CgroupBuilder, throttling_iops: bool, } -impl<'a> BlkIoResourcesBuilder<'a> { +impl BlkIoResourcesBuilder { gen_setter!(blkio, BlkIoController, set_weight, weight, u16); gen_setter!(blkio, BlkIoController, set_leaf_weight, leaf_weight, u16); @@ -322,7 +320,7 @@ impl<'a> BlkIoResourcesBuilder<'a> { minor: u64, weight: Option, leaf_weight: Option, - ) -> BlkIoResourcesBuilder<'a> { + ) -> BlkIoResourcesBuilder { self.cgroup .resources .blkio @@ -337,19 +335,19 @@ impl<'a> BlkIoResourcesBuilder<'a> { } /// Start configuring the I/O operations per second metric. - pub fn throttle_iops(mut self) -> BlkIoResourcesBuilder<'a> { + pub fn throttle_iops(mut self) -> BlkIoResourcesBuilder { self.throttling_iops = true; self } /// Start configuring the bytes per second metric. - pub fn throttle_bps(mut self) -> BlkIoResourcesBuilder<'a> { + pub fn throttle_bps(mut self) -> BlkIoResourcesBuilder { self.throttling_iops = false; self } /// Limit the read rate of the current metric for a certain device. - pub fn read(mut self, major: u64, minor: u64, rate: u64) -> BlkIoResourcesBuilder<'a> { + pub fn read(mut self, major: u64, minor: u64, rate: u64) -> BlkIoResourcesBuilder { let throttle = BlkIoDeviceThrottleResource { major, minor, rate }; if self.throttling_iops { self.cgroup @@ -368,7 +366,7 @@ impl<'a> BlkIoResourcesBuilder<'a> { } /// Limit the write rate of the current metric for a certain device. - pub fn write(mut self, major: u64, minor: u64, rate: u64) -> BlkIoResourcesBuilder<'a> { + pub fn write(mut self, major: u64, minor: u64, rate: u64) -> BlkIoResourcesBuilder { let throttle = BlkIoDeviceThrottleResource { major, minor, rate }; if self.throttling_iops { self.cgroup @@ -387,7 +385,7 @@ impl<'a> BlkIoResourcesBuilder<'a> { } /// Finish the construction of the blkio resources of a control group. - pub fn done(self) -> CgroupBuilder<'a> { + pub fn done(self) -> CgroupBuilder { self.cgroup } } diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 4e0742fa..fb06cb00 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -32,10 +32,12 @@ use crate::{Controllers, Hierarchy, Subsystem}; use crate::cgroup::Cgroup; /// The standard, original cgroup implementation. Often referred to as "cgroupv1". +#[derive(Debug)] pub struct V1 { mountinfo: Vec, } +#[derive(Debug)] pub struct V2 { root: String, } @@ -98,8 +100,7 @@ impl Hierarchy for V1 { } fn root_control_group(&self) -> Cgroup { - let b: &dyn Hierarchy = self as &dyn Hierarchy; - Cgroup::load(&*b, "".to_string()) + Cgroup::load(auto(), "".to_string()) } fn root(&self) -> PathBuf { @@ -170,8 +171,7 @@ impl Hierarchy for V2 { } fn root_control_group(&self) -> Cgroup { - let b: &dyn Hierarchy = self as &dyn Hierarchy; - Cgroup::load(&*b, "".to_string()) + Cgroup::load(auto(), "".to_string()) } fn root(&self) -> PathBuf { diff --git a/src/lib.rs b/src/lib.rs index cd53081e..46551cb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,7 +71,7 @@ use crate::systemd::SystemdController; pub use crate::cgroup::Cgroup; /// Contains all the subsystems that are available in this crate. -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Subsystem { /// Controller for the `Pid` subsystem, see `PidController` for more information. Pid(PidController), @@ -104,7 +104,7 @@ pub enum Subsystem { } #[doc(hidden)] -#[derive(Eq, PartialEq, Debug)] +#[derive(Eq, PartialEq, Debug, Clone)] pub enum Controllers { Pids, Mem, @@ -357,7 +357,7 @@ pub trait ControllIdentifier { /// Control group hierarchy (right now, only V1 is supported, but in the future Unified will be /// implemented as well). -pub trait Hierarchy { +pub trait Hierarchy: std::fmt::Debug + Send { /// Returns what subsystems are supported by the hierarchy. fn subsystems(&self) -> Vec; From 438d7748663b9c4c9caf8b2ffe4108d1eb0f07a1 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 3 Dec 2020 17:53:26 +0800 Subject: [PATCH 39/71] Fix test Fix test Signed-off-by: Tim Zhang --- src/cgroup_builder.rs | 5 ++--- tests/builder.rs | 35 ++++++++++++++--------------------- tests/cgroup.rs | 12 ++++++------ tests/cpu.rs | 2 +- tests/cpuset.rs | 6 +++--- tests/devices.rs | 2 +- tests/hugetlb.rs | 2 +- tests/memory.rs | 4 ++-- tests/pids.rs | 8 ++++---- tests/resources.rs | 2 +- 10 files changed, 35 insertions(+), 43 deletions(-) diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index 244ca4a9..f7033e4a 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -20,8 +20,7 @@ //! # use cgroups::devices::*; //! # use cgroups::cgroup_builder::*; //! let h = cgroups::hierarchies::auto(); -//! let h = Box::new(&*h); -//! let cgroup: Cgroup = CgroupBuilder::new("hello", h) +//! let cgroup: Cgroup = CgroupBuilder::new("hello") //! .memory() //! .kernel_memory_limit(1024 * 1024) //! .memory_hard_limit(1024 * 1024) @@ -58,7 +57,7 @@ //! .read(6, 1, 10) //! .write(11, 1, 100) //! .done() -//! .build(); +//! .build(h); //! ``` use crate::{ diff --git a/tests/builder.rs b/tests/builder.rs index cf215a34..7eef071e 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -18,12 +18,11 @@ use cgroups::*; #[test] pub fn test_cpu_res_build() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg: Cgroup = CgroupBuilder::new("test_cpu_res_build", h) + let cg: Cgroup = CgroupBuilder::new("test_cpu_res_build") .cpu() .shares(85) .done() - .build(); + .build(h); { let cpu: &CpuController = cg.controller_of().unwrap(); @@ -37,14 +36,13 @@ pub fn test_cpu_res_build() { #[test] pub fn test_memory_res_build() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg: Cgroup = CgroupBuilder::new("test_memory_res_build", h) + let cg: Cgroup = CgroupBuilder::new("test_memory_res_build") .memory() .kernel_memory_limit(128 * 1024 * 1024) .swappiness(70) .memory_hard_limit(1024 * 1024 * 1024) .done() - .build(); + .build(h); { let c: &MemController = cg.controller_of().unwrap(); @@ -61,12 +59,11 @@ pub fn test_memory_res_build() { #[test] pub fn test_pid_res_build() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg: Cgroup = CgroupBuilder::new("test_pid_res_build", h) + let cg: Cgroup = CgroupBuilder::new("test_pid_res_build") .pid() .maximum_number_of_processes(MaxValue::Value(123)) .done() - .build(); + .build(h); { let c: &PidController = cg.controller_of().unwrap(); @@ -81,12 +78,11 @@ pub fn test_pid_res_build() { #[ignore] // ignore this test for now, not sure why my kernel doesn't like it pub fn test_devices_res_build() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg: Cgroup = CgroupBuilder::new("test_devices_res_build", h) + let cg: Cgroup = CgroupBuilder::new("test_devices_res_build") .devices() .device(1, 6, DeviceType::Char, true, vec![DevicePermissions::Read]) .done() - .build(); + .build(h); { let c: &DevicesController = cg.controller_of().unwrap(); @@ -112,12 +108,11 @@ pub fn test_network_res_build() { // FIXME add cases for v2 return; } - let h = Box::new(&*h); - let cg: Cgroup = CgroupBuilder::new("test_network_res_build", h) + let cg: Cgroup = CgroupBuilder::new("test_network_res_build") .network() .class_id(1337) .done() - .build(); + .build(h); { let c: &NetClsController = cg.controller_of().unwrap(); @@ -134,12 +129,11 @@ pub fn test_hugepages_res_build() { // FIXME add cases for v2 return; } - let h = Box::new(&*h); - let cg: Cgroup = CgroupBuilder::new("test_hugepages_res_build", h) + let cg: Cgroup = CgroupBuilder::new("test_hugepages_res_build") .hugepages() .limit("2MB".to_string(), 4 * 2 * 1024 * 1024) .done() - .build(); + .build(h); { let c: &HugeTlbController = cg.controller_of().unwrap(); @@ -156,12 +150,11 @@ pub fn test_hugepages_res_build() { #[ignore] // high version kernel not support `blkio.weight` pub fn test_blkio_res_build() { let h = cgroups::hierarchies::auto(); - let h = Box::new(&*h); - let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build", h) + let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build") .blkio() .weight(100) .done() - .build(); + .build(h); { let c: &BlkIoController = cg.controller_of().unwrap(); diff --git a/tests/cgroup.rs b/tests/cgroup.rs index 7a6d8dd9..60ae4b34 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -13,7 +13,7 @@ use cgroups::{Cgroup, CgroupPid, Subsystem}; fn test_tasks_iterator() { let h = cgroups::hierarchies::auto(); let pid = libc::pid_t::from(nix::unistd::getpid()) as u64; - let cg = Cgroup::new(&*h, String::from("test_tasks_iterator")); + let cg = Cgroup::new(h, String::from("test_tasks_iterator")); { // Add a task to the control group. cg.add_task(CgroupPid::from(pid)).unwrap(); @@ -45,7 +45,7 @@ fn test_cgroup_with_relative_paths() { let cgroup_root = h.root(); let cgroup_name = "test_cgroup_with_relative_paths"; - let cg = Cgroup::load(&*h, String::from(cgroup_name)); + let cg = Cgroup::load(h, String::from(cgroup_name)); { let subsystems = cg.subsystems(); subsystems.into_iter().for_each(|sub| match sub { @@ -83,14 +83,14 @@ fn test_cgroup_v2() { return; } let h = cgroups::hierarchies::auto(); - let cg = Cgroup::load(&*h, String::from("test_v2")); + let cg = Cgroup::new(h, String::from("test_v2")); let mem_controller: &MemController = cg.controller_of().unwrap(); let (mem, swp, rev) = (4 * 1024 * 1000, 2 * 1024 * 1000, 1024 * 1000); - let _ = mem_controller.set_limit(mem); - let _ = mem_controller.set_memswap_limit(swp); - let _ = mem_controller.set_soft_limit(rev); + mem_controller.set_limit(mem).unwrap(); + mem_controller.set_memswap_limit(swp).unwrap(); + mem_controller.set_soft_limit(rev).unwrap(); let memory_stat = mem_controller.memory_stat(); println!("memory_stat {:?}", memory_stat); diff --git a/tests/cpu.rs b/tests/cpu.rs index 9eb4e99f..8d758713 100644 --- a/tests/cpu.rs +++ b/tests/cpu.rs @@ -10,7 +10,7 @@ use cgroups::Cgroup; #[test] fn test_cfs_quota_and_periods() { let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("test_cfs_quota_and_periods")); + let cg = Cgroup::new(h, String::from("test_cfs_quota_and_periods")); let cpu_controller: &CpuController = cg.controller_of().unwrap(); diff --git a/tests/cpuset.rs b/tests/cpuset.rs index 0e8aa2a6..34808ddf 100644 --- a/tests/cpuset.rs +++ b/tests/cpuset.rs @@ -13,7 +13,7 @@ use std::fs; #[test] fn test_cpuset_memory_pressure_root_cg() { let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("test_cpuset_memory_pressure_root_cg")); + let cg = Cgroup::new(h, String::from("test_cpuset_memory_pressure_root_cg")); { let cpuset: &CpuSetController = cg.controller_of().unwrap(); @@ -27,7 +27,7 @@ fn test_cpuset_memory_pressure_root_cg() { #[test] fn test_cpuset_set_cpus() { let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("test_cpuset_set_cpus")); + let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus")); { let cpuset: &CpuSetController = cg.controller_of().unwrap(); @@ -65,7 +65,7 @@ fn test_cpuset_set_cpus() { #[test] fn test_cpuset_set_cpus_add_task() { let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("test_cpuset_set_cpus_add_task/sub-dir")); + let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus_add_task/sub-dir")); let cpuset: &CpuSetController = cg.controller_of().unwrap(); let set = cpuset.cpuset(); diff --git a/tests/devices.rs b/tests/devices.rs index c8bc33c6..6758ff76 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -17,7 +17,7 @@ fn test_devices_parsing() { } let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("test_devices_parsing")); + let cg = Cgroup::new(h, String::from("test_devices_parsing")); { let devices: &DevicesController = cg.controller_of().unwrap(); diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index 505a6cb1..380afd37 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -17,7 +17,7 @@ fn test_hugetlb_sizes() { } let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("test_hugetlb_sizes")); + let cg = Cgroup::new(h, String::from("test_hugetlb_sizes")); { let hugetlb_controller: &HugeTlbController = cg.controller_of().unwrap(); let _ = hugetlb_controller.get_sizes(); diff --git a/tests/memory.rs b/tests/memory.rs index 92b508bd..0f57af5e 100644 --- a/tests/memory.rs +++ b/tests/memory.rs @@ -11,7 +11,7 @@ use cgroups::{Cgroup, MaxValue}; #[test] fn test_disable_oom_killer() { let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("test_disable_oom_killer")); + let cg = Cgroup::new(h, String::from("test_disable_oom_killer")); { let mem_controller: &MemController = cg.controller_of().unwrap(); @@ -40,7 +40,7 @@ fn set_mem_v2() { return; } - let cg = Cgroup::new(&*h, String::from("set_mem_v2")); + let cg = Cgroup::new(h, String::from("set_mem_v2")); { let mem_controller: &MemController = cg.controller_of().unwrap(); diff --git a/tests/pids.rs b/tests/pids.rs index c756581f..f5d7191a 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -17,7 +17,7 @@ use libc::pid_t; #[test] fn create_and_delete_cgroup() { let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("create_and_delete_cgroup")); + let cg = Cgroup::new(h, String::from("create_and_delete_cgroup")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); pidcontroller.set_pid_max(MaxValue::Value(1337)).unwrap(); @@ -31,7 +31,7 @@ fn create_and_delete_cgroup() { #[test] fn test_pids_current_is_zero() { let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("test_pids_current_is_zero")); + let cg = Cgroup::new(h, String::from("test_pids_current_is_zero")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); let current = pidcontroller.get_pid_current(); @@ -43,7 +43,7 @@ fn test_pids_current_is_zero() { #[test] fn test_pids_events_is_zero() { let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("test_pids_events_is_zero")); + let cg = Cgroup::new(h, String::from("test_pids_events_is_zero")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); let events = pidcontroller.get_pid_events(); @@ -56,7 +56,7 @@ fn test_pids_events_is_zero() { #[test] fn test_pid_events_is_not_zero() { let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("test_pid_events_is_not_zero")); + let cg = Cgroup::new(h, String::from("test_pid_events_is_not_zero")); { let pids: &PidController = cg.controller_of().unwrap(); let before = pids.get_pid_events(); diff --git a/tests/resources.rs b/tests/resources.rs index 7ceacfe1..0cb65bc0 100644 --- a/tests/resources.rs +++ b/tests/resources.rs @@ -11,7 +11,7 @@ use cgroups::{Cgroup, MaxValue, PidResources, Resources}; #[test] fn pid_resources() { let h = cgroups::hierarchies::auto(); - let cg = Cgroup::new(&*h, String::from("pid_resources")); + let cg = Cgroup::new(h, String::from("pid_resources")); { let res = Resources { pid: PidResources { From c254fffbe0defa8946b7385b2cd92e7453b82e1d Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 3 Dec 2020 17:53:46 +0800 Subject: [PATCH 40/71] Update readme Update readme Signed-off-by: Tim Zhang --- README.md | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index da0754e0..6f26f5c9 100644 --- a/README.md +++ b/README.md @@ -9,24 +9,29 @@ is planned for the Unified hierarchy. ## Create a control group using the builder pattern ``` rust -// Acquire a handle for the V1 cgroup hierarchy. -let hier = ::hierarchies::V1::new(); + + +use cgroups::*; +use cgroups::cgroup_builder::*; + +// Acquire a handle for the cgroup hierarchy. +let hier = cgroups::hierarchies::auto(); // Use the builder pattern (see the documentation to create the control group) // // This creates a control group named "example" in the V1 hierarchy. -let cg: Cgroup = CgroupBuilder::new("example", &v1) - .cpu() - .shares(85) - .done() - .build(); + let cg: Cgroup = CgroupBuilder::new("example") + .cpu() + .shares(85) + .done() + .build(hier); // Now `cg` is a control group that gets 85% of the CPU time in relative to // other control groups. // Get a handle to the CPU controller. -let cpus: &CpuController = cg.controller_of().unwrap(); -cpus.add_task(1234u64); +let cpus: &cgroups::cpu::CpuController = cg.controller_of().unwrap(); +cpus.add_task(&CgroupPid::from(1234u64)); // [...] From 059204589c4ae84e64cfd6beee0ea385fff4ac5f Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 7 Dec 2020 15:39:17 +0800 Subject: [PATCH 41/71] Ignore kmem in cgroup v2 Because there is no kmem in cgroup v2. Signed-off-by: Tim Zhang --- src/memory.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/memory.rs b/src/memory.rs index 314de66d..7e87a961 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -702,6 +702,11 @@ impl MemController { /// Reset the kernel memory fail counter pub fn reset_kmem_fail_count(&self) -> Result<()> { + // Ignore kmem because there is no kmem in cgroup v2 + if self.v2 { + return Ok(()); + } + self.open_path("memory.kmem.failcnt", true) .and_then(|mut file| { file.write_all("0".to_string().as_ref()) @@ -711,6 +716,11 @@ impl MemController { /// Reset the TCP related fail counter pub fn reset_tcp_fail_count(&self) -> Result<()> { + // Ignore kmem because there is no kmem in cgroup v2 + if self.v2 { + return Ok(()); + } + self.open_path("memory.kmem.tcp.failcnt", true) .and_then(|mut file| { file.write_all("0".to_string().as_ref()) @@ -750,6 +760,11 @@ impl MemController { /// Set the kernel memory limit of the control group, in bytes. pub fn set_kmem_limit(&self, limit: i64) -> Result<()> { + // Ignore kmem because there is no kmem in cgroup v2 + if self.v2 { + return Ok(()); + } + self.open_path("memory.kmem.limit_in_bytes", true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) @@ -771,6 +786,11 @@ impl MemController { /// Set how much kernel memory can be used for TCP-related buffers by the control group. pub fn set_tcp_limit(&self, limit: i64) -> Result<()> { + // Ignore kmem because there is no kmem in cgroup v2 + if self.v2 { + return Ok(()); + } + self.open_path("memory.kmem.tcp.limit_in_bytes", true) .and_then(|mut file| { file.write_all(limit.to_string().as_ref()) From 61a0957a65cd60aa9de4520c65b4d65ba9afd952 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 7 Dec 2020 15:53:14 +0800 Subject: [PATCH 42/71] Fix set_swappiness in cgroup v2 The file should be memory.swap.max in cgroup v2. Signed-off-by: Tim Zhang --- src/memory.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/memory.rs b/src/memory.rs index 7e87a961..6243a151 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -818,11 +818,15 @@ impl MemController { /// /// Note that a value of zero does not imply that the process will not be swapped out. pub fn set_swappiness(&self, swp: u64) -> Result<()> { - self.open_path("memory.swappiness", true) - .and_then(|mut file| { - file.write_all(swp.to_string().as_ref()) - .map_err(|e| Error::with_cause(WriteFailed, e)) - }) + let mut file = "memory.swappiness"; + if self.v2 { + file = "memory.swap.max" + } + + self.open_path(file, true).and_then(|mut file| { + file.write_all(swp.to_string().as_ref()) + .map_err(|e| Error::with_cause(WriteFailed, e)) + }) } pub fn disable_oom_killer(&self) -> Result<()> { From a89f4a062e76e89f316db51ec93cc473fb6c99ce Mon Sep 17 00:00:00 2001 From: Qingyuan Hou Date: Thu, 10 Dec 2020 01:35:01 +0800 Subject: [PATCH 43/71] Support set notify_on_release & release_agent Support set notify_on_release & release_agent Signed-off-by: Qingyuan Hou --- src/cgroup.rs | 16 ++++++++++++++++ src/lib.rs | 22 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/cgroup.rs b/src/cgroup.rs index 3e927579..63f413ab 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -260,6 +260,22 @@ impl Cgroup { .try_for_each(|sub| sub.to_controller().add_task_by_tgid(&pid)) } + /// Set notify_on_release to the control group. + pub fn set_notify_on_release(&self, enable: bool) -> Result<()> { + self.subsystems() + .iter() + .try_for_each(|sub| sub.to_controller().set_notify_on_release(enable)) + } + + /// Set release_agent + pub fn set_release_agent(&self, path: &str) -> Result<()> { + self.hier + .root_control_group() + .subsystems() + .iter() + .try_for_each(|sub| sub.to_controller().set_release_agent(path)) + } + /// Returns an Iterator that can be used to iterate over the tasks that are currently in the /// control group. pub fn tasks(&self) -> Vec { diff --git a/src/lib.rs b/src/lib.rs index 46551cb2..f1205be4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -246,6 +246,12 @@ pub trait Controller { /// Does this controller already exist? fn exists(&self) -> bool; + /// Set notify_on_release + fn set_notify_on_release(&self, enable: bool) -> Result<()>; + + /// Set release_agent + fn set_release_agent(&self, path: &str) -> Result<()>; + /// Delete the controller. fn delete(&self) -> Result<()>; @@ -290,6 +296,22 @@ where } } + /// Set notify_on_release + fn set_notify_on_release(&self, enable: bool) -> Result<()> { + self.open_path("notify_on_release", true) + .and_then(|mut file| { + write!(file, "{}", enable as i32) + .map_err(|e| Error::with_cause(ErrorKind::WriteFailed, e)) + }) + } + + /// Set release_agent + fn set_release_agent(&self, path: &str) -> Result<()> { + self.open_path("release_agent", true).and_then(|mut file| { + file.write_all(path.as_bytes()) + .map_err(|e| Error::with_cause(ErrorKind::WriteFailed, e)) + }) + } /// Does this controller already exist? fn exists(&self) -> bool { self.get_path().exists() From e1e05d3a1ce9909da02cd36a0a789f49cc372297 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 16 Dec 2020 21:06:04 +0800 Subject: [PATCH 44/71] Make new_with_relative_paths=new and load_with_relative_paths=new in v2 Because the relative_paths is only valid for cgroup v1, the v2 use unified hierarchy. Signed-off-by: Tim Zhang --- src/cgroup.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/cgroup.rs b/src/cgroup.rs index 63f413ab..5dedab5c 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -86,6 +86,8 @@ impl Cgroup { /// Create a new control group in the hierarchy `hier`, with name `path` and `relative_paths` /// /// Returns a handle to the control group that can be used to manipulate it. + /// + /// Note that this method is only meaningful for cgroup v1, call it is equivalent to call `new` in the v2 mode pub fn new_with_relative_paths>( hier: Box, path: P, @@ -123,11 +125,18 @@ impl Cgroup { /// /// Returns a handle to the control group (that possibly does not exist until `create()` has /// been called on the cgroup. + /// + /// Note that this method is only meaningful for cgroup v1, call it is equivalent to call `load` in the v2 mode pub fn load_with_relative_paths>( hier: Box, path: P, relative_paths: HashMap, ) -> Cgroup { + // relative_paths only valid for cgroup v1 + if hier.v2() { + return Self::load(hier, path); + } + let path = path.as_ref(); let mut subsystems = hier.subsystems(); if path.as_os_str() != "" { From e160df07519630da30c856633f981ca58e809ca7 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Thu, 17 Dec 2020 15:46:43 +0800 Subject: [PATCH 45/71] Make read_i64_from private and merge read_str_from to its caller Also remove duplicated read_i64_from. Signed-off-by: Tim Zhang --- src/lib.rs | 18 ++++++++---------- src/memory.rs | 12 +----------- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f1205be4..9253c349 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -219,7 +219,13 @@ mod sealed { } fn get(&self, key: &str) -> Result { - self.open_path(key, false).and_then(read_str_from) + self.open_path(key, false).and_then(|mut file: File| { + let mut string = String::new(); + match file.read_to_string(&mut string) { + Ok(_) => Ok(string.trim().to_owned()), + Err(e) => Err(Error::with_cause(ReadFailed, e)), + } + }) } } } @@ -827,7 +833,7 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result Result { +fn read_i64_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { Ok(_) => string @@ -837,11 +843,3 @@ pub fn read_i64_from(mut file: File) -> Result { Err(e) => Err(Error::with_cause(ReadFailed, e)), } } - -pub fn read_str_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => Ok(string.trim().to_owned()), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} diff --git a/src/memory.rs b/src/memory.rs index 6243a151..04fd908e 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -17,6 +17,7 @@ use std::sync::mpsc::Receiver; use crate::error::ErrorKind::*; use crate::error::*; use crate::events; +use crate::read_i64_from; use crate::flat_keyed_to_hashmap; @@ -880,17 +881,6 @@ fn read_u64_from(mut file: File) -> Result { } } -fn read_i64_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => string - .trim() - .parse() - .map_err(|e| Error::with_cause(ParseError, e)), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - fn read_string_from(mut file: File) -> Result { let mut string = String::new(); match file.read_to_string(&mut string) { From 9baa06522615157b12d6467fb89b7e18390b430a Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 9 Nov 2020 15:19:28 +0800 Subject: [PATCH 46/71] release: v0.2.0 Bump vertion to 0.2.0 Signed-off-by: Tim Zhang --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5bdbbe66..9ff10a3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ repository = "https://github.com/levex/cgroups-rs" keywords = ["linux", "cgroup", "containers", "isolation"] categories = ["os", "api-bindings", "os::unix-apis"] license = "MIT OR Apache-2.0" -version = "0.1.1-alpha.0" +version = "0.2.0" authors = ["Levente Kurusa ", "Sam Wilson "] edition = "2018" From eb6577e3e01c7338b435614afbe32714158d4177 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 21 Dec 2020 11:40:57 +0800 Subject: [PATCH 47/71] Change package name to cgroups-rs We need a new package name to create a new crate Signed-off-by: Tim Zhang --- Cargo.toml | 6 +++--- README.md | 8 ++++---- src/cgroup_builder.rs | 8 ++++---- src/lib.rs | 4 ++-- tests/builder.rs | 32 ++++++++++++++++---------------- tests/cgroup.rs | 16 ++++++++-------- tests/cpu.rs | 6 +++--- tests/cpuset.rs | 12 ++++++------ tests/devices.rs | 8 ++++---- tests/hugetlb.rs | 10 +++++----- tests/memory.rs | 10 +++++----- tests/pids.rs | 14 +++++++------- tests/resources.rs | 6 +++--- 13 files changed, 70 insertions(+), 70 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9ff10a3d..14cf747d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ [package] -name = "cgroups" +name = "cgroups-rs" description = "Native Rust crate for managing control groups on Linux" -repository = "https://github.com/levex/cgroups-rs" +repository = "https://github.com/kata-containers/cgroups-rs" keywords = ["linux", "cgroup", "containers", "isolation"] categories = ["os", "api-bindings", "os::unix-apis"] license = "MIT OR Apache-2.0" version = "0.2.0" -authors = ["Levente Kurusa ", "Sam Wilson "] +authors = ["The Kata Containers community ", "Levente Kurusa ", "Sam Wilson "] edition = "2018" [dependencies] diff --git a/README.md b/README.md index 6f26f5c9..617ed66d 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ is planned for the Unified hierarchy. ``` rust -use cgroups::*; -use cgroups::cgroup_builder::*; +use cgroups_rs::*; +use cgroups_rs::cgroup_builder::*; // Acquire a handle for the cgroup hierarchy. -let hier = cgroups::hierarchies::auto(); +let hier = cgroups_rs::hierarchies::auto(); // Use the builder pattern (see the documentation to create the control group) // @@ -30,7 +30,7 @@ let hier = cgroups::hierarchies::auto(); // other control groups. // Get a handle to the CPU controller. -let cpus: &cgroups::cpu::CpuController = cg.controller_of().unwrap(); +let cpus: &cgroups_rs::cpu::CpuController = cg.controller_of().unwrap(); cpus.add_task(&CgroupPid::from(1234u64)); // [...] diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index f7033e4a..e410fd83 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -16,10 +16,10 @@ //! by a call to `build()`. //! //! ```rust,no_run -//! # use cgroups::*; -//! # use cgroups::devices::*; -//! # use cgroups::cgroup_builder::*; -//! let h = cgroups::hierarchies::auto(); +//! # use cgroups_rs::*; +//! # use cgroups_rs::devices::*; +//! # use cgroups_rs::cgroup_builder::*; +//! let h = cgroups_rs::hierarchies::auto(); //! let cgroup: Cgroup = CgroupBuilder::new("hello") //! .memory() //! .kernel_memory_limit(1024 * 1024) diff --git a/src/lib.rs b/src/lib.rs index 9253c349..e08f2d97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -422,7 +422,7 @@ pub struct MemoryResources { /// /// # Usage: /// ``` - /// let resource = &mut cgroups::Resources::default(); + /// let resource = &mut cgroups_rs::Resources::default(); /// resource.memory.attrs.insert("memory.numa_balancing", "true".to_string()); /// // apply here pub attrs: std::collections::HashMap<&'static str, String>, @@ -464,7 +464,7 @@ pub struct CpuResources { /// Customized key-value attributes /// # Usage: /// ``` - /// let resource = &mut cgroups::Resources::default(); + /// let resource = &mut cgroups_rs::Resources::default(); /// resource.cpu.attrs.insert("cpu.cfs_init_buffer_us", "10".to_string()); /// // apply here /// ``` diff --git a/tests/builder.rs b/tests/builder.rs index 7eef071e..7e0bed22 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -5,19 +5,19 @@ // //! Some simple tests covering the builder pattern for control groups. -use cgroups::blkio::*; -use cgroups::cgroup_builder::*; -use cgroups::cpu::*; -use cgroups::devices::*; -use cgroups::hugetlb::*; -use cgroups::memory::*; -use cgroups::net_cls::*; -use cgroups::pid::*; -use cgroups::*; +use cgroups_rs::blkio::*; +use cgroups_rs::cgroup_builder::*; +use cgroups_rs::cpu::*; +use cgroups_rs::devices::*; +use cgroups_rs::hugetlb::*; +use cgroups_rs::memory::*; +use cgroups_rs::net_cls::*; +use cgroups_rs::pid::*; +use cgroups_rs::*; #[test] pub fn test_cpu_res_build() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg: Cgroup = CgroupBuilder::new("test_cpu_res_build") .cpu() .shares(85) @@ -35,7 +35,7 @@ pub fn test_cpu_res_build() { #[test] pub fn test_memory_res_build() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg: Cgroup = CgroupBuilder::new("test_memory_res_build") .memory() .kernel_memory_limit(128 * 1024 * 1024) @@ -58,7 +58,7 @@ pub fn test_memory_res_build() { #[test] pub fn test_pid_res_build() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg: Cgroup = CgroupBuilder::new("test_pid_res_build") .pid() .maximum_number_of_processes(MaxValue::Value(123)) @@ -77,7 +77,7 @@ pub fn test_pid_res_build() { #[test] #[ignore] // ignore this test for now, not sure why my kernel doesn't like it pub fn test_devices_res_build() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg: Cgroup = CgroupBuilder::new("test_devices_res_build") .devices() .device(1, 6, DeviceType::Char, true, vec![DevicePermissions::Read]) @@ -103,7 +103,7 @@ pub fn test_devices_res_build() { #[test] pub fn test_network_res_build() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); if h.v2() { // FIXME add cases for v2 return; @@ -124,7 +124,7 @@ pub fn test_network_res_build() { #[test] pub fn test_hugepages_res_build() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); if h.v2() { // FIXME add cases for v2 return; @@ -149,7 +149,7 @@ pub fn test_hugepages_res_build() { #[test] #[ignore] // high version kernel not support `blkio.weight` pub fn test_blkio_res_build() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build") .blkio() .weight(100) diff --git a/tests/cgroup.rs b/tests/cgroup.rs index 60ae4b34..962cdf5a 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -5,13 +5,13 @@ // //! Simple unit tests about the control groups system. -use cgroups::memory::MemController; -use cgroups::Controller; -use cgroups::{Cgroup, CgroupPid, Subsystem}; +use cgroups_rs::memory::MemController; +use cgroups_rs::Controller; +use cgroups_rs::{Cgroup, CgroupPid, Subsystem}; #[test] fn test_tasks_iterator() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let pid = libc::pid_t::from(nix::unistd::getpid()) as u64; let cg = Cgroup::new(h, String::from("test_tasks_iterator")); { @@ -38,10 +38,10 @@ fn test_tasks_iterator() { #[test] fn test_cgroup_with_relative_paths() { - if cgroups::hierarchies::is_cgroup2_unified_mode() { + if cgroups_rs::hierarchies::is_cgroup2_unified_mode() { return; } - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cgroup_root = h.root(); let cgroup_name = "test_cgroup_with_relative_paths"; @@ -79,10 +79,10 @@ fn test_cgroup_with_relative_paths() { #[test] fn test_cgroup_v2() { - if !cgroups::hierarchies::is_cgroup2_unified_mode() { + if !cgroups_rs::hierarchies::is_cgroup2_unified_mode() { return; } - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_v2")); let mem_controller: &MemController = cg.controller_of().unwrap(); diff --git a/tests/cpu.rs b/tests/cpu.rs index 8d758713..959474e7 100644 --- a/tests/cpu.rs +++ b/tests/cpu.rs @@ -4,12 +4,12 @@ // //! Simple unit tests about the CPU control groups system. -use cgroups::cpu::CpuController; -use cgroups::Cgroup; +use cgroups_rs::cpu::CpuController; +use cgroups_rs::Cgroup; #[test] fn test_cfs_quota_and_periods() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_cfs_quota_and_periods")); let cpu_controller: &CpuController = cg.controller_of().unwrap(); diff --git a/tests/cpuset.rs b/tests/cpuset.rs index 34808ddf..a714683d 100644 --- a/tests/cpuset.rs +++ b/tests/cpuset.rs @@ -4,15 +4,15 @@ // SPDX-License-Identifier: Apache-2.0 or MIT // -use cgroups::cpuset::CpuSetController; -use cgroups::error::ErrorKind; -use cgroups::{Cgroup, CgroupPid}; +use cgroups_rs::cpuset::CpuSetController; +use cgroups_rs::error::ErrorKind; +use cgroups_rs::{Cgroup, CgroupPid}; use std::fs; #[test] fn test_cpuset_memory_pressure_root_cg() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_cpuset_memory_pressure_root_cg")); { let cpuset: &CpuSetController = cg.controller_of().unwrap(); @@ -26,7 +26,7 @@ fn test_cpuset_memory_pressure_root_cg() { #[test] fn test_cpuset_set_cpus() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus")); { let cpuset: &CpuSetController = cg.controller_of().unwrap(); @@ -64,7 +64,7 @@ fn test_cpuset_set_cpus() { #[test] fn test_cpuset_set_cpus_add_task() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus_add_task/sub-dir")); let cpuset: &CpuSetController = cg.controller_of().unwrap(); diff --git a/tests/devices.rs b/tests/devices.rs index 6758ff76..a88bb294 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -6,17 +6,17 @@ //! Integration tests about the devices subsystem -use cgroups::devices::{DevicePermissions, DeviceType, DevicesController}; -use cgroups::{Cgroup, DeviceResource}; +use cgroups_rs::devices::{DevicePermissions, DeviceType, DevicesController}; +use cgroups_rs::{Cgroup, DeviceResource}; #[test] fn test_devices_parsing() { // now only v2 - if cgroups::hierarchies::is_cgroup2_unified_mode() { + if cgroups_rs::hierarchies::is_cgroup2_unified_mode() { return; } - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_devices_parsing")); { let devices: &DevicesController = cg.controller_of().unwrap(); diff --git a/tests/hugetlb.rs b/tests/hugetlb.rs index 380afd37..cc33e286 100644 --- a/tests/hugetlb.rs +++ b/tests/hugetlb.rs @@ -4,19 +4,19 @@ // //! Integration tests about the hugetlb subsystem -use cgroups::error::*; -use cgroups::hugetlb::{self, HugeTlbController}; -use cgroups::Cgroup; +use cgroups_rs::error::*; +use cgroups_rs::hugetlb::{self, HugeTlbController}; +use cgroups_rs::Cgroup; use std::fs; #[test] fn test_hugetlb_sizes() { // now only v2 - if cgroups::hierarchies::is_cgroup2_unified_mode() { + if cgroups_rs::hierarchies::is_cgroup2_unified_mode() { return; } - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_hugetlb_sizes")); { let hugetlb_controller: &HugeTlbController = cg.controller_of().unwrap(); diff --git a/tests/memory.rs b/tests/memory.rs index 0f57af5e..9ab2e018 100644 --- a/tests/memory.rs +++ b/tests/memory.rs @@ -4,13 +4,13 @@ // //! Integration tests about the hugetlb subsystem -use cgroups::memory::{MemController, SetMemory}; -use cgroups::Controller; -use cgroups::{Cgroup, MaxValue}; +use cgroups_rs::memory::{MemController, SetMemory}; +use cgroups_rs::Controller; +use cgroups_rs::{Cgroup, MaxValue}; #[test] fn test_disable_oom_killer() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_disable_oom_killer")); { let mem_controller: &MemController = cg.controller_of().unwrap(); @@ -35,7 +35,7 @@ fn test_disable_oom_killer() { #[test] fn set_mem_v2() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); if !h.v2() { return; } diff --git a/tests/pids.rs b/tests/pids.rs index f5d7191a..cdae8659 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -5,9 +5,9 @@ // //! Integration tests about the pids subsystem -use cgroups::pid::PidController; -use cgroups::Controller; -use cgroups::{Cgroup, MaxValue}; +use cgroups_rs::pid::PidController; +use cgroups_rs::Controller; +use cgroups_rs::{Cgroup, MaxValue}; use nix::sys::wait::{waitpid, WaitStatus}; use nix::unistd::{fork, ForkResult}; @@ -16,7 +16,7 @@ use libc::pid_t; #[test] fn create_and_delete_cgroup() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("create_and_delete_cgroup")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); @@ -30,7 +30,7 @@ fn create_and_delete_cgroup() { #[test] fn test_pids_current_is_zero() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_pids_current_is_zero")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); @@ -42,7 +42,7 @@ fn test_pids_current_is_zero() { #[test] fn test_pids_events_is_zero() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_pids_events_is_zero")); { let pidcontroller: &PidController = cg.controller_of().unwrap(); @@ -55,7 +55,7 @@ fn test_pids_events_is_zero() { #[test] fn test_pid_events_is_not_zero() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("test_pid_events_is_not_zero")); { let pids: &PidController = cg.controller_of().unwrap(); diff --git a/tests/resources.rs b/tests/resources.rs index 0cb65bc0..056349ee 100644 --- a/tests/resources.rs +++ b/tests/resources.rs @@ -5,12 +5,12 @@ // //! Integration test about setting resources using `apply()` -use cgroups::pid::PidController; -use cgroups::{Cgroup, MaxValue, PidResources, Resources}; +use cgroups_rs::pid::PidController; +use cgroups_rs::{Cgroup, MaxValue, PidResources, Resources}; #[test] fn pid_resources() { - let h = cgroups::hierarchies::auto(); + let h = cgroups_rs::hierarchies::auto(); let cg = Cgroup::new(h, String::from("pid_resources")); { let res = Resources { From 35ecd6fd7713483791e2b8472b0fe60ea7e35430 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 21 Dec 2020 15:51:34 +0800 Subject: [PATCH 48/71] Update readme - Change the travis badge - Update the description about v2 supporting. Signed-off-by: Tim Zhang --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 617ed66d..41c65399 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ -# cgroups-rs ![Build](https://travis-ci.org/levex/cgroups-rs.svg?branch=master) +# cgroups-rs ![Build](https://travis-ci.org/kata-containers/cgroups-rs.svg?branch=master) Native Rust library for managing control groups under Linux -Right now the crate only support the original, V1 hierarchy, however support -is planned for the Unified hierarchy. +Both v1 and v2 of cgroups are supported. # Examples From 033fa4b8574d605771210fd5a35f8b9d1b20908f Mon Sep 17 00:00:00 2001 From: LiYa'nan Date: Wed, 23 Dec 2020 13:55:08 +0800 Subject: [PATCH 49/71] optimize and refactor: read_to_string and read_i[u]64_from There's so many Duplicated read_string_from method in different subsystem's implementation, so as read_u64_from/read_i64_from methods. (1) Move the read_string_from method into `lib.rs`, called by each subsystem implementation as needed. (2) Refactor read_u[i]64_from method with the help Rust Generic f unction `read_from` and wrapped by read_u64_from or read_i64_from. fix: #20 Signed-off-by: LiYa'nan --- src/blkio.rs | 23 ++--------------------- src/cpu.rs | 13 +------------ src/cpuacct.rs | 24 ++---------------------- src/cpuset.rs | 23 ++--------------------- src/hugetlb.rs | 16 ++-------------- src/lib.rs | 28 +++++++++++++++++++++++++--- src/memory.rs | 24 ++---------------------- src/net_cls.rs | 15 ++------------- src/net_prio.rs | 15 ++------------- src/pid.rs | 13 +------------ src/rdma.rs | 12 ++---------- 11 files changed, 43 insertions(+), 163 deletions(-) diff --git a/src/blkio.rs b/src/blkio.rs index 7e21faf5..457dceb4 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -8,13 +8,13 @@ //! //! See the Kernel's documentation for more information about this subsystem, found at: //! [Documentation/cgroup-v1/blkio-controller.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt) -use std::fs::File; -use std::io::{Read, Write}; +use std::io::Write; use std::path::PathBuf; use crate::error::ErrorKind::*; use crate::error::*; +use crate::{read_string_from, read_u64_from}; use crate::{ BlkIoResources, ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem, }; @@ -401,25 +401,6 @@ impl<'a> From<&'a Subsystem> for &'a BlkIoController { } } -fn read_string_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => Ok(string.trim().to_string()), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - -fn read_u64_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => string - .trim() - .parse() - .map_err(|e| Error::with_cause(ParseError, e)), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - impl BlkIoController { /// Constructs a new `BlkIoController` with `root` serving as the root of the control group. pub fn new(root: PathBuf, v2: bool) -> Self { diff --git a/src/cpu.rs b/src/cpu.rs index bcf92062..6293e3c9 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -15,7 +15,7 @@ use std::path::PathBuf; use crate::error::ErrorKind::*; use crate::error::*; -use crate::{parse_max_value, read_i64_from}; +use crate::{parse_max_value, read_i64_from, read_u64_from}; use crate::{ ControllIdentifier, ControllerInternal, Controllers, CpuResources, CustomizedAttribute, @@ -110,17 +110,6 @@ impl<'a> From<&'a Subsystem> for &'a CpuController { } } -fn read_u64_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => string - .trim() - .parse() - .map_err(|e| Error::with_cause(ParseError, e)), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - impl CpuController { /// Contructs a new `CpuController` with `root` serving as the root of the control group. pub fn new(root: PathBuf, v2: bool) -> Self { diff --git a/src/cpuacct.rs b/src/cpuacct.rs index 6efde64f..57eafbd6 100644 --- a/src/cpuacct.rs +++ b/src/cpuacct.rs @@ -7,13 +7,13 @@ //! //! See the Kernel's documentation for more information about this subsystem, found at: //! [Documentation/cgroup-v1/cpuacct.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt) -use std::fs::File; -use std::io::{Read, Write}; +use std::io::Write; use std::path::PathBuf; use crate::error::ErrorKind::*; use crate::error::*; +use crate::{read_string_from, read_u64_from}; use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem}; /// A controller that allows controlling the `cpuacct` subsystem of a Cgroup. @@ -97,26 +97,6 @@ impl<'a> From<&'a Subsystem> for &'a CpuAcctController { } } -fn read_u64_from(mut file: File) -> Result { - let mut string = String::new(); - let res = file.read_to_string(&mut string); - match res { - Ok(_) => match string.trim().parse() { - Ok(e) => Ok(e), - Err(e) => Err(Error::with_cause(ParseError, e)), - }, - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - -fn read_string_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => Ok(string.trim().to_string()), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - impl CpuAcctController { /// Contructs a new `CpuAcctController` with `root` serving as the root of the control group. pub fn new(root: PathBuf) -> Self { diff --git a/src/cpuset.rs b/src/cpuset.rs index cef4679c..957ed7a5 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -10,13 +10,13 @@ //! [Documentation/cgroup-v1/cpusets.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt) use log::*; -use std::fs::File; -use std::io::{Read, Write}; +use std::io::Write; use std::path::PathBuf; use crate::error::ErrorKind::*; use crate::error::*; +use crate::{read_string_from, read_u64_from}; use crate::{ ControllIdentifier, ControllerInternal, Controllers, CpuResources, Resources, Subsystem, }; @@ -204,25 +204,6 @@ impl<'a> From<&'a Subsystem> for &'a CpuSetController { } } -fn read_string_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => Ok(string.trim().to_string()), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - -fn read_u64_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => string - .trim() - .parse() - .map_err(|e| Error::with_cause(ParseError, e)), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - /// Parse a string like "1,2,4-5,8" into a list of (start, end) tuples. fn parse_range(s: String) -> Result> { let mut fin = Vec::new(); diff --git a/src/hugetlb.rs b/src/hugetlb.rs index 686a599b..ed8d83d9 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -8,13 +8,12 @@ //! //! See the Kernel's documentation for more information about this subsystem, found at: //! [Documentation/cgroup-v1/hugetlb.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/hugetlb.txt) -use std::fs::File; -use std::io::{Read, Write}; +use std::io::Write; use std::path::PathBuf; use crate::error::ErrorKind::*; use crate::error::*; -use crate::flat_keyed_to_vec; +use crate::{flat_keyed_to_vec, read_u64_from}; use crate::{ ControllIdentifier, ControllerInternal, Controllers, HugePageResources, Resources, Subsystem, @@ -86,17 +85,6 @@ impl<'a> From<&'a Subsystem> for &'a HugeTlbController { } } -fn read_u64_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => string - .trim() - .parse() - .map_err(|e| Error::with_cause(ParseError, e)), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - impl HugeTlbController { /// Constructs a new `HugeTlbController` with `root` serving as the root of the control group. pub fn new(root: PathBuf, v2: bool) -> Self { diff --git a/src/lib.rs b/src/lib.rs index e08f2d97..3d3c68d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ use std::collections::HashMap; use std::fs::{self, File}; use std::io::{BufRead, BufReader, Read, Write}; use std::path::{Path, PathBuf}; +use std::str::FromStr; macro_rules! update_and_test { ($self: ident, $set_func:ident, $value:expr, $get_func:ident) => { @@ -832,14 +833,35 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result Result { +fn read_from(mut file: File) -> Result +where + T: FromStr, + ::Err: 'static + Send + Sync + std::error::Error, +{ let mut string = String::new(); match file.read_to_string(&mut string) { Ok(_) => string .trim() - .parse() + .parse::() .map_err(|e| Error::with_cause(ParseError, e)), Err(e) => Err(Error::with_cause(ReadFailed, e)), } } + +fn read_string_from(mut file: File) -> Result { + let mut string = String::new(); + match file.read_to_string(&mut string) { + Ok(_) => Ok(string.trim().to_string()), + Err(e) => Err(Error::with_cause(ReadFailed, e)), + } +} + +/// read and parse an u64 data +fn read_u64_from(file: File) -> Result { + read_from::(file) +} + +/// read and parse an i64 data +fn read_i64_from(file: File) -> Result { + read_from::(file) +} diff --git a/src/memory.rs b/src/memory.rs index 04fd908e..8ceb15a2 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -9,15 +9,14 @@ //! See the Kernel's documentation for more information about this subsystem, found at: //! [Documentation/cgroup-v1/memory.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt) use std::collections::HashMap; -use std::fs::File; -use std::io::{Read, Write}; +use std::io::Write; use std::path::PathBuf; use std::sync::mpsc::Receiver; use crate::error::ErrorKind::*; use crate::error::*; use crate::events; -use crate::read_i64_from; +use crate::{read_i64_from, read_string_from, read_u64_from}; use crate::flat_keyed_to_hashmap; @@ -870,25 +869,6 @@ impl<'a> From<&'a Subsystem> for &'a MemController { } } -fn read_u64_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => string - .trim() - .parse() - .map_err(|e| Error::with_cause(ParseError, e)), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - -fn read_string_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => Ok(string.trim().to_string()), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - #[cfg(test)] mod tests { use crate::memory::{ diff --git a/src/net_cls.rs b/src/net_cls.rs index 5328eb14..77b3f07d 100644 --- a/src/net_cls.rs +++ b/src/net_cls.rs @@ -7,13 +7,13 @@ //! //! See the Kernel's documentation for more information about this subsystem, found at: //! [Documentation/cgroup-v1/net_cls.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/net_cls.txt) -use std::fs::File; -use std::io::{Read, Write}; +use std::io::Write; use std::path::PathBuf; use crate::error::ErrorKind::*; use crate::error::*; +use crate::read_u64_from; use crate::{ ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, Subsystem, }; @@ -74,17 +74,6 @@ impl<'a> From<&'a Subsystem> for &'a NetClsController { } } -fn read_u64_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => string - .trim() - .parse() - .map_err(|e| Error::with_cause(ParseError, e)), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - impl NetClsController { /// Constructs a new `NetClsController` with `root` serving as the root of the control group. pub fn new(root: PathBuf) -> Self { diff --git a/src/net_prio.rs b/src/net_prio.rs index d1bbbde6..d2b6c68a 100644 --- a/src/net_prio.rs +++ b/src/net_prio.rs @@ -8,13 +8,13 @@ //! See the Kernel's documentation for more information about this subsystem, found at: //! [Documentation/cgroup-v1/net_prio.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/net_prio.txt) use std::collections::HashMap; -use std::fs::File; -use std::io::{BufRead, BufReader, Read, Write}; +use std::io::{BufRead, BufReader, Write}; use std::path::PathBuf; use crate::error::ErrorKind::*; use crate::error::*; +use crate::read_u64_from; use crate::{ ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, Subsystem, }; @@ -77,17 +77,6 @@ impl<'a> From<&'a Subsystem> for &'a NetPrioController { } } -fn read_u64_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => string - .trim() - .parse() - .map_err(|e| Error::with_cause(ParseError, e)), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - impl NetPrioController { /// Constructs a new `NetPrioController` with `root` serving as the root of the control group. pub fn new(root: PathBuf) -> Self { diff --git a/src/pid.rs b/src/pid.rs index 1955828b..fef84210 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -8,13 +8,13 @@ //! //! See the Kernel's documentation for more information about this subsystem, found at: //! [Documentation/cgroups-v1/pids.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt) -use std::fs::File; use std::io::{Read, Write}; use std::path::PathBuf; use crate::error::ErrorKind::*; use crate::error::*; +use crate::read_u64_from; use crate::{ parse_max_value, ControllIdentifier, ControllerInternal, Controllers, MaxValue, PidResources, Resources, Subsystem, @@ -89,17 +89,6 @@ impl<'a> From<&'a Subsystem> for &'a PidController { } } -fn read_u64_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => string - .trim() - .parse() - .map_err(|e| Error::with_cause(ParseError, e)), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - impl PidController { /// Constructors a new `PidController` instance, with `root` serving as the controller's root /// directory. diff --git a/src/rdma.rs b/src/rdma.rs index 8066c151..1ee1fc87 100644 --- a/src/rdma.rs +++ b/src/rdma.rs @@ -7,13 +7,13 @@ //! //! See the Kernel's documentation for more information about this subsystem, found at: //! [Documentation/cgroup-v1/rdma.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/rdma.txt) -use std::fs::File; -use std::io::{Read, Write}; +use std::io::Write; use std::path::PathBuf; use crate::error::ErrorKind::*; use crate::error::*; +use crate::read_string_from; use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem}; /// A controller that allows controlling the `rdma` subsystem of a Cgroup. @@ -66,14 +66,6 @@ impl<'a> From<&'a Subsystem> for &'a RdmaController { } } -fn read_string_from(mut file: File) -> Result { - let mut string = String::new(); - match file.read_to_string(&mut string) { - Ok(_) => Ok(string.trim().to_string()), - Err(e) => Err(Error::with_cause(ReadFailed, e)), - } -} - impl RdmaController { /// Constructs a new `RdmaController` with `root` serving as the root of the control group. pub fn new(root: PathBuf) -> Self { From f0a695cc003c2193887cee234af67cf661847150 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 6 Jan 2021 22:12:55 +0800 Subject: [PATCH 50/71] Add trait bound Sync for Hierarchy So that the struct Cgroup could across await Signed-off-by: Tim Zhang --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 3d3c68d3..1fcdaade 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -386,7 +386,7 @@ pub trait ControllIdentifier { /// Control group hierarchy (right now, only V1 is supported, but in the future Unified will be /// implemented as well). -pub trait Hierarchy: std::fmt::Debug + Send { +pub trait Hierarchy: std::fmt::Debug + Send + Sync { /// Returns what subsystems are supported by the hierarchy. fn subsystems(&self) -> Vec; From 225388ff7cad12f6c650e7d98e7f0623b9324478 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 6 Jan 2021 22:19:24 +0800 Subject: [PATCH 51/71] release: v0.2.1 Bump version to 0.2.1 Signed-off-by: Tim Zhang --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 14cf747d..f6bdbb33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ repository = "https://github.com/kata-containers/cgroups-rs" keywords = ["linux", "cgroup", "containers", "isolation"] categories = ["os", "api-bindings", "os::unix-apis"] license = "MIT OR Apache-2.0" -version = "0.2.0" +version = "0.2.1" authors = ["The Kata Containers community ", "Levente Kurusa ", "Sam Wilson "] edition = "2018" From 15b65c5e5e998efdf8eb87387c3218e650ffe528 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 25 Jan 2021 11:27:39 +0800 Subject: [PATCH 52/71] Apply customized attributes in MemController.apply Fixes: #25 Signed-off-by: Tim Zhang --- src/memory.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/memory.rs b/src/memory.rs index 8ceb15a2..b8e92a18 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -460,6 +460,10 @@ impl ControllerInternal for MemController { update!(self, set_tcp_limit, memres.kernel_tcp_memory_limit); update!(self, set_swappiness, memres.swappiness); + memres.attrs.iter().for_each(|(k, v)| { + let _ = self.set(k, v); + }); + Ok(()) } } From 853ed46993afeb6cc0c299a08f823665ad7131ee Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 25 Jan 2021 12:14:02 +0800 Subject: [PATCH 53/71] release: v0.2.2 Bump version to 0.2.2 Signed-off-by: Tim Zhang --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f6bdbb33..f7a20bc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ repository = "https://github.com/kata-containers/cgroups-rs" keywords = ["linux", "cgroup", "containers", "isolation"] categories = ["os", "api-bindings", "os::unix-apis"] license = "MIT OR Apache-2.0" -version = "0.2.1" +version = "0.2.2" authors = ["The Kata Containers community ", "Levente Kurusa ", "Sam Wilson "] edition = "2018" From d50245e1167b61208a7511bddf018e9ad9138235 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Mon, 25 Jan 2021 14:51:16 +0800 Subject: [PATCH 54/71] github: add issue templates cgroups-rs should not use the repository default issue templates. Let's add a private version to override the default ones. Fixes: #29 Signed-off-by: Peng Tao --- .github/ISSUE_TEMPLATE/bug_report.md | 17 ++++++++++++++++ .github/ISSUE_TEMPLATE/enhancement-request.md | 20 +++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/enhancement-request.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..8d472dcd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,17 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: 'bug, needs-review' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/enhancement-request.md b/.github/ISSUE_TEMPLATE/enhancement-request.md new file mode 100644 index 00000000..16075976 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement-request.md @@ -0,0 +1,20 @@ +--- +name: Enhancement request +about: Suggest an improvement to an existing feature +title: '' +labels: enhancement, needs-review +assignees: '' + +--- + +**Which feature do you think can be improved?** + +Specify the feature you think could be made better. + +**How can it be improved?** + +Describe how specifically you think it could be improved. + +**Additional Information** + +Anything else to add? diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..a8cea795 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: 'feature, needs-review' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. From 0c58b5dd8420c8e41dc1e98cb4fcb1109db30651 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 25 Jan 2021 16:15:46 +0800 Subject: [PATCH 55/71] Add Makefile So we can use make to build, check and test Signed-off-by: Tim Zhang --- Makefile | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..89fe2a57 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +all: debug fmt test + +# +# Build +# + +.PHONY: debug +debug: + RUSTFLAGS="--deny warnings" cargo build + +.PHONY: release +release: + cargo build --release + +.PHONY: build +build: debug + +# +# Tests and linters +# + +.PHONY: test +test: + cargo test -- --color always --nocapture + +.PHONY: check +check: fmt clippy + + +.PHONY: fmt +fmt: + cargo fmt --all -- --check + +.PHONY: clippy +clippy: + cargo clippy --all-targets --all-features -- -D warnings + From 88a45d4922d26a8979a0294fa047be00a53f0bf0 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 25 Jan 2021 16:17:03 +0800 Subject: [PATCH 56/71] Migrate the CI from travis-ci to Github Actions Because travis-ci.org will be shutting down. Signed-off-by: Tim Zhang --- .github/workflows/bvt.yaml | 26 ++++++++++++++++++++++++++ .travis.yml | 31 ------------------------------- 2 files changed, 26 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/bvt.yaml delete mode 100644 .travis.yml diff --git a/.github/workflows/bvt.yaml b/.github/workflows/bvt.yaml new file mode 100644 index 00000000..9471fc08 --- /dev/null +++ b/.github/workflows/bvt.yaml @@ -0,0 +1,26 @@ +name: BVT +on: [pull_request] +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Build + run: make debug + + fmt: + name: Format Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: rustup component add rustfmt + - run: make fmt + test: + name: Run Unit Test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: make test + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 298cd6aa..00000000 --- a/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2018 Levente Kurusa -# Copyright (c) 2020 Ant Group -# -# SPDX-License-Identifier: Apache-2.0 -# - -dist: bionic -os: linux -language: rust -cache: cargo - -arch: - - amd64 - - arm64 - -install: - - rustup component add rustfmt - -script: - - RUSTFLAGS="--deny warnings" cargo build - - if [ "$TRAVIS_CPU_ARCH" == "amd64" ]; then cargo test -- --color always --nocapture ; fi - - cargo fmt -- --check - -rust: - - 1.44.1 - - nightly - -jobs: - allow_failures: - - rust: nightly - fast_finish: true From 9ac2f5d5ab518c9a178d38bbec8f69cc8c49ccc6 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 25 Jan 2021 14:50:43 +0800 Subject: [PATCH 57/71] Add field homepage and readme for Cargo.toml Display readme on the crate's page. Signed-off-by: Tim Zhang --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index f7a20bc6..e5cf5ced 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,8 @@ license = "MIT OR Apache-2.0" version = "0.2.2" authors = ["The Kata Containers community ", "Levente Kurusa ", "Sam Wilson "] edition = "2018" +homepage = "https://github.com/kata-containers/cgroups-rs" +readme = "README.md" [dependencies] log = "0.4" From cd5645bb14ca73494100f3acf1a31ca0a1648ac1 Mon Sep 17 00:00:00 2001 From: "fupan.lfp" Date: Mon, 25 Jan 2021 16:53:21 +0800 Subject: [PATCH 58/71] cgroup: fix the issue of remove cgroup It should remove the child cgroups recursively and then remove the parent cgroup, otherwise, it would remove failed. Signed-off-by: fupan.lfp --- src/lib.rs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1fcdaade..221d576b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -330,7 +330,7 @@ where return Ok(()); } - fs::remove_dir(self.get_path()).map_err(|e| Error::with_cause(ErrorKind::RemoveFailed, e)) + remove_dir(self.get_path()) } /// Attach a task to this controller. @@ -379,6 +379,30 @@ where } } +// remove_dir aims to remove cgroup path. It does so recursively, +// by removing any subdirectories (sub-cgroups) first. +fn remove_dir(dir: &PathBuf) -> Result<()> { + // try the fast path first. + if fs::remove_dir(dir).is_ok() { + return Ok(()); + } + + if dir.exists() { + if dir.is_dir() { + for entry in fs::read_dir(dir).map_err(|e| Error::with_cause(ReadFailed, e))? { + let entry = entry.map_err(|e| Error::with_cause(ReadFailed, e))?; + let path = entry.path(); + if path.is_dir() { + remove_dir(&path)?; + } + } + fs::remove_dir(dir).map_err(|e| Error::with_cause(RemoveFailed, e))?; + } + } + + Ok(()) +} + #[doc(hidden)] pub trait ControllIdentifier { fn controller_type() -> Controllers; From 81d286f31d7cb49162056405034fe084690e9cc6 Mon Sep 17 00:00:00 2001 From: quanweiZhou Date: Sat, 30 Jan 2021 15:18:48 +0800 Subject: [PATCH 59/71] cgroup: get the mount info without procinfo The procinfo library gets all the mount info, but we don't need all the mount info. Signed-off-by: quanweiZhou --- Cargo.toml | 1 - src/hierarchies.rs | 107 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e5cf5ced..1b398a95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ log = "0.4" regex = "1.1" nix = "0.18.0" libc = "0.2" -procinfo = "0.4.2" [dev-dependencies] libc = "0.2.76" diff --git a/src/hierarchies.rs b/src/hierarchies.rs index fb06cb00..26edf98c 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -9,8 +9,9 @@ //! Currently, we only support the cgroupv1 hierarchy, but in the future we will add support for //! the Unified Hierarchy. -use procinfo::pid::{mountinfo_self, Mountinfo}; use std::fs; +use std::fs::File; +use std::io::{BufRead, BufReader}; use std::path::PathBuf; use crate::blkio::BlkIoController; @@ -31,6 +32,75 @@ use crate::{Controllers, Hierarchy, Subsystem}; use crate::cgroup::Cgroup; +/// Process mounts information. +/// +/// See `proc(5)` for format details. +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct Mountinfo { + /// Mount pathname relative to the process's root. + pub mount_point: PathBuf, + /// Filesystem type (main type with optional sub-type). + pub fs_type: (String, Option), + /// Superblock options. + pub super_opts: Vec, +} + +pub(crate) fn parse_mountinfo_for_line(line: &str) -> Option { + let s_values: Vec<_> = line.split(" - ").collect(); + if s_values.len() != 2 { + return None; + } + + let s0_values: Vec<_> = s_values[0].trim().split(' ').collect(); + let s1_values: Vec<_> = s_values[1].trim().split(' ').collect(); + if s0_values.len() < 6 || s1_values.len() < 3 { + return None; + } + let mount_point = PathBuf::from(s0_values[4]); + let fs_type_values: Vec<_> = s1_values[0].trim().split('.').collect(); + let fs_type = match fs_type_values.len() { + 1 => (fs_type_values[0].to_string(), None), + 2 => ( + fs_type_values[0].to_string(), + Some(fs_type_values[1].to_string()), + ), + _ => return None, + }; + + let super_opts: Vec = s1_values[2].trim().split(',').map(String::from).collect(); + Some(Mountinfo { + mount_point, + fs_type, + super_opts, + }) +} + +/// Parses the provided mountinfo file. +fn mountinfo_file(file: &mut File) -> Vec { + let mut r = Vec::new(); + for line in BufReader::new(file).lines() { + match line { + Ok(line) => { + if let Some(mi) = parse_mountinfo_for_line(&line) { + if mi.fs_type.0 == "cgroup" { + r.push(mi); + } + } + } + Err(_) => continue, + } + } + r +} + +/// Returns mounts information for the current process. +pub fn mountinfo_self() -> Vec { + match File::open("/proc/self/mountinfo") { + Ok(mut file) => mountinfo_file(&mut file), + Err(_) => vec![], + } +} + /// The standard, original cgroup implementation. Often referred to as "cgroupv1". #[derive(Debug)] pub struct V1 { @@ -184,7 +254,7 @@ impl V1 { /// can be created. pub fn new() -> V1 { V1 { - mountinfo: mountinfo_self().unwrap(), + mountinfo: mountinfo_self(), } } @@ -253,3 +323,36 @@ pub fn auto() -> Box { Box::new(V1::new()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_mount() { + let mountinfo = vec![ + ("29 26 0:26 / /sys/fs/cgroup/cpuset,cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,cpuset,cpu,cpuacct", + Mountinfo{mount_point: PathBuf::from("/sys/fs/cgroup/cpuset,cpu,cpuacct"), fs_type: ("cgroup".to_string(), None), super_opts: vec![ + "rw".to_string(), + "cpuset".to_string(), + "cpu".to_string(), + "cpuacct".to_string(), + ]}), + ("121 1731 0:42 / /shm rw,nosuid,nodev,noexec,relatime shared:68 master:66 - tmpfs shm rw,size=65536k", + Mountinfo{mount_point: PathBuf::from("/shm"), fs_type: ("tmpfs".to_string(), None), super_opts: vec![ + "rw".to_string(), + "size=65536k".to_string(), + ]}), + ("121 1731 0:42 / /shm rw,nosuid,nodev,noexec,relatime shared:68 master:66 - tmpfs.123 shm rw,size=65536k", + Mountinfo{mount_point: PathBuf::from("/shm"), fs_type: ("tmpfs".to_string(), Some("123".to_string())), super_opts: vec![ + "rw".to_string(), + "size=65536k".to_string(), + ]}), + ]; + + for mi in mountinfo { + let info = parse_mountinfo_for_line(mi.0).unwrap(); + assert_eq!(info, mi.1) + } + } +} From 79868d6bfc6f3224d1ddcd00455123cd8ff1f2ae Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Tue, 2 Feb 2021 10:24:58 +0800 Subject: [PATCH 60/71] release: v0.2.3 Bump version from 0.2.2 to 0.2.3 Signed-off-by: Tim Zhang --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1b398a95..50e6cb36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ repository = "https://github.com/kata-containers/cgroups-rs" keywords = ["linux", "cgroup", "containers", "isolation"] categories = ["os", "api-bindings", "os::unix-apis"] license = "MIT OR Apache-2.0" -version = "0.2.2" +version = "0.2.3" authors = ["The Kata Containers community ", "Levente Kurusa ", "Sam Wilson "] edition = "2018" homepage = "https://github.com/kata-containers/cgroups-rs" From b9ca0a51f1817c181e809ca12a7ac7448cadddfd Mon Sep 17 00:00:00 2001 From: Jakob Naucke Date: Mon, 22 Feb 2021 14:21:35 +0100 Subject: [PATCH 61/71] Update nix to 0.20.0 to pull in https://github.com/nix-rust/nix/pull/1372 and get statfs MAGIC constants on s390x. Additionally, fork() calls in tests now have to be marked unsafe. Fixes: #37 Signed-off-by: Jakob Naucke --- Cargo.toml | 2 +- tests/pids.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 50e6cb36..50ee8cb6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ readme = "README.md" [dependencies] log = "0.4" regex = "1.1" -nix = "0.18.0" +nix = "0.20.0" libc = "0.2" [dev-dependencies] diff --git a/tests/pids.rs b/tests/pids.rs index cdae8659..94d9ce19 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -62,7 +62,7 @@ fn test_pid_events_is_not_zero() { let before = pids.get_pid_events(); let before = before.unwrap(); - match fork() { + match unsafe { fork() } { Ok(ForkResult::Parent { child, .. }) => { // move the process into the control group let _ = pids.add_task(&(pid_t::from(child) as u64).into()); @@ -89,7 +89,7 @@ fn test_pid_events_is_not_zero() { Ok(ForkResult::Child) => loop { let pids_max = pids.get_pid_max(); if pids_max.is_ok() && pids_max.unwrap() == MaxValue::Value(1) { - if let Err(_) = fork() { + if let Err(_) = unsafe { fork() } { unsafe { libc::exit(0) }; } else { unsafe { libc::exit(1) }; From 8720aed65647186471101751850036298d6842a5 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Thu, 25 Feb 2021 11:00:48 +0800 Subject: [PATCH 62/71] memory: fix panic when no hierarchical numa stat is available For older kernels, it is possible that there is no hierarchical numa stats. Fixes: #36 Signed-off-by: Peng Tao --- src/memory.rs | 182 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 126 insertions(+), 56 deletions(-) diff --git a/src/memory.rs b/src/memory.rs index b8e92a18..95e79427 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -112,10 +112,10 @@ fn parse_numa_stat(s: String) -> Result { let file_line = ls.next().unwrap(); let anon_line = ls.next().unwrap(); let unevict_line = ls.next().unwrap(); - let hier_total_line = ls.next().unwrap(); - let hier_file_line = ls.next().unwrap(); - let hier_anon_line = ls.next().unwrap(); - let hier_unevict_line = ls.next().unwrap(); + let hier_total_line = ls.next().unwrap_or_default(); + let hier_file_line = ls.next().unwrap_or_default(); + let hier_anon_line = ls.next().unwrap_or_default(); + let hier_unevict_line = ls.next().unwrap_or_default(); Ok(NumaStat { total_pages: total_line @@ -178,65 +178,105 @@ fn parse_numa_stat(s: String) -> Result { }) .collect() }, - hierarchical_total_pages: hier_total_line - .split(|x| x == ' ' || x == '=') - .collect::>()[1] - .parse::() - .unwrap_or(0), + hierarchical_total_pages: { + if !hier_total_line.is_empty() { + hier_total_line + .split(|x| x == ' ' || x == '=') + .collect::>()[1] + .parse::() + .unwrap_or(0) + } else { + 0 + } + }, hierarchical_total_pages_per_node: { - let spl = &hier_total_line.split(" ").collect::>()[1..]; - spl.iter() - .map(|x| { - x.split("=").collect::>()[1] - .parse::() - .unwrap_or(0) - }) - .collect() + if !hier_total_line.is_empty() { + let spl = &hier_total_line.split(" ").collect::>()[1..]; + spl.iter() + .map(|x| { + x.split("=").collect::>()[1] + .parse::() + .unwrap_or(0) + }) + .collect() + } else { + Vec::new() + } + }, + hierarchical_file_pages: { + if !hier_file_line.is_empty() { + hier_file_line + .split(|x| x == ' ' || x == '=') + .collect::>()[1] + .parse::() + .unwrap_or(0) + } else { + 0 + } }, - hierarchical_file_pages: hier_file_line - .split(|x| x == ' ' || x == '=') - .collect::>()[1] - .parse::() - .unwrap_or(0), hierarchical_file_pages_per_node: { - let spl = &hier_file_line.split(" ").collect::>()[1..]; - spl.iter() - .map(|x| { - x.split("=").collect::>()[1] - .parse::() - .unwrap_or(0) - }) - .collect() + if !hier_file_line.is_empty() { + let spl = &hier_file_line.split(" ").collect::>()[1..]; + spl.iter() + .map(|x| { + x.split("=").collect::>()[1] + .parse::() + .unwrap_or(0) + }) + .collect() + } else { + Vec::new() + } + }, + hierarchical_anon_pages: { + if !hier_anon_line.is_empty() { + hier_anon_line + .split(|x| x == ' ' || x == '=') + .collect::>()[1] + .parse::() + .unwrap_or(0) + } else { + 0 + } }, - hierarchical_anon_pages: hier_anon_line - .split(|x| x == ' ' || x == '=') - .collect::>()[1] - .parse::() - .unwrap_or(0), hierarchical_anon_pages_per_node: { - let spl = &hier_anon_line.split(" ").collect::>()[1..]; - spl.iter() - .map(|x| { - x.split("=").collect::>()[1] - .parse::() - .unwrap_or(0) - }) - .collect() + if !hier_anon_line.is_empty() { + let spl = &hier_anon_line.split(" ").collect::>()[1..]; + spl.iter() + .map(|x| { + x.split("=").collect::>()[1] + .parse::() + .unwrap_or(0) + }) + .collect() + } else { + Vec::new() + } + }, + hierarchical_unevictable_pages: { + if !hier_unevict_line.is_empty() { + hier_unevict_line + .split(|x| x == ' ' || x == '=') + .collect::>()[1] + .parse::() + .unwrap_or(0) + } else { + 0 + } }, - hierarchical_unevictable_pages: hier_unevict_line - .split(|x| x == ' ' || x == '=') - .collect::>()[1] - .parse::() - .unwrap_or(0), hierarchical_unevictable_pages_per_node: { - let spl = &hier_unevict_line.split(" ").collect::>()[1..]; - spl.iter() - .map(|x| { - x.split("=").collect::>()[1] - .parse::() - .unwrap_or(0) - }) - .collect() + if !hier_unevict_line.is_empty() { + let spl = &hier_unevict_line.split(" ").collect::>()[1..]; + spl.iter() + .map(|x| { + x.split("=").collect::>()[1] + .parse::() + .unwrap_or(0) + }) + .collect() + } else { + Vec::new() + } }, }) } @@ -887,6 +927,13 @@ hierarchical_total=1628573 N0=1628573 N1=123 hierarchical_file=858151 N0=858151 N1=123 hierarchical_anon=770402 N0=770402 N1=123 hierarchical_unevictable=20 N0=20 N1=123 +"; + + static GOOD_VALUE_NON_HIERARCHICAL: &str = "\ +total=51189 N0=51189 N1=123 +file=50175 N0=50175 N1=123 +anon=1014 N0=1014 N1=123 +unevictable=0 N0=0 N1=123 "; static GOOD_OOMCONTROL_VAL: &str = "\ @@ -959,6 +1006,29 @@ total_unevictable 81920 hierarchical_unevictable_pages_per_node: vec![20, 123], } ); + let ok = parse_numa_stat(GOOD_VALUE_NON_HIERARCHICAL.to_string()).unwrap(); + assert_eq!( + ok, + NumaStat { + total_pages: 51189, + total_pages_per_node: vec![51189, 123], + file_pages: 50175, + file_pages_per_node: vec![50175, 123], + anon_pages: 1014, + anon_pages_per_node: vec![1014, 123], + unevictable_pages: 0, + unevictable_pages_per_node: vec![0, 123], + + hierarchical_total_pages: 0, + hierarchical_total_pages_per_node: vec![], + hierarchical_file_pages: 0, + hierarchical_file_pages_per_node: vec![], + hierarchical_anon_pages: 0, + hierarchical_anon_pages_per_node: vec![], + hierarchical_unevictable_pages: 0, + hierarchical_unevictable_pages_per_node: vec![], + } + ); } #[test] From 60820bfffbcf95436d257141bdaef8a68b5ecf63 Mon Sep 17 00:00:00 2001 From: Jakob Naucke Date: Thu, 25 Feb 2021 11:22:47 +0100 Subject: [PATCH 63/71] release: v0.2.4 Bump version from 0.2.3 to 0.2.4 Signed-off-by: Jakob Naucke --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 50ee8cb6..e56b412e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ repository = "https://github.com/kata-containers/cgroups-rs" keywords = ["linux", "cgroup", "containers", "isolation"] categories = ["os", "api-bindings", "os::unix-apis"] license = "MIT OR Apache-2.0" -version = "0.2.3" +version = "0.2.4" authors = ["The Kata Containers community ", "Levente Kurusa ", "Sam Wilson "] edition = "2018" homepage = "https://github.com/kata-containers/cgroups-rs" From 0a3e4a828f87c6275c3f74238799f134afc63dfd Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Fri, 26 Feb 2021 01:38:54 +0800 Subject: [PATCH 64/71] memory: fix parse_oom_control panic on older kernels Where the oom control fields might not be present. Fixes: #36 Signed-off-by: Peng Tao --- src/memory.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/src/memory.rs b/src/memory.rs index 95e79427..037e9c38 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -59,10 +59,28 @@ pub struct OomControl { fn parse_oom_control(s: String) -> Result { let spl = s.split_whitespace().collect::>(); + let oom_kill_disable = if spl.len() > 1 { + spl[1].parse::().unwrap() == 1 + } else { + false + }; + + let under_oom = if spl.len() > 3 { + spl[3].parse::().unwrap() == 1 + } else { + false + }; + + let oom_kill = if spl.len() > 5 { + spl[5].parse::().unwrap() + } else { + 0 + }; + Ok(OomControl { - oom_kill_disable: spl[1].parse::().unwrap() == 1, - under_oom: spl[3].parse::().unwrap() == 1, - oom_kill: spl[5].parse::().unwrap(), + oom_kill_disable, + under_oom, + oom_kill, }) } @@ -918,6 +936,7 @@ mod tests { use crate::memory::{ parse_memory_stat, parse_numa_stat, parse_oom_control, MemoryStat, NumaStat, OomControl, }; + static GOOD_VALUE: &str = "\ total=51189 N0=51189 N1=123 file=50175 N0=50175 N1=123 @@ -936,7 +955,17 @@ anon=1014 N0=1014 N1=123 unevictable=0 N0=0 N1=123 "; - static GOOD_OOMCONTROL_VAL: &str = "\ + static GOOD_OOMCONTROL_VAL_1: &str = "\ +oom_kill_disable 0 +oom_kill 1337 +"; + + static GOOD_OOMCONTROL_VAL_2: &str = "\ +oom_kill_disable 0 +under_oom 1 +"; + + static GOOD_OOMCONTROL_VAL_3: &str = "\ oom_kill_disable 0 under_oom 1 oom_kill 1337 @@ -1033,7 +1062,34 @@ total_unevictable 81920 #[test] fn test_parse_oom_control() { - let ok = parse_oom_control(GOOD_OOMCONTROL_VAL.to_string()).unwrap(); + let ok = parse_oom_control("".to_string()).unwrap(); + assert_eq!( + ok, + OomControl { + oom_kill_disable: false, + under_oom: false, + oom_kill: 0, + } + ); + let ok = parse_oom_control(GOOD_OOMCONTROL_VAL_1.to_string()).unwrap(); + assert_eq!( + ok, + OomControl { + oom_kill_disable: false, + under_oom: false, + oom_kill: 0, + } + ); + let ok = parse_oom_control(GOOD_OOMCONTROL_VAL_2.to_string()).unwrap(); + assert_eq!( + ok, + OomControl { + oom_kill_disable: false, + under_oom: true, + oom_kill: 0, + } + ); + let ok = parse_oom_control(GOOD_OOMCONTROL_VAL_3.to_string()).unwrap(); assert_eq!( ok, OomControl { From 9ec1010a15e37b007dfe00a48db11c1f4d4e1e9c Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Mon, 25 Jan 2021 17:15:55 +0800 Subject: [PATCH 65/71] Fix clippy warnings Fix clippy warnings. Signed-off-by: Tim Zhang --- src/blkio.rs | 133 +++++++++++++++--------------- src/cgroup.rs | 45 +++++----- src/cpu.rs | 9 +- src/cpuacct.rs | 26 +++--- src/cpuset.rs | 24 +++--- src/devices.rs | 19 +++-- src/events.rs | 9 +- src/freezer.rs | 2 +- src/hierarchies.rs | 16 +++- src/hugetlb.rs | 22 ++--- src/lib.rs | 201 ++++++++++++++++++++------------------------- src/memory.rs | 59 ++++++------- src/net_cls.rs | 4 +- src/net_prio.rs | 2 + src/pid.rs | 2 +- src/systemd.rs | 2 +- tests/cgroup.rs | 2 +- tests/cpuset.rs | 11 ++- tests/devices.rs | 4 +- tests/pids.rs | 2 +- 20 files changed, 288 insertions(+), 306 deletions(-) diff --git a/src/blkio.rs b/src/blkio.rs index 457dceb4..a399697c 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -84,14 +84,14 @@ pub struct IoStat { fn parse_io_service(s: String) -> Result> { s.lines() - .filter(|x| x.split_whitespace().collect::>().len() == 3) + .filter(|x| x.split_whitespace().count() == 3) .map(|x| { let mut spl = x.split_whitespace(); - (spl.nth(0).unwrap(), spl.nth(0).unwrap(), spl.nth(0).unwrap()) + (spl.next().unwrap(), spl.next().unwrap(), spl.next().unwrap()) }) .map(|(a, b, c)| { - let mut spl = a.split(":"); - (spl.nth(0).unwrap(), spl.nth(0).unwrap(), b, c) + let mut spl = a.split(':'); + (spl.next().unwrap(), spl.next().unwrap(), b, c) }) .collect::>() .chunks(5) @@ -131,15 +131,14 @@ fn get_value(s: &str) -> String { arr[1].to_string() } -fn parse_io_stat(s: String) -> Result> { +fn parse_io_stat(s: String) -> Vec { // line: // 8:0 rbytes=180224 wbytes=0 rios=3 wios=0 dbytes=0 dios=0 - let v = s - .lines() - .filter(|x| x.split_whitespace().collect::>().len() == 7) + s.lines() + .filter(|x| x.split_whitespace().count() == 7) .map(|x| { let arr = x.split_whitespace().collect::>(); - let device = arr[0].split(":").collect::>(); + let device = arr[0].split(':').collect::>(); let (major, minor) = (device[0], device[1]); IoStat { @@ -153,14 +152,12 @@ fn parse_io_stat(s: String) -> Result> { dios: get_value(arr[6]).parse::().unwrap(), } }) - .collect::>(); - - Ok(v) + .collect::>() } fn parse_io_service_total(s: String) -> Result { s.lines() - .filter(|x| x.split_whitespace().collect::>().len() == 2) + .filter(|x| x.split_whitespace().count() == 2) .fold(Err(Error::new(ParseError)), |_, x| { match x.split_whitespace().collect::>().as_slice() { ["Total", val] => val.parse::().map_err(|_| Error::new(ParseError)), @@ -197,9 +194,9 @@ fn parse_blkio_data(s: String) -> Result> { }); if err.is_err() { - return Err(Error::new(ParseError)); + Err(Error::new(ParseError)) } else { - return Ok(res); + Ok(res) } } @@ -407,19 +404,19 @@ impl BlkIoController { Self { base: root.clone(), path: root, - v2: v2, + v2, } } fn blkio_v2(&self) -> BlkIo { - let mut blkio: BlkIo = Default::default(); - blkio.io_stat = self - .open_path("io.stat", false) - .and_then(read_string_from) - .and_then(parse_io_stat) - .unwrap_or(Vec::new()); - - blkio + BlkIo { + io_stat: self + .open_path("io.stat", false) + .and_then(read_string_from) + .map(parse_io_stat) + .unwrap_or_default(), + ..Default::default() + } } /// Gathers statistics about and reports the state of the block devices used by the control @@ -433,222 +430,222 @@ impl BlkIoController { .open_path("blkio.io_merged", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_merged_total: self .open_path("blkio.io_merged", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_merged_recursive: self .open_path("blkio.io_merged_recursive", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_merged_recursive_total: self .open_path("blkio.io_merged_recursive", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_queued: self .open_path("blkio.io_queued", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_queued_total: self .open_path("blkio.io_queued", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_queued_recursive: self .open_path("blkio.io_queued_recursive", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_queued_recursive_total: self .open_path("blkio.io_queued_recursive", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_service_bytes: self .open_path("blkio.io_service_bytes", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_service_bytes_total: self .open_path("blkio.io_service_bytes", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_service_bytes_recursive: self .open_path("blkio.io_service_bytes_recursive", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_service_bytes_recursive_total: self .open_path("blkio.io_service_bytes_recursive", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_serviced: self .open_path("blkio.io_serviced", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_serviced_total: self .open_path("blkio.io_serviced", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_serviced_recursive: self .open_path("blkio.io_serviced_recursive", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_serviced_recursive_total: self .open_path("blkio.io_serviced_recursive", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_service_time: self .open_path("blkio.io_service_time", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_service_time_total: self .open_path("blkio.io_service_time", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_service_time_recursive: self .open_path("blkio.io_service_time_recursive", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_service_time_recursive_total: self .open_path("blkio.io_service_time_recursive", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_wait_time: self .open_path("blkio.io_wait_time", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_wait_time_total: self .open_path("blkio.io_wait_time", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_wait_time_recursive: self .open_path("blkio.io_wait_time_recursive", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_wait_time_recursive_total: self .open_path("blkio.io_wait_time_recursive", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), leaf_weight: self .open_path("blkio.leaf_weight", false) - .and_then(|file| read_u64_from(file)) + .and_then(read_u64_from) .unwrap_or(0u64), leaf_weight_device: self .open_path("blkio.leaf_weight_device", false) .and_then(read_string_from) .and_then(parse_blkio_data) - .unwrap_or(Vec::new()), + .unwrap_or_default(), sectors: self .open_path("blkio.sectors", false) .and_then(read_string_from) .and_then(parse_blkio_data) - .unwrap_or(Vec::new()), + .unwrap_or_default(), sectors_recursive: self .open_path("blkio.sectors_recursive", false) .and_then(read_string_from) .and_then(parse_blkio_data) - .unwrap_or(Vec::new()), + .unwrap_or_default(), throttle: BlkIoThrottle { io_service_bytes: self .open_path("blkio.throttle.io_service_bytes", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_service_bytes_total: self .open_path("blkio.throttle.io_service_bytes", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_service_bytes_recursive: self .open_path("blkio.throttle.io_service_bytes_recursive", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_service_bytes_recursive_total: self .open_path("blkio.throttle.io_service_bytes_recursive", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_serviced: self .open_path("blkio.throttle.io_serviced", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_serviced_total: self .open_path("blkio.throttle.io_serviced", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), io_serviced_recursive: self .open_path("blkio.throttle.io_serviced_recursive", false) .and_then(read_string_from) .and_then(parse_io_service) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_serviced_recursive_total: self .open_path("blkio.throttle.io_serviced_recursive", false) .and_then(read_string_from) .and_then(parse_io_service_total) - .unwrap_or(0), + .unwrap_or_default(), read_bps_device: self .open_path("blkio.throttle.read_bps_device", false) .and_then(read_string_from) .and_then(parse_blkio_data) - .unwrap_or(Vec::new()), + .unwrap_or_default(), read_iops_device: self .open_path("blkio.throttle.read_iops_device", false) .and_then(read_string_from) .and_then(parse_blkio_data) - .unwrap_or(Vec::new()), + .unwrap_or_default(), write_bps_device: self .open_path("blkio.throttle.write_bps_device", false) .and_then(read_string_from) .and_then(parse_blkio_data) - .unwrap_or(Vec::new()), + .unwrap_or_default(), write_iops_device: self .open_path("blkio.throttle.write_iops_device", false) .and_then(read_string_from) .and_then(parse_blkio_data) - .unwrap_or(Vec::new()), + .unwrap_or_default(), }, time: self .open_path("blkio.time", false) .and_then(read_string_from) .and_then(parse_blkio_data) - .unwrap_or(Vec::new()), + .unwrap_or_default(), time_recursive: self .open_path("blkio.time_recursive", false) .and_then(read_string_from) .and_then(parse_blkio_data) - .unwrap_or(Vec::new()), + .unwrap_or_default(), weight: self .open_path("blkio.weight", false) - .and_then(|file| read_u64_from(file)) + .and_then(read_u64_from) .unwrap_or(0u64), weight_device: self .open_path("blkio.weight_device", false) .and_then(read_string_from) .and_then(parse_blkio_data) - .unwrap_or(Vec::new()), + .unwrap_or_default(), io_stat: Vec::new(), } } diff --git a/src/cgroup.rs b/src/cgroup.rs index 5dedab5c..4dda0c08 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -62,7 +62,7 @@ impl Cgroup { /// Create this control group. fn create(&self) { if self.hier.v2() { - let _ret = create_v2_cgroup(self.hier.root().clone(), &self.path); + let _ret = create_v2_cgroup(self.hier.root(), &self.path); } else { for subsystem in &self.subsystems { subsystem.to_controller().create(); @@ -112,13 +112,11 @@ impl Cgroup { .collect::>(); } - let cg = Cgroup { + Cgroup { path: path.to_str().unwrap().to_string(), - subsystems: subsystems, + subsystems, hier, - }; - - cg + } } /// Create a handle for a control group in the hierarchy `hier`, with name `path` and `relative_paths` @@ -146,7 +144,7 @@ impl Cgroup { let cn = x.controller_name(); if relative_paths.contains_key(&cn) { let rp = relative_paths.get(&cn).unwrap(); - let valid_path = rp.trim_start_matches("/").to_string(); + let valid_path = rp.trim_start_matches('/').to_string(); let mut p = PathBuf::from(valid_path); p.push(path); x.enter(p.as_ref()) @@ -157,13 +155,11 @@ impl Cgroup { .collect::>(); } - let cg = Cgroup { - subsystems: subsystems, + Cgroup { + subsystems, hier, path: path.to_str().unwrap().to_string(), - }; - - cg + } } /// The list of subsystems that this control group supports. @@ -179,8 +175,8 @@ impl Cgroup { /// will change. pub fn delete(&self) -> Result<()> { if self.v2() { - if self.path != "" { - let mut p = self.hier.root().clone(); + if !self.path.is_empty() { + let mut p = self.hier.root(); p.push(self.path.clone()); return fs::remove_dir(p).map_err(|e| Error::with_cause(RemoveFailed, e)); } @@ -222,7 +218,7 @@ impl Cgroup { /// let cpu: &CpuController = control_group.controller_of() /// .expect("No cpu controller attached!"); /// ``` - pub fn controller_of<'a, T>(self: &'a Self) -> Option<&'a T> + pub fn controller_of<'a, T>(&'a self) -> Option<&'a T> where &'a T: From<&'a Subsystem>, T: Controller + ControllIdentifier, @@ -249,7 +245,7 @@ impl Cgroup { pub fn add_task(&self, pid: CgroupPid) -> Result<()> { if self.v2() { let subsystems = self.subsystems(); - if subsystems.len() > 0 { + if !subsystems.is_empty() { let c = subsystems[0].to_controller(); c.add_task(&pid) } else { @@ -291,7 +287,7 @@ impl Cgroup { // Collect the tasks from all subsystems let mut v = if self.v2() { let subsystems = self.subsystems(); - if subsystems.len() > 0 { + if !subsystems.is_empty() { let c = subsystems[0].to_controller(); c.tasks() } else { @@ -313,9 +309,9 @@ impl Cgroup { } } -pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; +pub const UNIFIED_MOUNTPOINT: &str = "/sys/fs/cgroup"; -fn enable_controllers(controllers: &Vec, path: &PathBuf) { +fn enable_controllers(controllers: &[String], path: &PathBuf) { let mut f = path.clone(); f.push("cgroup.subtree_control"); for c in controllers { @@ -327,8 +323,8 @@ fn enable_controllers(controllers: &Vec, path: &PathBuf) { fn supported_controllers() -> Vec { let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers"); let ret = fs::read_to_string(p.as_str()); - ret.unwrap_or(String::new()) - .split(" ") + ret.unwrap_or_default() + .split(' ') .map(|x| x.to_string()) .collect::>() } @@ -342,16 +338,15 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { enable_controllers(&controllers, &fp); // path: "a/b/c" - let elements = path.split("/").collect::>(); + let elements = path.split('/').collect::>(); let last_index = elements.len() - 1; for (i, ele) in elements.iter().enumerate() { // ROOT/a fp.push(ele); // create dir, need not check if is a file or directory if !fp.exists() { - match ::std::fs::create_dir(fp.clone()) { - Err(e) => return Err(Error::with_cause(ErrorKind::FsError, e)), - Ok(_) => {} + if let Err(e) = std::fs::create_dir(fp.clone()) { + return Err(Error::with_cause(ErrorKind::FsError, e)); } } diff --git a/src/cpu.rs b/src/cpu.rs index 6293e3c9..baaedadd 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -116,7 +116,7 @@ impl CpuController { Self { base: root.clone(), path: root, - v2: v2, + v2, } } @@ -133,7 +133,7 @@ impl CpuController { Err(e) => Err(Error::with_cause(ReadFailed, e)), } }) - .unwrap_or("".to_string()), + .unwrap_or_default(), } } @@ -299,8 +299,5 @@ fn parse_cfs_quota_and_period(mut file: File) -> Result { .parse::() .map_err(|e| Error::with_cause(ParseError, e))?; - Ok(CFSQuotaAndPeriod { - quota: quota, - period: period, - }) + Ok(CFSQuotaAndPeriod { quota, period }) } diff --git a/src/cpuacct.rs b/src/cpuacct.rs index 57eafbd6..7928e45a 100644 --- a/src/cpuacct.rs +++ b/src/cpuacct.rs @@ -111,35 +111,35 @@ impl CpuAcctController { CpuAcct { stat: self .open_path("cpuacct.stat", false) - .and_then(|file| read_string_from(file)) - .unwrap_or("".to_string()), + .and_then(read_string_from) + .unwrap_or_default(), usage: self .open_path("cpuacct.usage", false) - .and_then(|file| read_u64_from(file)) + .and_then(read_u64_from) .unwrap_or(0), usage_all: self .open_path("cpuacct.usage_all", false) - .and_then(|file| read_string_from(file)) - .unwrap_or("".to_string()), + .and_then(read_string_from) + .unwrap_or_default(), usage_percpu: self .open_path("cpuacct.usage_percpu", false) - .and_then(|file| read_string_from(file)) - .unwrap_or("".to_string()), + .and_then(read_string_from) + .unwrap_or_default(), usage_percpu_sys: self .open_path("cpuacct.usage_percpu_sys", false) - .and_then(|file| read_string_from(file)) - .unwrap_or("".to_string()), + .and_then(read_string_from) + .unwrap_or_default(), usage_percpu_user: self .open_path("cpuacct.usage_percpu_user", false) - .and_then(|file| read_string_from(file)) - .unwrap_or("".to_string()), + .and_then(read_string_from) + .unwrap_or_default(), usage_sys: self .open_path("cpuacct.usage_sys", false) - .and_then(|file| read_u64_from(file)) + .and_then(read_u64_from) .unwrap_or(0), usage_user: self .open_path("cpuacct.usage_user", false) - .and_then(|file| read_u64_from(file)) + .and_then(read_u64_from) .unwrap_or(0), } } diff --git a/src/cpuset.rs b/src/cpuset.rs index 957ed7a5..4bc5b57c 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -146,7 +146,7 @@ fn find_no_empty_parent(from: &str, file: &str) -> Result<(String, Vec) Err(e) => return Err(Error::with_cause(ReadFailed, e)), }; - if current_value != "" { + if !current_value.is_empty() { return Ok((current_value, v)); } v.push(current_path.clone()); @@ -167,7 +167,7 @@ fn copy_from_parent(current: &str, file: &str) -> Result<()> { // find not empty cpus/memes from current directory. let (value, parents) = find_no_empty_parent(current, file)?; - if value == "" || parents.len() == 0 { + if value.is_empty() || parents.is_empty() { return Ok(()); } @@ -208,17 +208,17 @@ impl<'a> From<&'a Subsystem> for &'a CpuSetController { fn parse_range(s: String) -> Result> { let mut fin = Vec::new(); - if s == "".to_string() { + if s.is_empty() { return Ok(fin); } // first split by commas - let comma_split = s.split(","); + let comma_split = s.split(','); for sp in comma_split { - if sp.contains("-") { + if sp.contains('-') { // this is a true range - let dash_split = sp.split("-").collect::>(); + let dash_split = sp.split('-').collect::>(); if dash_split.len() != 2 { return Err(Error::new(ParseError)); } @@ -247,7 +247,7 @@ impl CpuSetController { Self { base: root.clone(), path: root, - v2: v2, + v2, } } @@ -257,7 +257,7 @@ impl CpuSetController { CpuSet { cpu_exclusive: { self.open_path("cpuset.cpu_exclusive", false) - .and_then(|file| read_u64_from(file)) + .and_then(read_u64_from) .map(|x| x == 1) .unwrap_or(false) }, @@ -265,19 +265,19 @@ impl CpuSetController { self.open_path("cpuset.cpus", false) .and_then(read_string_from) .and_then(parse_range) - .unwrap_or(Vec::new()) + .unwrap_or_default() }, effective_cpus: { self.open_path("cpuset.effective_cpus", false) .and_then(read_string_from) .and_then(parse_range) - .unwrap_or(Vec::new()) + .unwrap_or_default() }, effective_mems: { self.open_path("cpuset.effective_mems", false) .and_then(read_string_from) .and_then(parse_range) - .unwrap_or(Vec::new()) + .unwrap_or_default() }, mem_exclusive: { self.open_path("cpuset.mem_exclusive", false) @@ -324,7 +324,7 @@ impl CpuSetController { self.open_path("cpuset.mems", false) .and_then(read_string_from) .and_then(parse_range) - .unwrap_or(Vec::new()) + .unwrap_or_default() }, sched_load_balance: { self.open_path("cpuset.sched_load_balance", false) diff --git a/src/devices.rs b/src/devices.rs index 838d17e5..1cd1ea8b 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -102,7 +102,7 @@ impl DevicePermissions { /// Checks whether the string is a valid descriptor of DevicePermissions. pub fn is_valid(s: &str) -> bool { - if s == "" { + if s.is_empty() { return false; } for i in s.chars() { @@ -110,7 +110,7 @@ impl DevicePermissions { return false; } } - return true; + true } /// Returns a Vec will all the permissions that a device can have. @@ -123,9 +123,10 @@ impl DevicePermissions { } /// Convert a string into DevicePermissions. + #[allow(clippy::should_implement_trait)] pub fn from_str(s: &str) -> Result> { let mut v = Vec::new(); - if s == "" { + if s.is_empty() { return Ok(v); } for e in s.chars() { @@ -206,7 +207,7 @@ impl DevicesController { devtype: DeviceType, major: i64, minor: i64, - perm: &Vec, + perm: &[DevicePermissions], ) -> Result<()> { let perms = perm .iter() @@ -238,7 +239,7 @@ impl DevicesController { devtype: DeviceType, major: i64, minor: i64, - perm: &Vec, + perm: &[DevicePermissions], ) -> Result<()> { let perms = perm .iter() @@ -274,13 +275,13 @@ impl DevicesController { error!("allowed_devices: acc: {:?}, ls: {:?}", acc, ls); Err(Error::new(ParseError)) } else { - let devtype = DeviceType::from_char(ls[0].chars().nth(0)); + let devtype = DeviceType::from_char(ls[0].chars().next()); let mut major = ls[1].parse::(); let mut minor = ls[2].parse::(); - if major.is_err() && ls[1] == "*".to_string() { + if major.is_err() && ls[1] == "*" { major = Ok(-1); } - if minor.is_err() && ls[2] == "*".to_string() { + if minor.is_err() && ls[2] == "*" { minor = Ok(-1); } if devtype.is_none() || major.is_err() || minor.is_err() || !DevicePermissions::is_valid(&ls[3]) { @@ -295,7 +296,7 @@ impl DevicesController { devtype: devtype.unwrap(), major: major.unwrap(), minor: minor.unwrap(), - access: access, + access, }); Ok(acc) } diff --git a/src/events.rs b/src/events.rs index b06f3c03..86f8f755 100644 --- a/src/events.rs +++ b/src/events.rs @@ -53,7 +53,7 @@ fn register_memory_event( let event_control_path = cg_dir.join("cgroup.event_control"); let data; - if arg == "" { + if arg.is_empty() { data = format!("{} {}", eventfd, event_file.as_raw_fd()); } else { data = format!("{} {} {}", eventfd, event_file.as_raw_fd(), arg); @@ -70,11 +70,8 @@ fn register_memory_event( thread::spawn(move || { loop { let mut buf = [0; 8]; - match eventfd_file.read(&mut buf) { - Err(_err) => { - return; - } - Ok(_) => {} + if eventfd_file.read(&mut buf).is_err() { + return; } // When a cgroup is destroyed, an event is sent to eventfd. diff --git a/src/freezer.rs b/src/freezer.rs index 93a01854..7f0fc1c9 100644 --- a/src/freezer.rs +++ b/src/freezer.rs @@ -87,7 +87,7 @@ impl FreezerController { Self { base: root.clone(), path: root, - v2: v2, + v2, } } diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 26edf98c..9a5d8df7 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -268,6 +268,12 @@ impl V1 { } } +impl Default for V1 { + fn default() -> Self { + Self::new() + } +} + impl V2 { /// Finds where control groups are mounted to and returns a hierarchy in which control groups /// can be created. @@ -278,7 +284,13 @@ impl V2 { } } -pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; +impl Default for V2 { + fn default() -> Self { + Self::new() + } +} + +pub const UNIFIED_MOUNTPOINT: &str = "/sys/fs/cgroup"; #[cfg(all(target_os = "linux", not(target_env = "musl")))] pub fn is_cgroup2_unified_mode() -> bool { @@ -294,7 +306,7 @@ pub fn is_cgroup2_unified_mode() -> bool { fs_stat.unwrap().filesystem_type() == statfs::CGROUP2_SUPER_MAGIC } -pub const INIT_CGROUP_PATHS: &'static str = "/proc/1/cgroup"; +pub const INIT_CGROUP_PATHS: &str = "/proc/1/cgroup"; #[cfg(all(target_os = "linux", target_env = "musl"))] pub fn is_cgroup2_unified_mode() -> bool { diff --git a/src/hugetlb.rs b/src/hugetlb.rs index ed8d83d9..b6888790 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -92,8 +92,8 @@ impl HugeTlbController { Self { base: root.clone(), path: root, - sizes: sizes, - v2: v2, + sizes, + v2, } } @@ -115,7 +115,7 @@ impl HugeTlbController { self.open_path(&format!("hugetlb.{}.events", hugetlb_size), false) .and_then(flat_keyed_to_vec) .and_then(|x| { - if x.len() == 0 { + if x.is_empty() { return Err(Error::from_string(format!( "get empty from hugetlb.{}.events", hugetlb_size @@ -175,7 +175,7 @@ impl HugeTlbController { } } -pub const HUGEPAGESIZE_DIR: &'static str = "/sys/kernel/mm/hugepages"; +pub const HUGEPAGESIZE_DIR: &str = "/sys/kernel/mm/hugepages"; use regex::Regex; use std::collections::HashMap; use std::fs; @@ -264,8 +264,8 @@ fn parse_size(s: &str, m: &HashMap) -> Result { let caps = re.unwrap().captures(s).unwrap(); let num = caps.name("num"); - let size: u128 = if num.is_some() { - let n = num.unwrap().as_str().trim().parse::(); + let size: u128 = if let Some(num) = num { + let n = num.as_str().trim().parse::(); if n.is_err() { return Err(Error::new(InvalidBytesSize)); } @@ -275,10 +275,10 @@ fn parse_size(s: &str, m: &HashMap) -> Result { }; let q = caps.name("mul"); - let mul: u128 = if q.is_some() { - let t = m.get(q.unwrap().as_str()); - if t.is_some() { - *t.unwrap() + let mul: u128 = if let Some(q) = q { + let t = m.get(q.as_str()); + if let Some(t) = t { + *t } else { return Err(Error::new(InvalidBytesSize)); } @@ -289,7 +289,7 @@ fn parse_size(s: &str, m: &HashMap) -> Result { Ok(size * mul) } -fn custom_size(mut size: f64, base: f64, m: &Vec) -> String { +fn custom_size(mut size: f64, base: f64, m: &[String]) -> String { let mut i = 0; while size >= base && i < m.len() - 1 { size /= base; diff --git a/src/lib.rs b/src/lib.rs index 221d576b..52e63be6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,9 +4,11 @@ // SPDX-License-Identifier: Apache-2.0 or MIT // +#![allow(clippy::unnecessary_unwrap)] use log::*; use std::collections::HashMap; +use std::fmt; use std::fs::{self, File}; use std::io::{BufRead, BufReader, Read, Write}; use std::path::{Path, PathBuf}; @@ -123,23 +125,23 @@ pub enum Controllers { Systemd, } -impl Controllers { - pub fn to_string(&self) -> String { +impl fmt::Display for Controllers { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Controllers::Pids => return "pids".to_string(), - Controllers::Mem => return "memory".to_string(), - Controllers::CpuSet => return "cpuset".to_string(), - Controllers::CpuAcct => return "cpuacct".to_string(), - Controllers::Cpu => return "cpu".to_string(), - Controllers::Devices => return "devices".to_string(), - Controllers::Freezer => return "freezer".to_string(), - Controllers::NetCls => return "net_cls".to_string(), - Controllers::BlkIo => return "blkio".to_string(), - Controllers::PerfEvent => return "perf_event".to_string(), - Controllers::NetPrio => return "net_prio".to_string(), - Controllers::HugeTlb => return "hugetlb".to_string(), - Controllers::Rdma => return "rdma".to_string(), - Controllers::Systemd => return "name=systemd".to_string(), + Controllers::Pids => write!(f, "pids"), + Controllers::Mem => write!(f, "memory"), + Controllers::CpuSet => write!(f, "cpuset"), + Controllers::CpuAcct => write!(f, "cpuacct"), + Controllers::Cpu => write!(f, "cpu"), + Controllers::Devices => write!(f, "devices"), + Controllers::Freezer => write!(f, "freezer"), + Controllers::NetCls => write!(f, "net_cls"), + Controllers::BlkIo => write!(f, "blkio"), + Controllers::PerfEvent => write!(f, "perf_event"), + Controllers::NetPrio => write!(f, "net_prio"), + Controllers::HugeTlb => write!(f, "hugetlb"), + Controllers::Rdma => write!(f, "rdma"), + Controllers::Systemd => write!(f, "name=systemd"), } } } @@ -179,13 +181,13 @@ mod sealed { if w { match File::create(&path) { - Err(e) => return Err(Error::with_cause(ErrorKind::WriteFailed, e)), - Ok(file) => return Ok(file), + Err(e) => Err(Error::with_cause(ErrorKind::WriteFailed, e)), + Ok(file) => Ok(file), } } else { match File::open(&path) { - Err(e) => return Err(Error::with_cause(ErrorKind::ReadFailed, e)), - Ok(file) => return Ok(file), + Err(e) => Err(Error::with_cause(ErrorKind::ReadFailed, e)), + Ok(file) => Ok(file), } } } @@ -203,7 +205,7 @@ mod sealed { #[doc(hidden)] fn path_exists(&self, p: &str) -> bool { - if let Err(_) = self.verify_path() { + if self.verify_path().is_err() { return false; } @@ -295,7 +297,7 @@ where /// Create this controller fn create(&self) { self.verify_path() - .expect(format!("path should be valid: {:?}", self.path()).as_str()); + .unwrap_or_else(|_| panic!("path should be valid: {:?}", self.path())); match ::std::fs::create_dir_all(self.get_path()) { Ok(_) => self.post_create(), @@ -360,7 +362,7 @@ where file = "cgroup.procs"; } self.open_path(file, false) - .and_then(|file| { + .map(|file| { let bf = BufReader::new(file); let mut v = Vec::new(); for line in bf.lines() { @@ -369,9 +371,9 @@ where v.push(n); } } - Ok(v.into_iter().map(CgroupPid::from).collect()) + v.into_iter().map(CgroupPid::from).collect() }) - .unwrap_or(vec![]) + .unwrap_or_default() } fn v2(&self) -> bool { @@ -387,17 +389,15 @@ fn remove_dir(dir: &PathBuf) -> Result<()> { return Ok(()); } - if dir.exists() { - if dir.is_dir() { - for entry in fs::read_dir(dir).map_err(|e| Error::with_cause(ReadFailed, e))? { - let entry = entry.map_err(|e| Error::with_cause(ReadFailed, e))?; - let path = entry.path(); - if path.is_dir() { - remove_dir(&path)?; - } + if dir.exists() && dir.is_dir() { + for entry in fs::read_dir(dir).map_err(|e| Error::with_cause(ReadFailed, e))? { + let entry = entry.map_err(|e| Error::with_cause(ReadFailed, e))?; + let path = entry.path(); + if path.is_dir() { + remove_dir(&path)?; } - fs::remove_dir(dir).map_err(|e| Error::with_cause(RemoveFailed, e))?; } + fs::remove_dir(dir).map_err(|e| Error::with_cause(RemoveFailed, e))?; } Ok(()) @@ -641,75 +641,61 @@ impl<'a> From<&'a std::process::Child> for CgroupPid { impl Subsystem { fn enter(self, path: &Path) -> Self { match self { - Subsystem::Pid(cont) => Subsystem::Pid({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::Pid(mut cont) => Subsystem::Pid({ + cont.get_path_mut().push(path); + cont }), - Subsystem::Mem(cont) => Subsystem::Mem({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::Mem(mut cont) => Subsystem::Mem({ + cont.get_path_mut().push(path); + cont }), - Subsystem::CpuSet(cont) => Subsystem::CpuSet({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::CpuSet(mut cont) => Subsystem::CpuSet({ + cont.get_path_mut().push(path); + cont }), - Subsystem::CpuAcct(cont) => Subsystem::CpuAcct({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::CpuAcct(mut cont) => Subsystem::CpuAcct({ + cont.get_path_mut().push(path); + cont }), - Subsystem::Cpu(cont) => Subsystem::Cpu({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::Cpu(mut cont) => Subsystem::Cpu({ + cont.get_path_mut().push(path); + cont }), - Subsystem::Devices(cont) => Subsystem::Devices({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::Devices(mut cont) => Subsystem::Devices({ + cont.get_path_mut().push(path); + cont }), - Subsystem::Freezer(cont) => Subsystem::Freezer({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::Freezer(mut cont) => Subsystem::Freezer({ + cont.get_path_mut().push(path); + cont }), - Subsystem::NetCls(cont) => Subsystem::NetCls({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::NetCls(mut cont) => Subsystem::NetCls({ + cont.get_path_mut().push(path); + cont }), - Subsystem::BlkIo(cont) => Subsystem::BlkIo({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::BlkIo(mut cont) => Subsystem::BlkIo({ + cont.get_path_mut().push(path); + cont }), - Subsystem::PerfEvent(cont) => Subsystem::PerfEvent({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::PerfEvent(mut cont) => Subsystem::PerfEvent({ + cont.get_path_mut().push(path); + cont }), - Subsystem::NetPrio(cont) => Subsystem::NetPrio({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::NetPrio(mut cont) => Subsystem::NetPrio({ + cont.get_path_mut().push(path); + cont }), - Subsystem::HugeTlb(cont) => Subsystem::HugeTlb({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::HugeTlb(mut cont) => Subsystem::HugeTlb({ + cont.get_path_mut().push(path); + cont }), - Subsystem::Rdma(cont) => Subsystem::Rdma({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::Rdma(mut cont) => Subsystem::Rdma({ + cont.get_path_mut().push(path); + cont }), - Subsystem::Systemd(cont) => Subsystem::Systemd({ - let mut c = cont.clone(); - c.get_path_mut().push(path); - c + Subsystem::Systemd(mut cont) => Subsystem::Systemd({ + cont.get_path_mut().push(path); + cont }), } } @@ -760,16 +746,18 @@ impl MaxValue { MaxValue::Value(num) => *num, } } +} - fn to_string(&self) -> String { +impl fmt::Display for MaxValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - MaxValue::Max => "max".to_string(), - MaxValue::Value(num) => num.to_string(), + MaxValue::Max => write!(f, "max"), + MaxValue::Value(num) => write!(f, "{}", num.to_string()), } } } -pub fn parse_max_value(s: &String) -> Result { +pub fn parse_max_value(s: &str) -> Result { if s.trim() == "max" { return Ok(MaxValue::Max); } @@ -791,11 +779,8 @@ pub fn flat_keyed_to_vec(mut file: File) -> Result> { for line in content.lines() { let parts: Vec<&str> = line.split(' ').collect(); if parts.len() == 2 { - match parts[1].parse::() { - Ok(i) => { - v.push((parts[0].to_string(), i)); - } - Err(_) => {} + if let Ok(i) = parts[1].parse::() { + v.push((parts[0].to_string(), i)); } } } @@ -814,11 +799,8 @@ pub fn flat_keyed_to_hashmap(mut file: File) -> Result> { for line in content.lines() { let parts: Vec<&str> = line.split(' ').collect(); if parts.len() == 2 { - match parts[1].parse::() { - Ok(i) => { - h.insert(parts[0].to_string(), i); - } - Err(_) => {} + if let Ok(i) = parts[1].parse::() { + h.insert(parts[0].to_string(), i); } } } @@ -836,18 +818,15 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result = line.split(' ').collect(); - if parts.len() == 0 { + if parts.is_empty() { continue; } let mut th = HashMap::new(); - for item in parts[1..].into_iter() { + for item in parts[1..].iter() { let fields: Vec<&str> = item.split('=').collect(); if fields.len() == 2 { - match fields[1].parse::() { - Ok(i) => { - th.insert(fields[0].to_string(), i); - } - Err(_) => {} + if let Ok(i) = fields[1].parse::() { + th.insert(fields[0].to_string(), i); } } } diff --git a/src/memory.rs b/src/memory.rs index 037e9c38..b682a9cb 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -56,6 +56,7 @@ pub struct OomControl { pub oom_kill: u64, } +#[allow(clippy::unnecessary_wraps)] fn parse_oom_control(s: String) -> Result { let spl = s.split_whitespace().collect::>(); @@ -122,9 +123,10 @@ pub struct NumaStat { pub hierarchical_unevictable_pages_per_node: Vec, } +#[allow(clippy::unnecessary_wraps)] fn parse_numa_stat(s: String) -> Result { // Parse the number of nodes - let _nodes = (s.split_whitespace().collect::>().len() - 8) / 8; + let _nodes = (s.split_whitespace().count() - 8) / 8; let mut ls = s.lines(); let total_line = ls.next().unwrap(); let file_line = ls.next().unwrap(); @@ -142,10 +144,10 @@ fn parse_numa_stat(s: String) -> Result { .parse::() .unwrap_or(0), total_pages_per_node: { - let spl = &total_line.split(" ").collect::>()[1..]; + let spl = &total_line.split(' ').collect::>()[1..]; spl.iter() .map(|x| { - x.split("=").collect::>()[1] + x.split('=').collect::>()[1] .parse::() .unwrap_or(0) }) @@ -157,10 +159,10 @@ fn parse_numa_stat(s: String) -> Result { .parse::() .unwrap_or(0), file_pages_per_node: { - let spl = &file_line.split(" ").collect::>()[1..]; + let spl = &file_line.split(' ').collect::>()[1..]; spl.iter() .map(|x| { - x.split("=").collect::>()[1] + x.split('=').collect::>()[1] .parse::() .unwrap_or(0) }) @@ -172,10 +174,10 @@ fn parse_numa_stat(s: String) -> Result { .parse::() .unwrap_or(0), anon_pages_per_node: { - let spl = &anon_line.split(" ").collect::>()[1..]; + let spl = &anon_line.split(' ').collect::>()[1..]; spl.iter() .map(|x| { - x.split("=").collect::>()[1] + x.split('=').collect::>()[1] .parse::() .unwrap_or(0) }) @@ -187,10 +189,10 @@ fn parse_numa_stat(s: String) -> Result { .parse::() .unwrap_or(0), unevictable_pages_per_node: { - let spl = &unevict_line.split(" ").collect::>()[1..]; + let spl = &unevict_line.split(' ').collect::>()[1..]; spl.iter() .map(|x| { - x.split("=").collect::>()[1] + x.split('=').collect::>()[1] .parse::() .unwrap_or(0) }) @@ -209,10 +211,10 @@ fn parse_numa_stat(s: String) -> Result { }, hierarchical_total_pages_per_node: { if !hier_total_line.is_empty() { - let spl = &hier_total_line.split(" ").collect::>()[1..]; + let spl = &hier_total_line.split(' ').collect::>()[1..]; spl.iter() .map(|x| { - x.split("=").collect::>()[1] + x.split('=').collect::>()[1] .parse::() .unwrap_or(0) }) @@ -234,10 +236,10 @@ fn parse_numa_stat(s: String) -> Result { }, hierarchical_file_pages_per_node: { if !hier_file_line.is_empty() { - let spl = &hier_file_line.split(" ").collect::>()[1..]; + let spl = &hier_file_line.split(' ').collect::>()[1..]; spl.iter() .map(|x| { - x.split("=").collect::>()[1] + x.split('=').collect::>()[1] .parse::() .unwrap_or(0) }) @@ -259,10 +261,10 @@ fn parse_numa_stat(s: String) -> Result { }, hierarchical_anon_pages_per_node: { if !hier_anon_line.is_empty() { - let spl = &hier_anon_line.split(" ").collect::>()[1..]; + let spl = &hier_anon_line.split(' ').collect::>()[1..]; spl.iter() .map(|x| { - x.split("=").collect::>()[1] + x.split('=').collect::>()[1] .parse::() .unwrap_or(0) }) @@ -284,10 +286,10 @@ fn parse_numa_stat(s: String) -> Result { }, hierarchical_unevictable_pages_per_node: { if !hier_unevict_line.is_empty() { - let spl = &hier_unevict_line.split(" ").collect::>()[1..]; + let spl = &hier_unevict_line.split(' ').collect::>()[1..]; spl.iter() .map(|x| { - x.split("=").collect::>()[1] + x.split('=').collect::>()[1] .parse::() .unwrap_or(0) }) @@ -340,6 +342,7 @@ pub struct MemoryStat { pub raw: HashMap, } +#[allow(clippy::unnecessary_wraps)] fn parse_memory_stat(s: String) -> Result { let mut raw = HashMap::new(); @@ -393,7 +396,7 @@ fn parse_memory_stat(s: String) -> Result { total_inactive_file: *raw.get("total_inactive_file").unwrap_or(&0), total_active_file: *raw.get("total_active_file").unwrap_or(&0), total_unevictable: *raw.get("total_unevictable").unwrap_or(&0), - raw: raw, + raw, }) } @@ -532,7 +535,7 @@ impl MemController { Self { base: root.clone(), path: root, - v2: v2, + v2, } } @@ -547,8 +550,8 @@ impl MemController { for value in values { let v = value.0; let f = value.1; - if v.is_some() { - let v = v.unwrap().to_string(); + if let Some(v) = v { + let v = v.to_string(); self.open_path(f, true).and_then(|mut file| { file.write_all(v.as_ref()) .map_err(|e| Error::with_cause(WriteFailed, e)) @@ -589,7 +592,7 @@ impl MemController { .open_path("memory.stat", false) .and_then(read_string_from) .and_then(parse_memory_stat) - .unwrap_or(MemoryStat::default()), + .unwrap_or_default(), swappiness: self .open_path("memory.swap.current", false) .and_then(read_u64_from) @@ -633,12 +636,12 @@ impl MemController { .open_path("memory.numa_stat", false) .and_then(read_string_from) .and_then(parse_numa_stat) - .unwrap_or(NumaStat::default()), + .unwrap_or_default(), oom_control: self .open_path("memory.oom_control", false) .and_then(read_string_from) .and_then(parse_oom_control) - .unwrap_or(OomControl::default()), + .unwrap_or_default(), soft_limit_in_bytes: self .open_path("memory.soft_limit_in_bytes", false) .and_then(read_i64_from) @@ -647,7 +650,7 @@ impl MemController { .open_path("memory.stat", false) .and_then(read_string_from) .and_then(parse_memory_stat) - .unwrap_or(MemoryStat::default()), + .unwrap_or_default(), swappiness: self .open_path("memory.swappiness", false) .and_then(read_u64_from) @@ -681,7 +684,7 @@ impl MemController { slabinfo: self .open_path("memory.kmem.slabinfo", false) .and_then(read_string_from) - .unwrap_or("".to_string()), + .unwrap_or_default(), } } @@ -713,7 +716,7 @@ impl MemController { fail_cnt: self .open_path("memory.swap.events", false) .and_then(flat_keyed_to_hashmap) - .and_then(|x| Ok(*x.get("fail").unwrap_or(&0) as u64)) + .map(|x| *x.get("fail").unwrap_or(&0) as u64) .unwrap(), limit_in_bytes: self .open_path("memory.swap.max", false) @@ -1143,7 +1146,7 @@ total_unevictable 81920 total_inactive_file: 1272135680, total_active_file: 2338816000, total_unevictable: 81920, - raw: raw, + raw, } ); } diff --git a/src/net_cls.rs b/src/net_cls.rs index 77b3f07d..fd6d1332 100644 --- a/src/net_cls.rs +++ b/src/net_cls.rs @@ -49,7 +49,7 @@ impl ControllerInternal for NetClsController { update_and_test!(self, set_class, res.class_id, get_class); - return Ok(()); + Ok(()) } } @@ -96,6 +96,6 @@ impl NetClsController { /// Get the network class id of the outgoing packets of the control group's tasks. pub fn get_class(&self) -> Result { self.open_path("net_cls.classid", false) - .and_then(|file| read_u64_from(file)) + .and_then(read_u64_from) } } diff --git a/src/net_prio.rs b/src/net_prio.rs index d2b6c68a..4620eb35 100644 --- a/src/net_prio.rs +++ b/src/net_prio.rs @@ -94,6 +94,7 @@ impl NetPrioController { } /// A map of priorities for each network interface. + #[allow(clippy::iter_nth_zero, clippy::unnecessary_unwrap)] pub fn ifpriomap(&self) -> Result> { self.open_path("net_prio.ifpriomap", false) .and_then(|file| { @@ -105,6 +106,7 @@ impl NetPrioController { let mut acc = acc.unwrap(); let l = line.unwrap(); let mut sp = l.split_whitespace(); + let ifname = sp.nth(0); let ifprio = sp.nth(1); if ifname.is_none() || ifprio.is_none() { diff --git a/src/pid.rs b/src/pid.rs index fef84210..b03e3dc4 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -96,7 +96,7 @@ impl PidController { Self { base: root.clone(), path: root, - v2: v2, + v2, } } diff --git a/src/systemd.rs b/src/systemd.rs index 3fe02626..8eb3db26 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -66,7 +66,7 @@ impl SystemdController { Self { base: root.clone(), path: root, - v2: v2, + v2, } } } diff --git a/tests/cgroup.rs b/tests/cgroup.rs index 962cdf5a..563168b1 100644 --- a/tests/cgroup.rs +++ b/tests/cgroup.rs @@ -48,7 +48,7 @@ fn test_cgroup_with_relative_paths() { let cg = Cgroup::load(h, String::from(cgroup_name)); { let subsystems = cg.subsystems(); - subsystems.into_iter().for_each(|sub| match sub { + subsystems.iter().for_each(|sub| match sub { Subsystem::Pid(c) => { let cgroup_path = c.path().to_str().unwrap(); let relative_path = "/pids/"; diff --git a/tests/cpuset.rs b/tests/cpuset.rs index a714683d..44e525ed 100644 --- a/tests/cpuset.rs +++ b/tests/cpuset.rs @@ -36,7 +36,7 @@ fn test_cpuset_set_cpus() { assert_eq!(0, set.cpus.len()); } else { // for cgroup v1, cpuset is copied from parent. - assert_eq!(true, set.cpus.len() > 0); + assert_eq!(true, !set.cpus.is_empty()); } // 0 @@ -48,10 +48,9 @@ fn test_cpuset_set_cpus() { assert_eq!((0, 0), set.cpus[0]); // all cpus in system - let cpus = - fs::read_to_string("/sys/fs/cgroup/cpuset.cpus.effective").unwrap_or("".to_string()); + let cpus = fs::read_to_string("/sys/fs/cgroup/cpuset.cpus.effective").unwrap_or_default(); let cpus = cpus.trim(); - if cpus != "" { + if !cpus.is_empty() { let r = cpuset.set_cpus(&cpus); assert_eq!(true, r.is_ok()); let set = cpuset.cpuset(); @@ -73,14 +72,14 @@ fn test_cpuset_set_cpus_add_task() { assert_eq!(0, set.cpus.len()); } else { // for cgroup v1, cpuset is copied from parent. - assert_eq!(true, set.cpus.len() > 0); + assert_eq!(true, !set.cpus.is_empty()); } // Add a task to the control group. let pid_i = libc::pid_t::from(nix::unistd::getpid()) as u64; let _ = cg.add_task(CgroupPid::from(pid_i)); let tasks = cg.tasks(); - assert_eq!(true, tasks.len() > 0); + assert_eq!(true, !tasks.is_empty()); println!("tasks after added: {:?}", tasks); // remove task diff --git a/tests/devices.rs b/tests/devices.rs index a88bb294..90c1bef2 100644 --- a/tests/devices.rs +++ b/tests/devices.rs @@ -27,7 +27,7 @@ fn test_devices_parsing() { DeviceType::All, -1, -1, - &vec![ + &[ DevicePermissions::Read, DevicePermissions::Write, DevicePermissions::MkNod, @@ -42,7 +42,7 @@ fn test_devices_parsing() { // Now add mknod access to /dev/null device devices - .allow_device(DeviceType::Char, 1, 3, &vec![DevicePermissions::MkNod]) + .allow_device(DeviceType::Char, 1, 3, &[DevicePermissions::MkNod]) .unwrap(); let allowed_devices = devices.allowed_devices(); assert!(allowed_devices.is_ok()); diff --git a/tests/pids.rs b/tests/pids.rs index 94d9ce19..27a2de79 100644 --- a/tests/pids.rs +++ b/tests/pids.rs @@ -89,7 +89,7 @@ fn test_pid_events_is_not_zero() { Ok(ForkResult::Child) => loop { let pids_max = pids.get_pid_max(); if pids_max.is_ok() && pids_max.unwrap() == MaxValue::Value(1) { - if let Err(_) = unsafe { fork() } { + if unsafe { fork() }.is_err() { unsafe { libc::exit(0) }; } else { unsafe { libc::exit(1) }; From fdabe5240153c3a63ec562ec7ce9900077321cd0 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 3 Mar 2021 13:46:19 +0800 Subject: [PATCH 66/71] github action: Add clippy check Because the existing warnings are all fixed. Signed-off-by: Tim Zhang --- .github/workflows/bvt.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/bvt.yaml b/.github/workflows/bvt.yaml index 9471fc08..b2bb741c 100644 --- a/.github/workflows/bvt.yaml +++ b/.github/workflows/bvt.yaml @@ -17,6 +17,13 @@ jobs: - uses: actions/checkout@v2 - run: rustup component add rustfmt - run: make fmt + clippy: + name: Clippy Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: rustup component add clippy + - run: make clippy test: name: Run Unit Test runs-on: ubuntu-latest @@ -24,3 +31,4 @@ jobs: - uses: actions/checkout@v2 - run: make test + From aa207edca8709dc4d4dd3720fc90ebc81fb6a812 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Tue, 23 Mar 2021 21:50:18 +0800 Subject: [PATCH 67/71] Impl Clone for hierarchies:V1, hierarchies:V2 Clone is useful. Signed-off-by: Tim Zhang --- src/hierarchies.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hierarchies.rs b/src/hierarchies.rs index 9a5d8df7..0cd2e0e8 100644 --- a/src/hierarchies.rs +++ b/src/hierarchies.rs @@ -35,7 +35,7 @@ use crate::cgroup::Cgroup; /// Process mounts information. /// /// See `proc(5)` for format details. -#[derive(Debug, PartialEq, Eq, Hash)] +#[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct Mountinfo { /// Mount pathname relative to the process's root. pub mount_point: PathBuf, @@ -102,12 +102,12 @@ pub fn mountinfo_self() -> Vec { } /// The standard, original cgroup implementation. Often referred to as "cgroupv1". -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct V1 { mountinfo: Vec, } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct V2 { root: String, } From 0b2a0405e29f6124ff9d67ffef8033f0e7605c27 Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Wed, 24 Mar 2021 14:37:19 +0800 Subject: [PATCH 68/71] release: v0.2.5 Bump version to 0.2.5 Signed-off-by: Tim Zhang --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e56b412e..86d211ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ repository = "https://github.com/kata-containers/cgroups-rs" keywords = ["linux", "cgroup", "containers", "isolation"] categories = ["os", "api-bindings", "os::unix-apis"] license = "MIT OR Apache-2.0" -version = "0.2.4" +version = "0.2.5" authors = ["The Kata Containers community ", "Levente Kurusa ", "Sam Wilson "] edition = "2018" homepage = "https://github.com/kata-containers/cgroups-rs" From 5aa7e6c90ea6ff52064d0dfe5d63dae5c8fa40df Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Fri, 21 May 2021 00:45:27 +0800 Subject: [PATCH 69/71] Fix clippy for rust 1.52 There are new lints are added in clippy for rust 1.52 Signed-off-by: Tim Zhang --- src/cgroup.rs | 5 ++--- src/cgroup_builder.rs | 4 ++-- src/error.rs | 1 + src/events.rs | 10 +++++----- src/lib.rs | 10 ++++------ 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/cgroup.rs b/src/cgroup.rs index 4dda0c08..c28f0226 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -311,9 +311,8 @@ impl Cgroup { pub const UNIFIED_MOUNTPOINT: &str = "/sys/fs/cgroup"; -fn enable_controllers(controllers: &[String], path: &PathBuf) { - let mut f = path.clone(); - f.push("cgroup.subtree_control"); +fn enable_controllers(controllers: &[String], path: &Path) { + let f = path.join("cgroup.subtree_control"); for c in controllers { let body = format!("+{}", c); let _rest = fs::write(f.as_path(), body.as_bytes()); diff --git a/src/cgroup_builder.rs b/src/cgroup_builder.rs index e410fd83..09eca24e 100644 --- a/src/cgroup_builder.rs +++ b/src/cgroup_builder.rs @@ -240,10 +240,10 @@ impl DeviceResourceBuilder { access: Vec, ) -> DeviceResourceBuilder { self.cgroup.resources.devices.devices.push(DeviceResource { + allow, + devtype, major, minor, - devtype, - allow, access, }); self diff --git a/src/error.rs b/src/error.rs index 26c86a80..cea6a39b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -76,6 +76,7 @@ impl fmt::Display for Error { impl StdError for Error { fn cause(&self) -> Option<&dyn StdError> { + #[allow(clippy::manual_map)] match self.cause { Some(ref x) => Some(&**x), None => None, diff --git a/src/events.rs b/src/events.rs index 86f8f755..08c25dee 100644 --- a/src/events.rs +++ b/src/events.rs @@ -8,7 +8,7 @@ use nix::sys::eventfd; use std::fs::{self, File}; use std::io::Read; use std::os::unix::io::{AsRawFd, FromRawFd}; -use std::path::{Path, PathBuf}; +use std::path::Path; use std::sync::mpsc::{self, Receiver}; use std::thread; @@ -17,18 +17,18 @@ use crate::error::*; // notify_on_oom returns channel on which you can expect event about OOM, // if process died without OOM this channel will be closed. -pub fn notify_on_oom_v2(key: &str, dir: &PathBuf) -> Result> { +pub fn notify_on_oom_v2(key: &str, dir: &Path) -> Result> { register_memory_event(key, dir, "memory.oom_control", "") } // notify_on_oom returns channel on which you can expect event about OOM, // if process died without OOM this channel will be closed. -pub fn notify_on_oom_v1(key: &str, dir: &PathBuf) -> Result> { +pub fn notify_on_oom_v1(key: &str, dir: &Path) -> Result> { register_memory_event(key, dir, "memory.oom_control", "") } // level is one of "low", "medium", or "critical" -pub fn notify_memory_pressure(key: &str, dir: &PathBuf, level: &str) -> Result> { +pub fn notify_memory_pressure(key: &str, dir: &Path, level: &str) -> Result> { if level != "low" && level != "medium" && level != "critical" { return Err(Error::from_string(format!( "invalid pressure level {}", @@ -41,7 +41,7 @@ pub fn notify_memory_pressure(key: &str, dir: &PathBuf, level: &str) -> Result Result> { diff --git a/src/lib.rs b/src/lib.rs index 52e63be6..b8b2385d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -365,11 +365,9 @@ where .map(|file| { let bf = BufReader::new(file); let mut v = Vec::new(); - for line in bf.lines() { - if let Ok(line) = line { - let n = line.trim().parse().unwrap_or(0u64); - v.push(n); - } + for line in bf.lines().flatten() { + let n = line.trim().parse().unwrap_or(0u64); + v.push(n); } v.into_iter().map(CgroupPid::from).collect() }) @@ -383,7 +381,7 @@ where // remove_dir aims to remove cgroup path. It does so recursively, // by removing any subdirectories (sub-cgroups) first. -fn remove_dir(dir: &PathBuf) -> Result<()> { +fn remove_dir(dir: &Path) -> Result<()> { // try the fast path first. if fs::remove_dir(dir).is_ok() { return Ok(()); From 0e2430fde169be52a4d724d1d0b751572967febf Mon Sep 17 00:00:00 2001 From: Tim Zhang Date: Fri, 21 May 2021 00:48:50 +0800 Subject: [PATCH 70/71] clippy: turn on lint upper_case_acronyms cargo-clippy has moved the upper_case_acronyms lint to pedantic(removed from the default list), but we need the lint to keep names consistent and follow the rust naming conventions. Signed-off-by: Tim Zhang --- .clippy.toml | 1 + src/cpu.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 .clippy.toml diff --git a/.clippy.toml b/.clippy.toml new file mode 100644 index 00000000..cc94ec53 --- /dev/null +++ b/.clippy.toml @@ -0,0 +1 @@ +upper-case-acronyms-aggressive = true diff --git a/src/cpu.rs b/src/cpu.rs index baaedadd..0c7edd90 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -45,7 +45,7 @@ pub struct Cpu { /// The current state of the control group and its processes. #[derive(Debug)] -struct CFSQuotaAndPeriod { +struct CfsQuotaAndPeriod { quota: MaxValue, period: u64, } @@ -284,7 +284,7 @@ impl CpuController { impl CustomizedAttribute for CpuController {} -fn parse_cfs_quota_and_period(mut file: File) -> Result { +fn parse_cfs_quota_and_period(mut file: File) -> Result { let mut content = String::new(); file.read_to_string(&mut content) .map_err(|e| Error::with_cause(ReadFailed, e))?; @@ -299,5 +299,5 @@ fn parse_cfs_quota_and_period(mut file: File) -> Result { .parse::() .map_err(|e| Error::with_cause(ParseError, e))?; - Ok(CFSQuotaAndPeriod { quota, period }) + Ok(CfsQuotaAndPeriod { quota, period }) } From 4b5a190ecc8f9ad01897ccc6568c1c16aa3f523c Mon Sep 17 00:00:00 2001 From: "fupan.lfp" Date: Wed, 30 Jun 2021 17:41:25 +0800 Subject: [PATCH 71/71] freezer: fix the issue of missing trim the str When reading from the freezer file, it should trim it first, and the string may container an '\n'. Fixes: #48 Signed-off-by: fupan.lfp --- src/freezer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/freezer.rs b/src/freezer.rs index 7f0fc1c9..1382b824 100644 --- a/src/freezer.rs +++ b/src/freezer.rs @@ -130,7 +130,7 @@ impl FreezerController { let mut s = String::new(); let res = file.read_to_string(&mut s); match res { - Ok(_) => match s.as_ref() { + Ok(_) => match s.trim() { "FROZEN" => Ok(FreezerState::Frozen), "THAWED" => Ok(FreezerState::Thawed), "1" => Ok(FreezerState::Frozen),