controllers: verify that resource application went ok or not

Signed-off-by: Levente Kurusa <lkurusa@acm.org>
This commit is contained in:
Levente Kurusa
2018-09-14 15:59:29 +02:00
parent af12452fca
commit 0e350463a1
15 changed files with 98 additions and 24 deletions

View File

@@ -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)
})
}
}

View File

@@ -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.

View File

@@ -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<u64, CgroupError> {
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<u64, CgroupError> {
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<u64, CgroupError> {
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<u64, CgroupError> {
self.open_path("cpu.cfs_quota_us", false)
.and_then(read_u64_from)
}
}

View File

@@ -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(())
}
}

View File

@@ -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(())
}
}

View File

@@ -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(())
}
}

View File

@@ -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(())
}
}

View File

@@ -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(())
}
}

View File

@@ -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)]

View File

@@ -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(())
}
}

View File

@@ -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(());
}
}

View File

@@ -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(())
}
}

View File

@@ -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(())
}
}

View File

@@ -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(())
}
}

View File

@@ -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(())
}
}