diff --git a/src/blkio.rs b/src/blkio.rs index fcd0c5e..f3b6cbe 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -101,7 +101,7 @@ impl Controller for BlkIoController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, res: &Resources) { + fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError> { /* get the resources that apply to this controller */ let res: &BlkIoResources = &res.blkio; @@ -110,8 +110,7 @@ impl Controller for BlkIoController { let _ = self.set_leaf_weight(res.leaf_weight as u64); for dev in &res.weight_device { - let _ = self.set_weight_for_device(format!("{}:{} {}", - dev.major, dev.minor, dev.weight)); + let _ = self.set_weight_for_device(dev.major, dev.minor, dev.weight as u64); } for dev in &res.throttle_read_bps_device { @@ -130,6 +129,8 @@ impl Controller for BlkIoController { let _ = self.throttle_write_iops_for_device(dev.major, dev.minor, dev.rate); } } + + Ok(()) } } @@ -334,9 +335,10 @@ impl BlkIoController { } /// Same as `set_weight()`, but settable per each block device. - pub fn set_weight_for_device(self: &Self, d: String) -> Result<(), CgroupError> { + pub fn set_weight_for_device(self: &Self, major: u64, minor: u64, weight: u64) -> Result<(), CgroupError> { self.open_path("blkio.weight_device", true).and_then(|mut file| { - file.write_all(d.as_ref()).map_err(CgroupError::WriteError) + file.write_all(format!("{}:{} {}", major, minor, weight).as_ref()) + .map_err(CgroupError::WriteError) }) } } diff --git a/src/cgroup.rs b/src/cgroup.rs index 5f858dc..affc001 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -99,10 +99,8 @@ impl<'b> Cgroup<'b> { } /// Apply a set of resource limits to the control group. - pub fn apply(self: &Self, res: &Resources) { - for subsystem in &self.subsystems { - subsystem.to_controller().apply(res); - } + pub fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError> { + self.subsystems.iter().try_fold((), |_, e| e.to_controller().apply(res)) } /// Retrieve a container based on type inference. diff --git a/src/cpu.rs b/src/cpu.rs index 2d6d74c..5a2a232 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -5,6 +5,7 @@ //! paragraph 7 ("GROUP SCHEDULER EXTENSIONS TO CFS"). use std::path::PathBuf; use std::io::{Read, Write}; +use std::fs::File; use {CgroupError, CpuResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem}; @@ -34,17 +35,28 @@ impl Controller for CpuController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, res: &Resources) { + fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError> { /* get the resources that apply to this controller */ let res: &CpuResources = &res.cpu; if res.update_values { /* apply pid_max */ let _ = self.set_shares(res.shares); + if self.shares() != Ok(res.shares as u64) { + return Err(CgroupError::Unknown); + } let _ = self.set_cfs_period(res.period); + if self.cfs_period() != Ok(res.period as u64) { + return Err(CgroupError::Unknown); + } let _ = self.set_cfs_quota(res.quota as u64); + if self.cfs_quota() != Ok(res.quota as u64) { + return Err(CgroupError::Unknown); + } /* TODO: rt properties (CONFIG_RT_GROUP_SCHED) are not yet supported */ } + + Ok(()) } } @@ -68,6 +80,14 @@ impl<'a> From<&'a Subsystem> for &'a CpuController { } } +fn read_u64_from(mut file: File) -> Result { + let mut string = String::new(); + match file.read_to_string(&mut string) { + Ok(_) => string.trim().parse().map_err(|_| CgroupError::ParseError), + Err(e) => Err(CgroupError::ReadError(e)), + } +} + impl CpuController { /// Contructs a new `CpuController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { @@ -105,6 +125,13 @@ impl CpuController { }) } + /// Retrieve the CPU bandwidth that this control group (relative to other control groups and + /// this control group's parent) can use. + pub fn shares(self: &Self) -> Result { + self.open_path("cpu.shares", false) + .and_then(read_u64_from) + } + /// Specify a period (when using the CFS scheduler) of time in microseconds for how often this /// control group's access to the CPU should be reallocated. pub fn set_cfs_period(self: &Self, us: u64) -> Result<(), CgroupError> { @@ -113,6 +140,13 @@ impl CpuController { }) } + /// Retrieve the period of time of how often this cgroup's access to the CPU should be + /// reallocated in microseconds. + pub fn cfs_period(self: &Self) -> Result { + self.open_path("cpu.cfs_period_us", false) + .and_then(read_u64_from) + } + /// Specify a quota (when using the CFS scheduler) of time in microseconds for which all tasks /// in this control group can run during one period (see: `set_cfs_period()`). pub fn set_cfs_quota(self: &Self, us: u64) -> Result<(), CgroupError> { @@ -120,4 +154,11 @@ impl CpuController { file.write_all(us.to_string().as_ref()).map_err(CgroupError::WriteError) }) } + + /// Retrieve the quota of time for which all tasks in this cgroup can run during one period, in + /// microseconds. + pub fn cfs_quota(self: &Self) -> Result { + self.open_path("cpu.cfs_quota_us", false) + .and_then(read_u64_from) + } } diff --git a/src/cpuacct.rs b/src/cpuacct.rs index 851b107..31d9997 100644 --- a/src/cpuacct.rs +++ b/src/cpuacct.rs @@ -55,7 +55,8 @@ impl Controller for CpuAcctController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, _res: &Resources) { + fn apply(self: &Self, _res: &Resources) -> Result<(), CgroupError> { + Ok(()) } } diff --git a/src/cpuset.rs b/src/cpuset.rs index e44ca20..1d9718c 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -82,15 +82,16 @@ impl Controller for CpuSetController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, res: &Resources) { + fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError> { /* get the resources that apply to this controller */ let res: &CpuResources = &res.cpu; if res.update_values { - /* apply pid_max */ let _ = self.set_cpus(&res.cpus); let _ = self.set_mems(&res.mems); } + + Ok(()) } } diff --git a/src/devices.rs b/src/devices.rs index 0af65ca..2d0481f 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -129,7 +129,7 @@ impl Controller for DevicesController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, res: &Resources) { + fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError> { /* get the resources that apply to this controller */ let res: &DeviceResources = &res.devices; @@ -142,6 +142,8 @@ impl Controller for DevicesController { } } } + + Ok(()) } } diff --git a/src/freezer.rs b/src/freezer.rs index b8d76a8..f223b04 100644 --- a/src/freezer.rs +++ b/src/freezer.rs @@ -37,7 +37,8 @@ impl Controller for FreezerController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, _res: &Resources) { + fn apply(self: &Self, _res: &Resources) -> Result<(), CgroupError> { + Ok(()) } } diff --git a/src/hugetlb.rs b/src/hugetlb.rs index 9c0506a..4cc4006 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -26,15 +26,19 @@ impl Controller for HugeTlbController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, res: &Resources) { + fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError> { /* 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) != Ok(i.limit) { + return Err(CgroupError::Unknown); + } } } + Ok(()) } } diff --git a/src/lib.rs b/src/lib.rs index b8eb231..8a3036c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,6 +86,8 @@ pub enum CgroupError { /// This could be caused by trying to escape the control group filesystem via a string of "..". /// This crate checks against this and operations will fail with this error. InvalidPath, + /// An unknown error has occured. + Unknown, } impl PartialEq for CgroupError { @@ -106,6 +108,9 @@ impl PartialEq for CgroupError { CgroupError::InvalidPath => if let CgroupError::InvalidPath = other { return true; } else { return false }, + CgroupError::Unknown => if let CgroupError::Unknown = other { + return true; + } else { return false }, } } } @@ -154,7 +159,7 @@ impl Controllers { pub trait Controller { /// Apply a set of resources to the Controller, invoking its internal functions to pass the /// kernel the information. - fn apply(self: &Self, res: &Resources); + fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError>; /* meta stuff */ #[doc(hidden)] diff --git a/src/memory.rs b/src/memory.rs index a10c03a..0a15379 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -121,7 +121,7 @@ impl Controller for MemController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, res: &Resources) { + fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError> { /* get the resources that apply to this controller */ let memres: &MemoryResources = &res.memory; @@ -133,6 +133,8 @@ impl Controller for MemController { let _ = self.set_tcp_limit(memres.kernel_tcp_memory_limit); let _ = self.set_swappiness(memres.swappiness); } + + Ok(()) } } diff --git a/src/net_cls.rs b/src/net_cls.rs index febe901..a96e41e 100644 --- a/src/net_cls.rs +++ b/src/net_cls.rs @@ -26,13 +26,17 @@ impl Controller for NetClsController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, res: &Resources) { + fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError> { /* 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() != Ok(res.class_id) { + return Err(CgroupError::Unknown); + } } + return Ok(()); } } diff --git a/src/net_prio.rs b/src/net_prio.rs index 10082a2..2fc1e21 100644 --- a/src/net_prio.rs +++ b/src/net_prio.rs @@ -27,7 +27,7 @@ impl Controller for NetPrioController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, res: &Resources) { + fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError> { /* get the resources that apply to this controller */ let res: &NetworkResources = &res.network; @@ -36,6 +36,8 @@ impl Controller for NetPrioController { let _ = self.set_if_prio(&i.name, i.priority); } } + + Ok(()) } } diff --git a/src/perf_event.rs b/src/perf_event.rs index 313f570..bf80729 100644 --- a/src/perf_event.rs +++ b/src/perf_event.rs @@ -4,7 +4,7 @@ //! [tools/perf/Documentation/perf-record.txt](https://raw.githubusercontent.com/torvalds/linux/master/tools/perf/Documentation/perf-record.txt) use std::path::PathBuf; -use {Controllers, Controller, Resources, ControllIdentifier, Subsystem}; +use {CgroupError, Controllers, Controller, Resources, ControllIdentifier, Subsystem}; /// A controller that allows controlling the `perf_event` subsystem of a Cgroup. /// @@ -22,7 +22,8 @@ impl Controller for PerfEventController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, _res: &Resources) { + fn apply(self: &Self, _res: &Resources) -> Result<(), CgroupError> { + Ok(()) } } diff --git a/src/pid.rs b/src/pid.rs index 32bc1b2..3b7c610 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -38,14 +38,23 @@ impl Controller for PidController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, res: &Resources) { + fn apply(self: &Self, res: &Resources) -> Result<(), CgroupError> { /* 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() == Ok(pidres.maximum_number_of_processes) { + return Ok(()); + } else { + return Err(CgroupError::Unknown); + } } + + Ok(()) } } diff --git a/src/rdma.rs b/src/rdma.rs index 82fea7b..74fde9a 100644 --- a/src/rdma.rs +++ b/src/rdma.rs @@ -24,7 +24,8 @@ impl Controller for RdmaController { fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path } fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base } - fn apply(self: &Self, _res: &Resources) { + fn apply(self: &Self, _res: &Resources) -> Result<(), CgroupError> { + Ok(()) } }