From ca610bb57e8872680264ad89164bdd5a3b3b2e4e Mon Sep 17 00:00:00 2001 From: "Yang, Wei" Date: Fri, 24 Jul 2020 19:14:40 +0800 Subject: [PATCH 01/23] 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 13308a8..8e6dd97 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 0761631..c94f73e 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 02/23] 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 535de66..9f34911 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 c94f73e..d1aa71f 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 9b1e804..0e3ea8c 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 03/23] 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 f648343..b0f78a2 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); } + 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_read_bps_device { - let _ = self.throttle_read_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_write_bps_device { - let _ = self.throttle_write_bps_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_read_iops_device { - let _ = self.throttle_read_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); - } + 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 0432fa5..174b8ec 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 9f34911..105a438 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)); - } + 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_period(res.period); - if self.cfs_period()? != res.period as u64 { - return Err(Error::new(ErrorKind::Other)); - } + res.attrs.iter().for_each(|(k, v)| { + let _ = self.set(k, v); + }); - 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); - }) - - // 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 28de1eb..4d4427d 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 605e735..5a78a2e 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 c65b4f4..d9e8d3c 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 d1aa71f..9fe2bef 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 0e3ea8c..3b48289 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 860ae8d..ad2af39 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 ed16ed9..3728796 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 d08ba30..e9c4869 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 04/23] 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 fced12a..cb19bfa 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 665e4d0..4047124 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 05/23] 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 e498f70..50a2bd3 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 06/23] 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 8e6dd97..4579204 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 1a273ab..a8cd65c 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 9fe2bef..117e88e 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 07/23] 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 50a2bd3..3588039 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 08/23] 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 4579204..b0a8fb1 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) + let cg = Cgroup::load(hier, path); + cg.create(); + cg } - /// 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) - } - - /// 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 09/23] 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 b0a8fb1..9a7e859 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 174b8ec..afe7387 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 3588039..c0ca8b0 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 915a5f9..c071fc5 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 cbaad33..bcd563d 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 3563354..efb7141 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 adb7e13..85cc617 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 095243e..9a2468f 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 2d64906..f1f6e8a 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 0449a0d..fadb2e1 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 4047124..18c4aef 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 10/23] 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 3b48289..9dcea22 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 cb19bfa..cf215a3 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 c071fc5..7a6d8dd 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 bcd563d..9eb4e99 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 efb7141..0e8aa2a 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 85cc617..c8bc33c 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 9a2468f..505a6cb 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 f1f6e8a..92b508b 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 fadb2e1..c756581 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 18c4aef..7ceacfe 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 11/23] 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 156a69f..5bdbbe6 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 b0f78a2..7e21faf 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 105a438..bcf9206 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 0924d95..6efde64 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 4d4427d..cef4679 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 5a78a2e..838d17e 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 c9da379..93a0185 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 c0ca8b0..4e0742f 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 d9e8d3c..686a599 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 117e88e..fe5c0c0 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 9dcea22..314de66 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 ad2af39..5328eb1 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 3728796..d1bbbde 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 09eefc6..f0e9240 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 e9c4869..1955828 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 9d366d2..8066c15 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 545c411..3fe0262 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 12/23] 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 fe5c0c0..96b96c2 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 13/23] 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 a8cd65c..26c86a8 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 14/23] 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 96b96c2..cd53081 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 15/23] 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 9a7e859..3e92757 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 afe7387..244ca4a 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 4e0742f..fb06cb0 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 cd53081..46551cb 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 16/23] 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 244ca4a..f7033e4 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 cf215a3..7eef071 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 7a6d8dd..60ae4b3 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 9eb4e99..8d75871 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 0e8aa2a..34808dd 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 c8bc33c..6758ff7 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 505a6cb..380afd3 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 92b508b..0f57af5 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 c756581..f5d7191 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 7ceacfe..0cb65bc 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 17/23] 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 da0754e..6f26f5c 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 18/23] 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 314de66..7e87a96 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 19/23] 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 7e87a96..6243a15 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 20/23] 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 3e92757..63f413a 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 46551cb..f1205be 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 21/23] 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 63f413a..5dedab5 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 22/23] 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 f1205be..9253c34 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 6243a15..04fd908 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 23/23] 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 5bdbbe6..9ff10a3 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"