Run rustfmt

This commit is contained in:
Hidehito Yabuuchi
2018-10-04 00:45:43 +09:00
committed by Levente Kurusa
parent 5660656e3a
commit 2149e1c0c4
21 changed files with 1208 additions and 737 deletions

View File

@@ -1,13 +1,15 @@
//! This module contains the implementation of the `blkio` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroup-v1/blkio-controller.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt)
use std::path::PathBuf;
use std::io::{Read, Write};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use {CgroupError, BlkIoResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
use CgroupError::*;
use {
BlkIoResources, CgroupError, ControllIdentifier, Controller, Controllers, Resources, Subsystem,
};
/// A controller that allows controlling the `blkio` subsystem of a Cgroup.
///
@@ -102,35 +104,31 @@ fn parse_io_service_total(s: String) -> Result<u64, CgroupError> {
}
fn parse_blkio_data(s: String) -> Result<Vec<BlkIoData>, CgroupError> {
let r = s.chars()
let r = s
.chars()
.map(|x| if x == ':' { ' ' } else { x })
.collect::<String>();
let r = r.lines()
let r = r
.lines()
.flat_map(|x| x.split_whitespace())
.collect::<Vec<_>>();
let r = r.chunks(3)
.collect::<Vec<_>>();
let r = r.chunks(3).collect::<Vec<_>>();
let mut res = Vec::new();
let err = r.iter()
.try_for_each(|x|
match x {
[major, minor, data] => {
res.push(BlkIoData {
major: major.parse::<i16>().unwrap(),
minor: minor.parse::<i16>().unwrap(),
data: data.parse::<u64>().unwrap(),
});
Ok(())
},
_ => {
Err(CgroupError::ParseError)
}
}
);
let err = r.iter().try_for_each(|x| match x {
[major, minor, data] => {
res.push(BlkIoData {
major: major.parse::<i16>().unwrap(),
minor: minor.parse::<i16>().unwrap(),
data: data.parse::<u64>().unwrap(),
});
Ok(())
}
_ => Err(CgroupError::ParseError),
});
if err.is_err() {
return Err(CgroupError::ParseError);
@@ -256,10 +254,18 @@ pub struct BlkIo {
}
impl Controller for BlkIoController {
fn control_type(&self) -> Controllers { Controllers::BlkIo }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::BlkIo
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, res: &Resources) -> Result<(), CgroupError> {
/* get the resources that apply to this controller */
@@ -308,7 +314,7 @@ impl<'a> From<&'a Subsystem> for &'a BlkIoController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -345,172 +351,216 @@ impl BlkIoController {
/// group's tasks.
pub fn blkio(&self) -> BlkIo {
BlkIo {
io_merged: self.open_path("blkio.io_merged", false)
io_merged: self
.open_path("blkio.io_merged", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_merged_total: self.open_path("blkio.io_merged", false)
io_merged_total: self
.open_path("blkio.io_merged", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_merged_recursive: self.open_path("blkio.io_merged_recursive", false)
io_merged_recursive: self
.open_path("blkio.io_merged_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_merged_recursive_total: self.open_path("blkio.io_merged_recursive", false)
io_merged_recursive_total: self
.open_path("blkio.io_merged_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_queued: self.open_path("blkio.io_queued", false)
io_queued: self
.open_path("blkio.io_queued", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_queued_total: self.open_path("blkio.io_queued", false)
io_queued_total: self
.open_path("blkio.io_queued", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_queued_recursive: self.open_path("blkio.io_queued_recursive", false)
io_queued_recursive: self
.open_path("blkio.io_queued_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_queued_recursive_total: self.open_path("blkio.io_queued_recursive", false)
io_queued_recursive_total: self
.open_path("blkio.io_queued_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_service_bytes: self.open_path("blkio.io_service_bytes", false)
io_service_bytes: self
.open_path("blkio.io_service_bytes", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_service_bytes_total: self.open_path("blkio.io_service_bytes", false)
io_service_bytes_total: self
.open_path("blkio.io_service_bytes", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_service_bytes_recursive: self.open_path("blkio.io_service_bytes_recursive", false)
io_service_bytes_recursive: self
.open_path("blkio.io_service_bytes_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_service_bytes_recursive_total: self.open_path("blkio.io_service_bytes_recursive", false)
io_service_bytes_recursive_total: self
.open_path("blkio.io_service_bytes_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_serviced: self.open_path("blkio.io_serviced", false)
io_serviced: self
.open_path("blkio.io_serviced", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_serviced_total: self.open_path("blkio.io_serviced", false)
io_serviced_total: self
.open_path("blkio.io_serviced", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_serviced_recursive: self.open_path("blkio.io_serviced_recursive", false)
io_serviced_recursive: self
.open_path("blkio.io_serviced_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_serviced_recursive_total: self.open_path("blkio.io_serviced_recursive", false)
io_serviced_recursive_total: self
.open_path("blkio.io_serviced_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_service_time: self.open_path("blkio.io_service_time", false)
io_service_time: self
.open_path("blkio.io_service_time", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_service_time_total: self.open_path("blkio.io_service_time", false)
io_service_time_total: self
.open_path("blkio.io_service_time", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_service_time_recursive: self.open_path("blkio.io_service_time_recursive", false)
io_service_time_recursive: self
.open_path("blkio.io_service_time_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_service_time_recursive_total: self.open_path("blkio.io_service_time_recursive", false)
io_service_time_recursive_total: self
.open_path("blkio.io_service_time_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_wait_time: self.open_path("blkio.io_wait_time", false)
io_wait_time: self
.open_path("blkio.io_wait_time", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_wait_time_total: self.open_path("blkio.io_wait_time", false)
io_wait_time_total: self
.open_path("blkio.io_wait_time", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_wait_time_recursive: self.open_path("blkio.io_wait_time_recursive", false)
io_wait_time_recursive: self
.open_path("blkio.io_wait_time_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_wait_time_recursive_total: self.open_path("blkio.io_wait_time_recursive", false)
io_wait_time_recursive_total: self
.open_path("blkio.io_wait_time_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
leaf_weight: self.open_path("blkio.leaf_weight", false).and_then(|file| {
read_u64_from(file)
}).unwrap_or(0u64),
leaf_weight_device: self.open_path("blkio.leaf_weight_device", false).and_then(|file| {
read_string_from(file)
}).unwrap_or("".to_string()),
sectors: self.open_path("blkio.sectors", false).and_then(|file| {
read_string_from(file)
}).unwrap_or("".to_string()),
sectors_recursive: self.open_path("blkio.sectors_recursive", false).and_then(|file| {
read_string_from(file)
}).unwrap_or("".to_string()),
leaf_weight: self
.open_path("blkio.leaf_weight", false)
.and_then(|file| read_u64_from(file))
.unwrap_or(0u64),
leaf_weight_device: self
.open_path("blkio.leaf_weight_device", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
sectors: self
.open_path("blkio.sectors", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
sectors_recursive: self
.open_path("blkio.sectors_recursive", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
throttle: BlkIoThrottle {
io_service_bytes: self.open_path("blkio.throttle.io_service_bytes", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_service_bytes_total: self.open_path("blkio.throttle.io_service_bytes", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_service_bytes_recursive: self.open_path("blkio.throttle.io_service_bytes_recursive", false)
io_service_bytes: self
.open_path("blkio.throttle.io_service_bytes", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_service_bytes_recursive_total: self.open_path("blkio.throttle.io_service_bytes_recursive", false)
io_service_bytes_total: self
.open_path("blkio.throttle.io_service_bytes", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_serviced: self.open_path("blkio.throttle.io_serviced", false)
io_service_bytes_recursive: self
.open_path("blkio.throttle.io_service_bytes_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_serviced_total: self.open_path("blkio.throttle.io_serviced", false)
io_service_bytes_recursive_total: self
.open_path("blkio.throttle.io_service_bytes_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
io_serviced_recursive: self.open_path("blkio.throttle.io_serviced_recursive", false)
io_serviced: self
.open_path("blkio.throttle.io_serviced", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_serviced_recursive_total: self.open_path("blkio.throttle.io_serviced_recursive", false)
io_serviced_total: self
.open_path("blkio.throttle.io_serviced", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
read_bps_device: self.open_path("blkio.throttle.read_bps_device", false).and_then(|file| {
read_string_from(file)
}).unwrap_or("".to_string()),
read_iops_device: self.open_path("blkio.throttle.read_iops_device", false).and_then(|file| {
read_string_from(file)
}).unwrap_or("".to_string()),
write_bps_device: self.open_path("blkio.throttle.write_bps_device", false).and_then(|file| {
read_string_from(file)
}).unwrap_or("".to_string()),
write_iops_device: self.open_path("blkio.throttle.write_iops_device", false).and_then(|file| {
read_string_from(file)
}).unwrap_or("".to_string()),
io_serviced_recursive: self
.open_path("blkio.throttle.io_serviced_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service)
.unwrap_or(Vec::new()),
io_serviced_recursive_total: self
.open_path("blkio.throttle.io_serviced_recursive", false)
.and_then(read_string_from)
.and_then(parse_io_service_total)
.unwrap_or(0),
read_bps_device: self
.open_path("blkio.throttle.read_bps_device", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
read_iops_device: self
.open_path("blkio.throttle.read_iops_device", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
write_bps_device: self
.open_path("blkio.throttle.write_bps_device", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
write_iops_device: self
.open_path("blkio.throttle.write_iops_device", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
},
time: self.open_path("blkio.time", false)
time: self
.open_path("blkio.time", false)
.and_then(read_string_from)
.and_then(parse_blkio_data)
.unwrap_or(Vec::new()),
time_recursive: self.open_path("blkio.time_recursive", false)
time_recursive: self
.open_path("blkio.time_recursive", false)
.and_then(read_string_from)
.and_then(parse_blkio_data)
.unwrap_or(Vec::new()),
weight: self.open_path("blkio.weight", false).and_then(|file| {
read_u64_from(file)
}).unwrap_or(0u64),
weight_device: self.open_path("blkio.weight_device", false)
weight: self
.open_path("blkio.weight", false)
.and_then(|file| read_u64_from(file))
.unwrap_or(0u64),
weight_device: self
.open_path("blkio.weight_device", false)
.and_then(read_string_from)
.and_then(parse_blkio_data)
.unwrap_or(Vec::new()),
@@ -520,77 +570,116 @@ impl BlkIoController {
/// Set the leaf weight on the control group's tasks, i.e., how are they weighted against the
/// descendant control groups' tasks.
pub fn set_leaf_weight(&self, w: u64) -> Result<(), CgroupError> {
self.open_path("blkio.leaf_weight", true).and_then(|mut file| {
file.write_all(w.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("blkio.leaf_weight", true)
.and_then(|mut file| {
file.write_all(w.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Same as `set_leaf_weight()`, but settable per each block device.
pub fn set_leaf_weight_for_device(&self, d: String) -> Result<(), CgroupError> {
self.open_path("blkio.leaf_weight_device", true).and_then(|mut file| {
file.write_all(d.as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("blkio.leaf_weight_device", true)
.and_then(|mut file| file.write_all(d.as_ref()).map_err(CgroupError::WriteError))
}
/// Reset the statistics the kernel has gathered so far and start fresh.
pub fn reset_stats(&self) -> Result<(), CgroupError> {
self.open_path("blkio.leaf_weight_device", true).and_then(|mut file| {
file.write_all("1".to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("blkio.leaf_weight_device", true)
.and_then(|mut file| {
file.write_all("1".to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Throttle the bytes per second rate of read operation affecting the block device
/// `major:minor` to `bps`.
pub fn throttle_read_bps_for_device(&self, major: u64, minor: u64, bps: u64) -> Result<(), CgroupError> {
self.open_path("blkio.throttle.read_bps_device", true).and_then(|mut file| {
file.write_all(format!("{}:{} {}", major, minor, bps).to_string().as_ref()).map_err(CgroupError::WriteError)
})
pub fn throttle_read_bps_for_device(
&self,
major: u64,
minor: u64,
bps: u64,
) -> Result<(), CgroupError> {
self.open_path("blkio.throttle.read_bps_device", true)
.and_then(|mut file| {
file.write_all(format!("{}:{} {}", major, minor, bps).to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Throttle the I/O operations per second rate of read operation affecting the block device
/// `major:minor` to `bps`.
pub fn throttle_read_iops_for_device(&self, major: u64, minor: u64, iops: u64) -> Result<(), CgroupError> {
self.open_path("blkio.throttle.read_iops_device", true).and_then(|mut file| {
file.write_all(format!("{}:{} {}", major, minor, iops).to_string().as_ref()).map_err(CgroupError::WriteError)
})
pub fn throttle_read_iops_for_device(
&self,
major: u64,
minor: u64,
iops: u64,
) -> Result<(), CgroupError> {
self.open_path("blkio.throttle.read_iops_device", true)
.and_then(|mut file| {
file.write_all(format!("{}:{} {}", major, minor, iops).to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Throttle the bytes per second rate of write operation affecting the block device
/// `major:minor` to `bps`.
pub fn throttle_write_bps_for_device(&self, major: u64, minor: u64, bps: u64) -> Result<(), CgroupError> {
self.open_path("blkio.throttle.write_bps_device", true).and_then(|mut file| {
file.write_all(format!("{}:{} {}", major, minor, bps).to_string().as_ref()).map_err(CgroupError::WriteError)
})
pub fn throttle_write_bps_for_device(
&self,
major: u64,
minor: u64,
bps: u64,
) -> Result<(), CgroupError> {
self.open_path("blkio.throttle.write_bps_device", true)
.and_then(|mut file| {
file.write_all(format!("{}:{} {}", major, minor, bps).to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Throttle the I/O operations per second rate of write operation affecting the block device
/// `major:minor` to `bps`.
pub fn throttle_write_iops_for_device(&self, major: u64, minor: u64, iops: u64) -> Result<(), CgroupError> {
self.open_path("blkio.throttle.write_iops_device", true).and_then(|mut file| {
file.write_all(format!("{}:{} {}", major, minor, iops).to_string().as_ref()).map_err(CgroupError::WriteError)
})
pub fn throttle_write_iops_for_device(
&self,
major: u64,
minor: u64,
iops: u64,
) -> Result<(), CgroupError> {
self.open_path("blkio.throttle.write_iops_device", true)
.and_then(|mut file| {
file.write_all(format!("{}:{} {}", major, minor, iops).to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Set the weight of the control group's tasks.
pub fn set_weight(&self, w: u64) -> Result<(), CgroupError> {
self.open_path("blkio.leaf_weight", true).and_then(|mut file| {
file.write_all(w.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("blkio.leaf_weight", true)
.and_then(|mut file| {
file.write_all(w.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Same as `set_weight()`, but settable per each block device.
pub fn set_weight_for_device(&self, major: u64, minor: u64, weight: u64) -> Result<(), CgroupError> {
self.open_path("blkio.weight_device", true).and_then(|mut file| {
file.write_all(format!("{}:{} {}", major, minor, weight).as_ref())
.map_err(CgroupError::WriteError)
})
pub fn set_weight_for_device(
&self,
major: u64,
minor: u64,
weight: u64,
) -> Result<(), CgroupError> {
self.open_path("blkio.weight_device", true)
.and_then(|mut file| {
file.write_all(format!("{}:{} {}", major, minor, weight).as_ref())
.map_err(CgroupError::WriteError)
})
}
}
#[cfg(test)]
mod test {
use blkio::{IoService, parse_io_service, parse_io_service_total};
use blkio::{BlkIoData, parse_blkio_data};
use ::CgroupError;
use blkio::{parse_blkio_data, BlkIoData};
use blkio::{parse_io_service, parse_io_service_total, IoService};
use CgroupError;
const test_value: &str = "\
8:32 Read 4280320
@@ -645,75 +734,87 @@ Total 61823067136
#[test]
fn test_parse_io_service_total() {
assert_eq!(parse_io_service_total(test_value.to_string()), Ok(61823067136));
assert_eq!(
parse_io_service_total(test_value.to_string()),
Ok(61823067136)
);
}
#[test]
fn test_parse_io_service() {
assert_eq!(parse_io_service(test_value.to_string()), Ok(vec![
IoService {
major: 8,
minor: 32,
read: 4280320,
write: 0,
sync: 4280320,
async: 0,
total: 4280320,
},
IoService {
major: 8,
minor: 48,
read: 5705479168,
write: 56096055296,
sync: 11213923328,
async: 50587611136,
total: 61801534464,
},
IoService {
major: 8,
minor: 16,
read: 10059776,
write: 0,
sync: 10059776,
async: 0,
total: 10059776,
},
IoService {
major: 8,
minor: 0 ,
read: 7192576,
write: 0,
sync: 7192576,
async: 0,
total: 7192576,
}
]));
assert_eq!(parse_io_service(test_wrong_value.to_string()), Err(CgroupError::ParseError));
assert_eq!(
parse_io_service(test_value.to_string()),
Ok(vec![
IoService {
major: 8,
minor: 32,
read: 4280320,
write: 0,
sync: 4280320,
async: 0,
total: 4280320,
},
IoService {
major: 8,
minor: 48,
read: 5705479168,
write: 56096055296,
sync: 11213923328,
async: 50587611136,
total: 61801534464,
},
IoService {
major: 8,
minor: 16,
read: 10059776,
write: 0,
sync: 10059776,
async: 0,
total: 10059776,
},
IoService {
major: 8,
minor: 0,
read: 7192576,
write: 0,
sync: 7192576,
async: 0,
total: 7192576,
}
])
);
assert_eq!(
parse_io_service(test_wrong_value.to_string()),
Err(CgroupError::ParseError)
);
}
#[test]
fn test_parse_blkio_data() {
assert_eq!(parse_blkio_data(test_blkio_data.to_string()), Ok(vec![
BlkIoData {
major: 8,
minor: 48,
data: 454480833999,
},
BlkIoData {
major: 8,
minor: 32,
data: 228392923193,
},
BlkIoData {
major: 8,
minor: 16,
data: 772456885,
},
BlkIoData {
major: 8,
minor: 0,
data: 559583764,
}
]));
assert_eq!(
parse_blkio_data(test_blkio_data.to_string()),
Ok(vec![
BlkIoData {
major: 8,
minor: 48,
data: 454480833999,
},
BlkIoData {
major: 8,
minor: 32,
data: 228392923193,
},
BlkIoData {
major: 8,
minor: 16,
data: 772456885,
},
BlkIoData {
major: 8,
minor: 0,
data: 559583764,
}
])
);
}
}

View File

@@ -1,16 +1,15 @@
//! This module handles cgroup operations. Start here!
use {CgroupError, CgroupPid, Resources, ControllIdentifier, Controller, Hierarchy, Subsystem};
use {CgroupError, CgroupPid, ControllIdentifier, Controller, Hierarchy, Resources, Subsystem};
use std::convert::From;
/// A control group is the central structure to this crate.
///
///
/// # What are control groups?
///
/// Lifting over from the Linux kernel sources:
/// Lifting over from the Linux kernel sources:
///
/// > Control Groups provide a mechanism for aggregating/partitioning sets of
/// > tasks, and all their future children, into hierarchical groups with
@@ -26,7 +25,6 @@ pub struct Cgroup<'b> {
}
impl<'b> Cgroup<'b> {
/// Create this control group.
fn create(&self) {
for subsystem in &self.subsystems {
@@ -55,8 +53,11 @@ impl<'b> Cgroup<'b> {
/// destroyed.
pub fn load(hier: &Hierarchy, path: String) -> Cgroup {
let mut subsystems = hier.subsystems();
if path != "" {
subsystems = subsystems.into_iter().map(|x| x.enter(&path)).collect::<Vec<_>>();
if path != "" {
subsystems = subsystems
.into_iter()
.map(|x| x.enter(&path))
.collect::<Vec<_>>();
}
let cg = Cgroup {
@@ -79,28 +80,28 @@ impl<'b> Cgroup<'b> {
/// actually removed, and remove the descendants first if not. In the future, this behavior
/// will change.
pub fn delete(self) {
self.subsystems.into_iter().for_each(|sub| {
match sub {
Subsystem::Pid(pidc) => pidc.delete(),
Subsystem::Mem(c) => c.delete(),
Subsystem::CpuSet(c) => c.delete(),
Subsystem::CpuAcct(c) => c.delete(),
Subsystem::Cpu(c) => c.delete(),
Subsystem::Devices(c) => c.delete(),
Subsystem::Freezer(c) => c.delete(),
Subsystem::NetCls(c) => c.delete(),
Subsystem::BlkIo(c) => c.delete(),
Subsystem::PerfEvent(c) => c.delete(),
Subsystem::NetPrio(c) => c.delete(),
Subsystem::HugeTlb(c) => c.delete(),
Subsystem::Rdma(c) => c.delete(),
}
self.subsystems.into_iter().for_each(|sub| match sub {
Subsystem::Pid(pidc) => pidc.delete(),
Subsystem::Mem(c) => c.delete(),
Subsystem::CpuSet(c) => c.delete(),
Subsystem::CpuAcct(c) => c.delete(),
Subsystem::Cpu(c) => c.delete(),
Subsystem::Devices(c) => c.delete(),
Subsystem::Freezer(c) => c.delete(),
Subsystem::NetCls(c) => c.delete(),
Subsystem::BlkIo(c) => c.delete(),
Subsystem::PerfEvent(c) => c.delete(),
Subsystem::NetPrio(c) => c.delete(),
Subsystem::HugeTlb(c) => c.delete(),
Subsystem::Rdma(c) => c.delete(),
});
}
/// Apply a set of resource limits to the control group.
pub fn apply(&self, res: &Resources) -> Result<(), CgroupError> {
self.subsystems.iter().try_fold((), |_, e| e.to_controller().apply(res))
self.subsystems
.iter()
.try_fold((), |_, e| e.to_controller().apply(res))
}
/// Retrieve a container based on type inference.
@@ -114,8 +115,9 @@ impl<'b> Cgroup<'b> {
/// .expect("No cpu controller attached!");
/// ```
pub fn controller_of<'a, T>(self: &'a Self) -> Option<&'a T>
where &'a T: From<&'a Subsystem>,
T: Controller + ControllIdentifier,
where
&'a T: From<&'a Subsystem>,
T: Controller + ControllIdentifier,
{
for i in &self.subsystems {
if i.to_controller().control_type() == T::controller_type() {
@@ -139,19 +141,25 @@ impl<'b> Cgroup<'b> {
/// Attach a task to the control group.
pub fn add_task(&self, pid: CgroupPid) -> Result<(), CgroupError> {
self.subsystems().iter().try_for_each(|sub| sub.to_controller().add_task(&pid))
self.subsystems()
.iter()
.try_for_each(|sub| sub.to_controller().add_task(&pid))
}
/// Returns an Iterator that can be used to iterate over the tasks that are currently in the
/// control group.
pub fn tasks(&self) -> Vec<CgroupPid> {
/* Collect the tasks from all subsystems */
let mut v = self.subsystems().iter()
let mut v = self
.subsystems()
.iter()
.map(|x| x.to_controller().tasks())
.fold(vec![], |mut acc, mut x| { acc.append(&mut x); acc });
.fold(vec![], |mut acc, mut x| {
acc.append(&mut x);
acc
});
v.sort();
v.dedup();
v
}
}

View File

@@ -1,21 +1,23 @@
//! This module contains the implementation of the `cpu` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/scheduler/sched-design-CFS.txt](https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt)
//! paragraph 7 ("GROUP SCHEDULER EXTENSIONS TO CFS").
use std::path::PathBuf;
use std::io::{Read, Write};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use {CgroupError, CpuResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
use {
CgroupError, ControllIdentifier, Controller, Controllers, CpuResources, Resources, Subsystem,
};
/// A controller that allows controlling the `cpu` subsystem of a Cgroup.
///
///
/// In essence, it allows gathering information about how much the tasks inside the control group
/// are using the CPU and creating rules that limit their usage. Note that this crate does not yet
/// support managing realtime tasks.
#[derive(Debug, Clone)]
pub struct CpuController{
pub struct CpuController {
base: PathBuf,
path: PathBuf,
}
@@ -30,10 +32,18 @@ pub struct Cpu {
}
impl Controller for CpuController {
fn control_type(&self) -> Controllers { Controllers::Cpu}
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::Cpu
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, res: &Resources) -> Result<(), CgroupError> {
/* get the resources that apply to this controller */
@@ -74,7 +84,7 @@ impl<'a> From<&'a Subsystem> for &'a CpuController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -102,42 +112,46 @@ impl CpuController {
/// Returns CPU time statistics based on the processes in the control group.
pub fn cpu(&self) -> Cpu {
Cpu {
stat: self.open_path("cpu.stat", false).and_then(|mut file| {
let mut s = String::new();
let res = file.read_to_string(&mut s);
match res {
Ok(_) => Ok(s),
Err(e) => Err(CgroupError::ReadError(e)),
}
}).unwrap_or("".to_string()),
stat: self
.open_path("cpu.stat", false)
.and_then(|mut file| {
let mut s = String::new();
let res = file.read_to_string(&mut s);
match res {
Ok(_) => Ok(s),
Err(e) => Err(CgroupError::ReadError(e)),
}
}).unwrap_or("".to_string()),
}
}
/// Configures the CPU bandwidth (in relative relation to other control groups and this control
/// group's parent).
///
///
/// For example, setting control group `A`'s `shares` to `100`, and control group `B`'s
/// `shares` to `200` ensures that control group `B` receives twice as much as CPU bandwidth.
/// (Assuming both `A` and `B` are of the same parent)
pub fn set_shares(&self, shares: u64) -> Result<(), CgroupError> {
self.open_path("cpu.shares", true).and_then(|mut file| {
file.write_all(shares.to_string().as_ref()).map_err(CgroupError::WriteError)
file.write_all(shares.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Retrieve the CPU bandwidth that this control group (relative to other control groups and
/// this control group's parent) can use.
pub fn shares(&self) -> Result<u64, CgroupError> {
self.open_path("cpu.shares", false)
.and_then(read_u64_from)
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, us: u64) -> Result<(), CgroupError> {
self.open_path("cpu.cfs_period_us", true).and_then(|mut file| {
file.write_all(us.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("cpu.cfs_period_us", true)
.and_then(|mut file| {
file.write_all(us.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Retrieve the period of time of how often this cgroup's access to the CPU should be
@@ -150,11 +164,13 @@ impl CpuController {
/// Specify a quota (when using the CFS scheduler) of time in microseconds for which all tasks
/// in this control group can run during one period (see: `set_cfs_period()`).
pub fn set_cfs_quota(&self, us: u64) -> Result<(), CgroupError> {
self.open_path("cpu.cfs_quota_us", true).and_then(|mut file| {
file.write_all(us.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("cpu.cfs_quota_us", true)
.and_then(|mut file| {
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) -> Result<u64, CgroupError> {

View File

@@ -1,12 +1,12 @@
//! This module contains the implementation of the `cpuacct` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroup-v1/cpuacct.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt)
use std::path::PathBuf;
use std::io::{Read, Write};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use {CgroupError, Controllers, Resources, Subsystem, ControllIdentifier, Controller};
use {CgroupError, ControllIdentifier, Controller, Controllers, Resources, Subsystem};
/// A controller that allows controlling the `cpuacct` subsystem of a Cgroup.
///
@@ -50,10 +50,18 @@ pub struct CpuAcct {
}
impl Controller for CpuAcctController {
fn control_type(&self) -> Controllers { Controllers::CpuAcct }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::CpuAcct
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, _res: &Resources) -> Result<(), CgroupError> {
Ok(())
@@ -74,7 +82,7 @@ impl<'a> From<&'a Subsystem> for &'a CpuAcctController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -101,7 +109,6 @@ fn read_string_from(mut file: File) -> Result<String, CgroupError> {
}
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;
@@ -115,32 +122,44 @@ impl CpuAcctController {
/// Gathers the statistics that are available in the control group into a `CpuAcct` structure.
pub fn cpuacct(&self) -> CpuAcct {
CpuAcct {
stat: self.open_path("cpuacct.stat", false)
.and_then(|file| read_string_from(file)).unwrap_or("".to_string()),
usage: self.open_path("cpuacct.usage", false)
.and_then(|file| read_u64_from(file))
.unwrap_or(0),
usage_all: self.open_path("cpuacct.usage_all", false)
.and_then(|file| read_string_from(file)).unwrap_or("".to_string()),
usage_percpu: self.open_path("cpuacct.usage_percpu", false)
.and_then(|file| read_string_from(file)).unwrap_or("".to_string()),
usage_percpu_sys: self.open_path("cpuacct.usage_percpu_sys", false)
.and_then(|file| read_string_from(file)).unwrap_or("".to_string()),
usage_percpu_user: self.open_path("cpuacct.usage_percpu_user", false)
.and_then(|file| read_string_from(file)).unwrap_or("".to_string()),
usage_sys: self.open_path("cpuacct.usage_sys", false)
.and_then(|file| read_u64_from(file))
.unwrap_or(0),
usage_user: self.open_path("cpuacct.usage_user", false)
.and_then(|file| read_u64_from(file))
.unwrap_or(0),
stat: self
.open_path("cpuacct.stat", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
usage: self
.open_path("cpuacct.usage", false)
.and_then(|file| read_u64_from(file))
.unwrap_or(0),
usage_all: self
.open_path("cpuacct.usage_all", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
usage_percpu: self
.open_path("cpuacct.usage_percpu", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
usage_percpu_sys: self
.open_path("cpuacct.usage_percpu_sys", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
usage_percpu_user: self
.open_path("cpuacct.usage_percpu_user", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
usage_sys: self
.open_path("cpuacct.usage_sys", false)
.and_then(|file| read_u64_from(file))
.unwrap_or(0),
usage_user: self
.open_path("cpuacct.usage_user", false)
.and_then(|file| read_u64_from(file))
.unwrap_or(0),
}
}
/// Reset the statistics the kernel has gathered about the control group.
pub fn reset(&self) -> Result<(), CgroupError> {
self.open_path("cpuacct.usage", true).and_then(|mut file| {
file.write_all(b"0").map_err(CgroupError::WriteError)
})
self.open_path("cpuacct.usage", true)
.and_then(|mut file| file.write_all(b"0").map_err(CgroupError::WriteError))
}
}

View File

@@ -1,16 +1,18 @@
//! This module contains the implementation of the `cpuset` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroup-v1/cpusets.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt)
use std::path::PathBuf;
use std::io::{Read, Write};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use {CgroupError, CpuResources, Resources, Controller, ControllIdentifier, Subsystem, Controllers};
use CgroupError::*;
use {
CgroupError, ControllIdentifier, Controller, Controllers, CpuResources, Resources, Subsystem,
};
/// A controller that allows controlling the `cpuset` subsystem of a Cgroup.
///
///
/// In essence, this controller is responsible for restricting the tasks in the control group to a
/// set of CPUs and/or memory nodes.
#[derive(Debug, Clone)]
@@ -50,11 +52,11 @@ pub struct CpuSet {
/// the memory pressure for control groups or not.
pub memory_pressure_enabled: Option<bool>,
/// If true, filesystem buffers are spread across evenly between the nodes specified in `mems`.
pub memory_spread_page: bool,
pub memory_spread_page: bool,
/// If true, kernel slab caches for file I/O are spread across evenly between the nodes
/// specified in `mems`.
pub memory_spread_slab: bool,
/// The list of memory nodes the tasks of the control group can use.
pub memory_spread_slab: bool,
/// The list of memory nodes the tasks of the control group can use.
///
/// The format is the same as the `cpus`, `effective_cpus` and `effective_mems` fields.
pub mems: Vec<(u64, u64)>,
@@ -73,14 +75,21 @@ pub struct CpuSet {
/// | 5 | Immediately balance the load between CPUs even if the system is NUMA |
/// | 6 | Immediately balance the load between all CPUs |
pub sched_relax_domain_level: u64,
}
impl Controller for CpuSetController {
fn control_type(&self) -> Controllers { Controllers::CpuSet }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::CpuSet
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, res: &Resources) -> Result<(), CgroupError> {
/* get the resources that apply to this controller */
@@ -109,7 +118,7 @@ impl<'a> From<&'a Subsystem> for &'a CpuSetController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -184,13 +193,16 @@ impl CpuSetController {
pub fn cpuset(&self) -> CpuSet {
CpuSet {
cpu_exclusive: {
self.open_path("cpuset.cpu_exclusive", false).and_then(|file| {
read_u64_from(file)
}).map(|x| x == 1).unwrap_or(false)
self.open_path("cpuset.cpu_exclusive", false)
.and_then(|file| read_u64_from(file))
.map(|x| x == 1)
.unwrap_or(false)
},
cpus: {
self.open_path("cpuset.cpus", false).and_then(read_string_from)
.and_then(parse_range).unwrap_or(Vec::new())
self.open_path("cpuset.cpus", false)
.and_then(read_string_from)
.and_then(parse_range)
.unwrap_or(Vec::new())
},
effective_cpus: {
self.open_path("cpuset.effective_cpus", false)
@@ -205,31 +217,45 @@ impl CpuSetController {
.unwrap_or(Vec::new())
},
mem_exclusive: {
self.open_path("cpuset.mem_exclusive", false).and_then(read_u64_from)
.map(|x| x == 1).unwrap_or(false)
self.open_path("cpuset.mem_exclusive", false)
.and_then(read_u64_from)
.map(|x| x == 1)
.unwrap_or(false)
},
mem_hardwall: {
self.open_path("cpuset.mem_hardwall", false).and_then(read_u64_from)
.map(|x| x == 1).unwrap_or(false)
self.open_path("cpuset.mem_hardwall", false)
.and_then(read_u64_from)
.map(|x| x == 1)
.unwrap_or(false)
},
memory_migrate: {
self.open_path("cpuset.memory_migrate", false).and_then(read_u64_from)
.map(|x| x == 1).unwrap_or(false)
self.open_path("cpuset.memory_migrate", false)
.and_then(read_u64_from)
.map(|x| x == 1)
.unwrap_or(false)
},
memory_pressure: {
self.open_path("cpuset.memory_pressure", false).and_then(read_u64_from).unwrap_or(0)
self.open_path("cpuset.memory_pressure", false)
.and_then(read_u64_from)
.unwrap_or(0)
},
memory_pressure_enabled: {
self.open_path("cpuset.memory_pressure_enabled", false).and_then(read_u64_from)
.map(|x| x == 1).ok()
self.open_path("cpuset.memory_pressure_enabled", false)
.and_then(read_u64_from)
.map(|x| x == 1)
.ok()
},
memory_spread_page: {
self.open_path("cpuset.memory_spread_page", false).and_then(read_u64_from)
.map(|x| x == 1).unwrap_or(false)
self.open_path("cpuset.memory_spread_page", false)
.and_then(read_u64_from)
.map(|x| x == 1)
.unwrap_or(false)
},
memory_spread_slab: {
self.open_path("cpuset.memory_spread_slab", false).and_then(read_u64_from)
.map(|x| x == 1).unwrap_or(false)
self.open_path("cpuset.memory_spread_slab", false)
.and_then(read_u64_from)
.map(|x| x == 1)
.unwrap_or(false)
},
mems: {
self.open_path("cpuset.mems", false)
@@ -238,11 +264,14 @@ impl CpuSetController {
.unwrap_or(Vec::new())
},
sched_load_balance: {
self.open_path("cpuset.sched_load_balance", false).and_then(read_u64_from)
.map(|x| x == 1).unwrap_or(false)
self.open_path("cpuset.sched_load_balance", false)
.and_then(read_u64_from)
.map(|x| x == 1)
.unwrap_or(false)
},
sched_relax_domain_level: {
self.open_path("cpuset.sched_relax_domain_level", false).and_then(read_u64_from)
self.open_path("cpuset.sched_relax_domain_level", false)
.and_then(read_u64_from)
.unwrap_or(0)
},
}
@@ -251,25 +280,27 @@ impl CpuSetController {
/// Control whether the CPUs selected via `set_cpus()` should be exclusive to this control
/// group or not.
pub fn set_cpu_exclusive(&self, b: bool) -> Result<(), CgroupError> {
self.open_path("cpuset.cpu_exclusive", true).and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
self.open_path("cpuset.cpu_exclusive", true)
.and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
}
/// Control whether the memory nodes selected via `set_memss()` should be exclusive to this control
/// group or not.
pub fn set_mem_exclusive(&self, b: bool) -> Result<(), CgroupError> {
self.open_path("cpuset.mem_exclusive", true).and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
self.open_path("cpuset.mem_exclusive", true)
.and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
}
/// Set the CPUs that the tasks in this control group can run on.
@@ -278,7 +309,8 @@ impl CpuSetController {
/// be represented via dashes.
pub fn set_cpus(&self, cpus: &String) -> Result<(), CgroupError> {
self.open_path("cpuset.cpus", true).and_then(|mut file| {
file.write_all(cpus.as_ref()).map_err(CgroupError::WriteError)
file.write_all(cpus.as_ref())
.map_err(CgroupError::WriteError)
})
}
@@ -287,7 +319,8 @@ impl CpuSetController {
/// Syntax is the same as with `set_cpus()`.
pub fn set_mems(&self, mems: &String) -> Result<(), CgroupError> {
self.open_path("cpuset.mems", true).and_then(|mut file| {
file.write_all(mems.as_ref()).map_err(CgroupError::WriteError)
file.write_all(mems.as_ref())
.map_err(CgroupError::WriteError)
})
}
@@ -297,70 +330,77 @@ impl CpuSetController {
/// Note that some kernel allocations, most notably those that are made in interrupt handlers
/// may disregard this.
pub fn set_hardwall(&self, b: bool) -> Result<(), CgroupError> {
self.open_path("cpuset.mem_hardwall", true).and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
self.open_path("cpuset.mem_hardwall", true)
.and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
}
/// Controls whether the kernel should attempt to rebalance the load between the CPUs specified in the
/// `cpus` field of this control group.
pub fn set_load_balancing(&self, b: bool) -> Result<(), CgroupError> {
self.open_path("cpuset.sched_load_balance", true).and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
self.open_path("cpuset.sched_load_balance", true)
.and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
}
/// Contorl how much effort the kernel should invest in rebalacing the control group.
///
/// See @CpuSet 's similar field for more information.
pub fn set_rebalance_relax_domain_level(&self, i: i64) -> Result<(), CgroupError> {
self.open_path("cpuset.sched_relax_domain_level", true).and_then(|mut file| {
file.write_all(i.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("cpuset.sched_relax_domain_level", true)
.and_then(|mut file| {
file.write_all(i.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Control whether when using `set_mems()` the existing memory used by the tasks should be
/// migrated over to the now-selected nodes.
pub fn set_memory_migration(&self, b: bool) -> Result<(), CgroupError> {
self.open_path("cpuset.memory_migrate", true).and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
self.open_path("cpuset.memory_migrate", true)
.and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
}
/// Control whether filesystem buffers should be evenly split across the nodes selected via
/// `set_mems()`.
pub fn set_memory_spread_page(&self, b: bool) -> Result<(), CgroupError> {
self.open_path("cpuset.memory_spread_page", true).and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
self.open_path("cpuset.memory_spread_page", true)
.and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
}
/// Control whether the kernel's slab cache for file I/O should be evenly split across the
/// nodes selected via `set_mems()`.
pub fn set_memory_spread_slab(&self, b: bool) -> Result<(), CgroupError> {
self.open_path("cpuset.memory_spread_slab", true).and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
self.open_path("cpuset.memory_spread_slab", true)
.and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
}
/// Control whether the kernel should collect information to calculate memory pressure for
@@ -372,13 +412,14 @@ impl CpuSetController {
if !self.path_exists("cpuset.memory_pressure_enabled") {
return Err(CgroupError::InvalidOperation);
}
self.open_path("cpuset.memory_pressure_enabled", true).and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
self.open_path("cpuset.memory_pressure_enabled", true)
.and_then(|mut file| {
if b {
file.write_all(b"1").map_err(CgroupError::WriteError)
} else {
file.write_all(b"0").map_err(CgroupError::WriteError)
}
})
}
}
@@ -387,20 +428,22 @@ mod tests {
use cpuset;
#[test]
fn test_parse_range() {
let test_cases = vec!["1,2,4-6,9".to_string(),
"".to_string(),
"1".to_string(),
"1-111".to_string(),
"1,2,3,4".to_string(),
"1-5,6-7,8-9".to_string()
];
let expecteds = vec![vec![(1, 1), (2, 2), (4, 6), (9, 9)],
vec![],
vec![(1, 1)],
vec![(1, 111)],
vec![(1, 1), (2, 2), (3, 3), (4, 4)],
vec![(1, 5), (6, 7), (8, 9)]
];
let test_cases = vec![
"1,2,4-6,9".to_string(),
"".to_string(),
"1".to_string(),
"1-111".to_string(),
"1,2,3,4".to_string(),
"1-5,6-7,8-9".to_string(),
];
let expecteds = vec![
vec![(1, 1), (2, 2), (4, 6), (9, 9)],
vec![],
vec![(1, 1)],
vec![(1, 111)],
vec![(1, 1), (2, 2), (3, 3), (4, 4)],
vec![(1, 5), (6, 7), (8, 9)],
];
for (i, case) in test_cases.into_iter().enumerate() {
let range = cpuset::parse_range(case.clone());

View File

@@ -1,18 +1,21 @@
//! This module contains the implementation of the `devices` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroup-v1/devices.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/devices.txt)
use std::path::PathBuf;
use std::io::{Read, Write};
use std::path::PathBuf;
use {DeviceResource, CgroupError, DeviceResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
use {
CgroupError, ControllIdentifier, Controller, Controllers, DeviceResource, DeviceResources,
Resources, Subsystem,
};
/// A controller that allows controlling the `devices` subsystem of a Cgroup.
///
/// In essence, using the devices controller, it is possible to allow or disallow sets of devices to
/// be used by the control group's tasks.
#[derive(Debug, Clone)]
pub struct DevicesController{
pub struct DevicesController {
base: PathBuf,
path: PathBuf,
}
@@ -29,7 +32,9 @@ pub enum DeviceType {
}
impl Default for DeviceType {
fn default() -> Self { DeviceType::All }
fn default() -> Self {
DeviceType::All
}
}
impl DeviceType {
@@ -124,10 +129,18 @@ impl DevicePermissions {
}
impl Controller for DevicesController {
fn control_type(&self) -> Controllers { Controllers::Devices }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::Devices
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, res: &Resources) -> Result<(), CgroupError> {
/* get the resources that apply to this controller */
@@ -161,7 +174,7 @@ impl<'a> From<&'a Subsystem> for &'a DevicesController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -182,13 +195,31 @@ impl DevicesController {
///
/// When `-1` is passed as `major` or `minor`, the kernel interprets that value as "any",
/// meaning that it will match any device.
pub fn allow_device(&self, devtype: DeviceType, major: i64, minor: i64, perm: &Vec<DevicePermissions>) -> Result<(), CgroupError> {
let perms = perm.iter().map(DevicePermissions::to_char).collect::<String>();
let minor = if minor == -1 { "*".to_string() } else { format!("{}", minor) };
let major = if major == -1 { "*".to_string() } else { format!("{}", major) };
pub fn allow_device(
&self,
devtype: DeviceType,
major: i64,
minor: i64,
perm: &Vec<DevicePermissions>,
) -> Result<(), CgroupError> {
let perms = perm
.iter()
.map(DevicePermissions::to_char)
.collect::<String>();
let minor = if minor == -1 {
"*".to_string()
} else {
format!("{}", minor)
};
let major = if major == -1 {
"*".to_string()
} else {
format!("{}", major)
};
let final_str = format!("{} {}:{} {}", devtype.to_char(), major, minor, perms);
self.open_path("devices.allow", true).and_then(|mut file| {
file.write_all(final_str.as_ref()).map_err(CgroupError::WriteError)
file.write_all(final_str.as_ref())
.map_err(CgroupError::WriteError)
})
}
@@ -196,13 +227,31 @@ impl DevicesController {
///
/// When `-1` is passed as `major` or `minor`, the kernel interprets that value as "any",
/// meaning that it will match any device.
pub fn deny_device(&self, devtype: DeviceType, major: i64, minor: i64, perm: &Vec<DevicePermissions>) -> Result<(), CgroupError> {
let perms = perm.iter().map(DevicePermissions::to_char).collect::<String>();
let minor = if minor == -1 { "*".to_string() } else { format!("{}", minor) };
let major = if major == -1 { "*".to_string() } else { format!("{}", major) };
pub fn deny_device(
&self,
devtype: DeviceType,
major: i64,
minor: i64,
perm: &Vec<DevicePermissions>,
) -> Result<(), CgroupError> {
let perms = perm
.iter()
.map(DevicePermissions::to_char)
.collect::<String>();
let minor = if minor == -1 {
"*".to_string()
} else {
format!("{}", minor)
};
let major = if major == -1 {
"*".to_string()
} else {
format!("{}", major)
};
let final_str = format!("{} {}:{} {}", devtype.to_char(), major, minor, perms);
self.open_path("devices.deny", true).and_then(|mut file| {
file.write_all(final_str.as_ref()).map_err(CgroupError::WriteError)
file.write_all(final_str.as_ref())
.map_err(CgroupError::WriteError)
})
}

View File

@@ -1,11 +1,11 @@
//! This module contains the implementation of the `freezer` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroup-v1/freezer-subsystem.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt)
use std::path::PathBuf;
use std::io::{Read, Write};
use std::path::PathBuf;
use {CgroupError, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
use {CgroupError, ControllIdentifier, Controller, Controllers, Resources, Subsystem};
/// A controller that allows controlling the `freezer` subsystem of a Cgroup.
///
@@ -16,7 +16,7 @@ use {CgroupError, Controllers, Controller, Resources, ControllIdentifier, Subsys
/// Note that if the control group is currently in the `Frozen` or `Freezing` state, then no
/// processes can be added to it.
#[derive(Debug, Clone)]
pub struct FreezerController{
pub struct FreezerController {
base: PathBuf,
path: PathBuf,
}
@@ -32,10 +32,18 @@ pub enum FreezerState {
}
impl Controller for FreezerController {
fn control_type(&self) -> Controllers { Controllers::Freezer }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::Freezer
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, _res: &Resources) -> Result<(), CgroupError> {
Ok(())
@@ -56,7 +64,7 @@ impl<'a> From<&'a Subsystem> for &'a FreezerController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -76,14 +84,16 @@ impl FreezerController {
/// Freezes the processes in the control group.
pub fn freeze(&self) -> Result<(), CgroupError> {
self.open_path("freezer.state", true).and_then(|mut file| {
file.write_all("FROZEN".to_string().as_ref()).map_err(CgroupError::WriteError)
file.write_all("FROZEN".to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Thaws, that is, unfreezes the processes in the control group.
pub fn thaw(&self) -> Result<(), CgroupError> {
self.open_path("freezer.state", true).and_then(|mut file| {
file.write_all("THAWED".to_string().as_ref()).map_err(CgroupError::WriteError)
file.write_all("THAWED".to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}

View File

@@ -3,28 +3,27 @@
//! Currently, we only support the cgroupv1 hierarchy, but in the future we will add support for
//! the Unified Hierarchy.
use std::fs::File;
use std::io::BufRead;
use std::io::BufReader;
use std::fs::File;
use std::path::{Path, PathBuf};
use blkio::BlkIoController;
use cpu::CpuController;
use cpuacct::CpuAcctController;
use cpuset::CpuSetController;
use devices::DevicesController;
use freezer::FreezerController;
use hugetlb::HugeTlbController;
use memory::MemController;
use net_cls::NetClsController;
use net_prio::NetPrioController;
use perf_event::PerfEventController;
use pid::PidController;
use rdma::RdmaController;
use {Controllers, Hierarchy, Subsystem};
use ::pid::PidController;
use ::memory::MemController;
use ::cpuset::CpuSetController;
use ::cpuacct::CpuAcctController;
use ::cpu::CpuController;
use ::freezer::FreezerController;
use ::devices::DevicesController;
use ::net_cls::NetClsController;
use ::blkio::BlkIoController;
use ::perf_event::PerfEventController;
use ::net_prio::NetPrioController;
use ::hugetlb::HugeTlbController;
use ::rdma::RdmaController;
use ::cgroup::Cgroup;
use cgroup::Cgroup;
/// The standard, original cgroup implementation. Often referred to as "cgroupv1".
pub struct V1 {

View File

@@ -1,14 +1,16 @@
//! This module contains the implementation of the `hugetlb` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroup-v1/hugetlb.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/hugetlb.txt)
use std::path::PathBuf;
use std::fs::File;
use std::io::{Write, Read};
use std::io::{Read, Write};
use std::path::PathBuf;
use {CgroupError, HugePageResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
use CgroupError::*;
use {
CgroupError, ControllIdentifier, Controller, Controllers, HugePageResources, Resources,
Subsystem,
};
/// A controller that allows controlling the `hugetlb` subsystem of a Cgroup.
///
@@ -21,10 +23,18 @@ pub struct HugeTlbController {
}
impl Controller for HugeTlbController {
fn control_type(&self) -> Controllers { Controllers::HugeTlb }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::HugeTlb
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, res: &Resources) -> Result<(), CgroupError> {
/* get the resources that apply to this controller */
@@ -56,7 +66,7 @@ impl<'a> From<&'a Subsystem> for &'a HugeTlbController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -110,8 +120,10 @@ impl HugeTlbController {
/// Get the maximum observed usage of memory that is backed by hugepages of a certain size
/// (`hugetlb_size`).
pub fn max_usage_in_bytes(&self, hugetlb_size: &String) -> Result<u64, CgroupError> {
self.open_path(&format!("hugetlb.{}.max_usage_in_bytes", hugetlb_size), false)
.and_then(read_u64_from)
self.open_path(
&format!("hugetlb.{}.max_usage_in_bytes", hugetlb_size),
false,
).and_then(read_u64_from)
}
/// Set the limit (in bytes) of how much memory can be backed by hugepages of a certain size
@@ -119,7 +131,8 @@ impl HugeTlbController {
pub fn set_limit_in_bytes(&self, hugetlb_size: &String, limit: u64) -> Result<(), CgroupError> {
self.open_path(&format!("hugetlb.{}.limit_in_bytes", hugetlb_size), false)
.and_then(|mut file| {
file.write_all(limit.to_string().as_ref()).map_err(CgroupError::WriteError)
file.write_all(limit.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
}

View File

@@ -1,35 +1,35 @@
use std::path::PathBuf;
use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::path::PathBuf;
pub mod hierarchies;
pub mod pid;
pub mod memory;
pub mod cpuset;
pub mod cpuacct;
pub mod cpu;
pub mod devices;
pub mod cgroup;
pub mod freezer;
pub mod net_cls;
pub mod blkio;
pub mod perf_event;
pub mod net_prio;
pub mod cgroup;
pub mod cpu;
pub mod cpuacct;
pub mod cpuset;
pub mod devices;
pub mod freezer;
pub mod hierarchies;
pub mod hugetlb;
pub mod memory;
pub mod net_cls;
pub mod net_prio;
pub mod perf_event;
pub mod pid;
pub mod rdma;
use pid::PidController;
use memory::MemController;
use cpuset::CpuSetController;
use cpuacct::CpuAcctController;
use cpu::CpuController;
use freezer::FreezerController;
use devices::DevicesController;
use net_cls::NetClsController;
use blkio::BlkIoController;
use perf_event::PerfEventController;
use net_prio::NetPrioController;
use cpu::CpuController;
use cpuacct::CpuAcctController;
use cpuset::CpuSetController;
use devices::DevicesController;
use freezer::FreezerController;
use hugetlb::HugeTlbController;
use memory::MemController;
use net_cls::NetClsController;
use net_prio::NetPrioController;
use perf_event::PerfEventController;
use pid::PidController;
use rdma::RdmaController;
pub use cgroup::Cgroup;
@@ -95,22 +95,34 @@ impl PartialEq for CgroupError {
match self {
CgroupError::WriteError(_) => if let CgroupError::WriteError(_) = other {
return true;
} else { return false },
} else {
return false;
},
CgroupError::ReadError(_) => if let CgroupError::ReadError(_) = other {
return true;
} else { return false },
} else {
return false;
},
CgroupError::ParseError => if let CgroupError::ParseError = other {
return true;
} else { return false },
} else {
return false;
},
CgroupError::InvalidOperation => if let CgroupError::InvalidOperation = other {
return true;
} else { return false },
} else {
return false;
},
CgroupError::InvalidPath => if let CgroupError::InvalidPath = other {
return true;
} else { return false },
} else {
return false;
},
CgroupError::Unknown => if let CgroupError::Unknown = other {
return true;
} else { return false },
} else {
return false;
},
}
}
}
@@ -232,23 +244,25 @@ pub trait Controller {
/// Attach a task to this controller.
fn add_task(&self, pid: &CgroupPid) -> Result<(), CgroupError> {
self.open_path("tasks", true).and_then(|mut file| {
file.write_all(pid.pid.to_string().as_ref()).map_err(CgroupError::WriteError)
file.write_all(pid.pid.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Get the list of tasks that this controller has.
fn tasks(&self) -> Vec<CgroupPid> {
self.open_path("tasks", false).and_then(|file| {
let bf = BufReader::new(file);
let mut v = Vec::new();
for line in bf.lines() {
if let Ok(line) = line {
let n = line.trim().parse().unwrap_or(0u64);
v.push(n);
self.open_path("tasks", false)
.and_then(|file| {
let bf = BufReader::new(file);
let mut v = Vec::new();
for line in bf.lines() {
if let Ok(line) = line {
let n = line.trim().parse().unwrap_or(0u64);
v.push(n);
}
}
}
Ok(v.into_iter().map(CgroupPid::from).collect())
}).unwrap_or(vec![])
Ok(v.into_iter().map(CgroupPid::from).collect())
}).unwrap_or(vec![])
}
}
@@ -479,21 +493,16 @@ pub struct CgroupPid {
impl From<u64> for CgroupPid {
fn from(u: u64) -> CgroupPid {
CgroupPid {
pid: u,
}
CgroupPid { pid: u }
}
}
impl<'a> From<&'a std::process::Child> for CgroupPid {
fn from(u: &std::process::Child) -> CgroupPid {
CgroupPid {
pid: u.id() as u64,
}
CgroupPid { pid: u.id() as u64 }
}
}
impl Subsystem {
fn enter(self, path: &String) -> Self {
match self {

View File

@@ -1,13 +1,15 @@
//! This module contains the implementation of the `memory` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroup-v1/memory.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt)
use std::path::PathBuf;
use std::io::{Write, Read};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use {CgroupError, Resources, MemoryResources, Controller, Controllers, Subsystem, ControllIdentifier};
use CgroupError::*;
use {
CgroupError, ControllIdentifier, Controller, Controllers, MemoryResources, Resources, Subsystem,
};
/// A controller that allows controlling the `memory` subsystem of a Cgroup.
///
@@ -15,7 +17,7 @@ use CgroupError::*;
/// of the tasks in the control group. Additonally, one can also set powerful limits on their
/// memory usage.
#[derive(Debug, Clone)]
pub struct MemController{
pub struct MemController {
base: PathBuf,
path: PathBuf,
}
@@ -83,55 +85,127 @@ fn parse_numa_stat(s: String) -> Result<NumaStat, CgroupError> {
// Parse the number of nodes
let nodes = (s.split_whitespace().collect::<Vec<_>>().len() - 8) / 8;
let mut ls = s.lines();
let total_line = ls.next().unwrap();
let file_line = ls.next().unwrap();
let anon_line = ls.next().unwrap();
let total_line = ls.next().unwrap();
let file_line = ls.next().unwrap();
let anon_line = ls.next().unwrap();
let unevict_line = ls.next().unwrap();
let hier_total_line = ls.next().unwrap();
let hier_file_line = ls.next().unwrap();
let hier_anon_line = ls.next().unwrap();
let hier_total_line = ls.next().unwrap();
let hier_file_line = ls.next().unwrap();
let hier_anon_line = ls.next().unwrap();
let hier_unevict_line = ls.next().unwrap();
Ok(NumaStat {
total_pages: total_line.split(|x| x == ' ' || x == '=').collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0),
total_pages: total_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
total_pages_per_node: {
let spl = &total_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter().map(|x| x.split("=").collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0)).collect()
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
}).collect()
},
file_pages: file_line.split(|x| x == ' ' || x == '=').collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0),
file_pages: file_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
file_pages_per_node: {
let spl = &file_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter().map(|x| x.split("=").collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0)).collect()
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
}).collect()
},
anon_pages: anon_line.split(|x| x == ' ' || x == '=').collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0),
anon_pages: anon_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
anon_pages_per_node: {
let spl = &anon_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter().map(|x| x.split("=").collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0)).collect()
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
}).collect()
},
unevictable_pages: unevict_line.split(|x| x == ' ' || x == '=').collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0),
unevictable_pages: unevict_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
unevictable_pages_per_node: {
let spl = &unevict_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter().map(|x| x.split("=").collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0)).collect()
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
}).collect()
},
hierarchical_total_pages: hier_total_line.split(|x| x == ' ' || x == '=').collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0),
hierarchical_total_pages: hier_total_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
hierarchical_total_pages_per_node: {
let spl = &hier_total_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter().map(|x| x.split("=").collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0)).collect()
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
}).collect()
},
hierarchical_file_pages: hier_file_line.split(|x| x == ' ' || x == '=').collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0),
hierarchical_file_pages: hier_file_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
hierarchical_file_pages_per_node: {
let spl = &hier_file_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter().map(|x| x.split("=").collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0)).collect()
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
}).collect()
},
hierarchical_anon_pages: hier_anon_line.split(|x| x == ' ' || x == '=').collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0),
hierarchical_anon_pages: hier_anon_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
hierarchical_anon_pages_per_node: {
let spl = &hier_anon_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter().map(|x| x.split("=").collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0)).collect()
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
}).collect()
},
hierarchical_unevictable_pages: hier_unevict_line.split(|x| x == ' ' || x == '=').collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0),
hierarchical_unevictable_pages: hier_unevict_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
hierarchical_unevictable_pages_per_node: {
let spl = &hier_unevict_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter().map(|x| x.split("=").collect::<Vec<_>>()[1].parse::<u64>().unwrap_or(0)).collect()
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
}).collect()
},
})
}
@@ -177,9 +251,10 @@ pub struct MemoryStat {
}
fn parse_memory_stat(s: String) -> Result<MemoryStat, CgroupError> {
let sp: Vec<&str> = s.split_whitespace()
.filter(|x| x.parse::<u64>().is_ok())
.collect();
let sp: Vec<&str> = s
.split_whitespace()
.filter(|x| x.parse::<u64>().is_ok())
.collect();
let mut spl = sp.iter();
Ok(MemoryStat {
@@ -317,10 +392,18 @@ pub struct Kmem {
}
impl Controller for MemController {
fn control_type(&self) -> Controllers { Controllers::Mem }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::Mem
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, res: &Resources) -> Result<(), CgroupError> {
/* get the resources that apply to this controller */
@@ -357,53 +440,79 @@ impl MemController {
/// kernel Documentation and/or sources.
pub fn memory_stat(&self) -> Memory {
Memory {
fail_cnt: self.open_path("memory.failcnt", false)
.and_then(read_u64_from).unwrap_or(0),
limit_in_bytes: self.open_path("memory.limit_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
usage_in_bytes: self.open_path("memory.usage_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
max_usage_in_bytes: self.open_path("memory.max_usage_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
move_charge_at_immigrate: self.open_path("memory.move_charge_at_immigrate", false)
.and_then(read_u64_from).unwrap_or(0),
numa_stat: self.open_path("memory.numa_stat", false)
.and_then(read_string_from)
.and_then(parse_numa_stat)
.unwrap_or(NumaStat::default()),
oom_control: self.open_path("memory.oom_control", false)
.and_then(read_string_from)
.and_then(parse_oom_control)
.unwrap_or(OomControl::default()),
soft_limit_in_bytes: self.open_path("memory.soft_limit_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
stat: self.open_path("memory.stat", false)
.and_then(read_string_from)
.and_then(parse_memory_stat)
.unwrap_or(MemoryStat::default()),
swappiness: self.open_path("memory.swappiness", false)
.and_then(read_u64_from)
.unwrap_or(0),
use_hierarchy: self.open_path("memory.use_hierarchy", false)
.and_then(read_u64_from)
.unwrap_or(0)
fail_cnt: self
.open_path("memory.failcnt", false)
.and_then(read_u64_from)
.unwrap_or(0),
limit_in_bytes: self
.open_path("memory.limit_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
usage_in_bytes: self
.open_path("memory.usage_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
max_usage_in_bytes: self
.open_path("memory.max_usage_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
move_charge_at_immigrate: self
.open_path("memory.move_charge_at_immigrate", false)
.and_then(read_u64_from)
.unwrap_or(0),
numa_stat: self
.open_path("memory.numa_stat", false)
.and_then(read_string_from)
.and_then(parse_numa_stat)
.unwrap_or(NumaStat::default()),
oom_control: self
.open_path("memory.oom_control", false)
.and_then(read_string_from)
.and_then(parse_oom_control)
.unwrap_or(OomControl::default()),
soft_limit_in_bytes: self
.open_path("memory.soft_limit_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
stat: self
.open_path("memory.stat", false)
.and_then(read_string_from)
.and_then(parse_memory_stat)
.unwrap_or(MemoryStat::default()),
swappiness: self
.open_path("memory.swappiness", false)
.and_then(read_u64_from)
.unwrap_or(0),
use_hierarchy: self
.open_path("memory.use_hierarchy", false)
.and_then(read_u64_from)
.unwrap_or(0),
}
}
/// Gathers information about the kernel memory usage of the control group's tasks.
pub fn kmem_stat(&self) -> Kmem {
Kmem {
fail_cnt: self.open_path("memory.kmem.failcnt", false)
.and_then(read_u64_from).unwrap_or(0),
limit_in_bytes: self.open_path("memory.kmem.limit_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
usage_in_bytes: self.open_path("memory.kmem.usage_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
max_usage_in_bytes: self.open_path("memory.kmem.max_usage_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
slabinfo: self.open_path("memory.kmem.slabinfo", false)
.and_then(read_string_from).unwrap_or("".to_string()),
fail_cnt: self
.open_path("memory.kmem.failcnt", false)
.and_then(read_u64_from)
.unwrap_or(0),
limit_in_bytes: self
.open_path("memory.kmem.limit_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
usage_in_bytes: self
.open_path("memory.kmem.usage_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
max_usage_in_bytes: self
.open_path("memory.kmem.max_usage_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
slabinfo: self
.open_path("memory.kmem.slabinfo", false)
.and_then(read_string_from)
.unwrap_or("".to_string()),
}
}
@@ -411,14 +520,22 @@ impl MemController {
/// TCP-related.
pub fn kmem_tcp_stat(&self) -> Tcp {
Tcp {
fail_cnt: self.open_path("memory.kmem.tcp.failcnt", false)
.and_then(read_u64_from).unwrap_or(0),
limit_in_bytes: self.open_path("memory.kmem.tcp.limit_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
usage_in_bytes: self.open_path("memory.kmem.tcp.usage_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
max_usage_in_bytes: self.open_path("memory.kmem.tcp.max_usage_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
fail_cnt: self
.open_path("memory.kmem.tcp.failcnt", false)
.and_then(read_u64_from)
.unwrap_or(0),
limit_in_bytes: self
.open_path("memory.kmem.tcp.limit_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
usage_in_bytes: self
.open_path("memory.kmem.tcp.usage_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
max_usage_in_bytes: self
.open_path("memory.kmem.tcp.max_usage_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
}
}
@@ -426,65 +543,83 @@ impl MemController {
/// (if any).
pub fn memswap(&self) -> MemSwap {
MemSwap {
fail_cnt: self.open_path("memory.memsw.failcnt", false)
.and_then(read_u64_from).unwrap_or(0),
limit_in_bytes: self.open_path("memory.memsw.limit_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
usage_in_bytes: self.open_path("memory.memsw.usage_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
max_usage_in_bytes: self.open_path("memory.memsw.max_usage_in_bytes", false)
.and_then(read_u64_from).unwrap_or(0),
fail_cnt: self
.open_path("memory.memsw.failcnt", false)
.and_then(read_u64_from)
.unwrap_or(0),
limit_in_bytes: self
.open_path("memory.memsw.limit_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
usage_in_bytes: self
.open_path("memory.memsw.usage_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
max_usage_in_bytes: self
.open_path("memory.memsw.max_usage_in_bytes", false)
.and_then(read_u64_from)
.unwrap_or(0),
}
}
/// Set the memory usage limit of the control group, in bytes.
pub fn set_limit(&self, limit: u64) -> Result<(), CgroupError> {
self.open_path("memory.limit_in_bytes", true).and_then(|mut file| {
file.write_all(limit.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("memory.limit_in_bytes", true)
.and_then(|mut file| {
file.write_all(limit.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Set the kernel memory limit of the control group, in bytes.
pub fn set_kmem_limit(&self, limit: u64) -> Result<(), CgroupError> {
self.open_path("memory.kmem.limit_in_bytes", true).and_then(|mut file| {
file.write_all(limit.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("memory.kmem.limit_in_bytes", true)
.and_then(|mut file| {
file.write_all(limit.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Set the memory+swap limit of the control group, in bytes.
pub fn set_memswap_limit(&self, limit: u64) -> Result<(), CgroupError> {
self.open_path("memory.memsw.limit_in_bytes", true).and_then(|mut file| {
file.write_all(limit.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("memory.memsw.limit_in_bytes", true)
.and_then(|mut file| {
file.write_all(limit.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Set how much kernel memory can be used for TCP-related buffers by the control group.
pub fn set_tcp_limit(&self, limit: u64) -> Result<(), CgroupError> {
self.open_path("memory.kmem.tcp.limit_in_bytes", true).and_then(|mut file| {
file.write_all(limit.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("memory.kmem.tcp.limit_in_bytes", true)
.and_then(|mut file| {
file.write_all(limit.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Set the soft limit of the control group, in bytes.
///
/// This limit is enforced when the system is nearing OOM conditions. Contrast this with the
/// hard limit, which is _always_ enforced.
pub fn set_soft_limit(&self, limit: u64) -> Result<(), CgroupError> {
self.open_path("memory.soft_limit_in_bytes", true).and_then(|mut file| {
file.write_all(limit.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("memory.soft_limit_in_bytes", true)
.and_then(|mut file| {
file.write_all(limit.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
/// Set how likely the kernel is to swap out parts of the address space used by the control
/// group.
///
/// 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<(), CgroupError> {
self.open_path("memory.swappiness", true).and_then(|mut file| {
file.write_all(swp.to_string().as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("memory.swappiness", true)
.and_then(|mut file| {
file.write_all(swp.to_string().as_ref())
.map_err(CgroupError::WriteError)
})
}
}
@@ -502,7 +637,7 @@ impl<'a> From<&'a Subsystem> for &'a MemController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -526,7 +661,9 @@ fn read_string_from(mut file: File) -> Result<String, CgroupError> {
#[cfg(test)]
mod tests {
use memory::{MemoryStat, parse_memory_stat, NumaStat, parse_oom_control, OomControl, parse_numa_stat};
use memory::{
parse_memory_stat, parse_numa_stat, parse_oom_control, MemoryStat, NumaStat, OomControl,
};
const good_value: &str = "\
total=51189 N0=51189 N1=123
file=50175 N0=50175 N1=123
@@ -585,7 +722,8 @@ total_unevictable 81920
#[test]
fn test_parse_numa_stat() {
assert_eq!(parse_numa_stat(good_value.to_string()),
assert_eq!(
parse_numa_stat(good_value.to_string()),
Ok(NumaStat {
total_pages: 51189,
total_pages_per_node: vec![51189, 123],
@@ -604,22 +742,26 @@ total_unevictable 81920
hierarchical_anon_pages_per_node: vec![770402, 123],
hierarchical_unevictable_pages: 20,
hierarchical_unevictable_pages_per_node: vec![20, 123],
}));
})
);
}
#[test]
fn test_parse_oom_control() {
assert_eq!(parse_oom_control(good_oomcontrol_val.to_string()),
Ok(OomControl {
oom_kill_disable: false,
under_oom: true,
oom_kill: 1337,
}));
assert_eq!(
parse_oom_control(good_oomcontrol_val.to_string()),
Ok(OomControl {
oom_kill_disable: false,
under_oom: true,
oom_kill: 1337,
})
);
}
#[test]
fn test_parse_memory_stat() {
assert_eq!(parse_memory_stat(good_memorystat_val.to_string()),
assert_eq!(
parse_memory_stat(good_memorystat_val.to_string()),
Ok(MemoryStat {
cache: 178880512,
rss: 4206592,
@@ -657,6 +799,7 @@ total_unevictable 81920
total_inactive_file: 1272135680,
total_active_file: 2338816000,
total_unevictable: 81920,
}));
})
);
}
}

View File

@@ -1,13 +1,16 @@
//! This module contains the implementation of the `net_cls` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroup-v1/net_cls.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/net_cls.txt)
use std::path::PathBuf;
use std::io::{Read, Write};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use {CgroupError, NetworkResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
use CgroupError::*;
use {
CgroupError, ControllIdentifier, Controller, Controllers, NetworkResources, Resources,
Subsystem,
};
/// A controller that allows controlling the `net_cls` subsystem of a Cgroup.
///
@@ -21,10 +24,18 @@ pub struct NetClsController {
}
impl Controller for NetClsController {
fn control_type(&self) -> Controllers { Controllers::NetCls }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::NetCls
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, res: &Resources) -> Result<(), CgroupError> {
/* get the resources that apply to this controller */
@@ -54,7 +65,7 @@ impl<'a> From<&'a Subsystem> for &'a NetClsController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -78,19 +89,19 @@ impl NetClsController {
path: root,
}
}
/// Set the network class id of the outgoing packets of the control group's tasks.
pub fn set_class(&self, class: u64) -> Result<(), CgroupError> {
self.open_path("net_cls.classid", true).and_then(|mut file| {
let s = format!("{:#08X}", class);
file.write_all(s.as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("net_cls.classid", true)
.and_then(|mut file| {
let s = format!("{:#08X}", class);
file.write_all(s.as_ref()).map_err(CgroupError::WriteError)
})
}
/// Get the network class id of the outgoing packets of the control group's tasks.
pub fn get_class(&self) -> Result<u64, CgroupError> {
self.open_path("net_cls.classid", false).and_then(|file| {
read_u64_from(file)
})
self.open_path("net_cls.classid", false)
.and_then(|file| read_u64_from(file))
}
}

View File

@@ -1,14 +1,17 @@
//! This module contains the implementation of the `net_prio` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroup-v1/net_prio.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/net_prio.txt)
use std::path::PathBuf;
use std::io::{BufReader, BufRead, Write, Read};
use std::fs::File;
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufRead, BufReader, Read, Write};
use std::path::PathBuf;
use {CgroupError, NetworkResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
use CgroupError::*;
use {
CgroupError, ControllIdentifier, Controller, Controllers, NetworkResources, Resources,
Subsystem,
};
/// A controller that allows controlling the `net_prio` subsystem of a Cgroup.
///
@@ -22,10 +25,18 @@ pub struct NetPrioController {
}
impl Controller for NetPrioController {
fn control_type(&self) -> Controllers { Controllers::NetPrio }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::NetPrio
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, res: &Resources) -> Result<(), CgroupError> {
/* get the resources that apply to this controller */
@@ -55,7 +66,7 @@ impl<'a> From<&'a Subsystem> for &'a NetPrioController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -89,38 +100,41 @@ impl NetPrioController {
/// A map of priorities for each network interface.
pub fn ifpriomap(&self) -> Result<HashMap<String, u64>, CgroupError> {
self.open_path("net_prio.ifpriomap", false) .and_then(|file| {
let bf = BufReader::new(file);
bf.lines().fold(Ok(HashMap::new()), |acc, line| {
if acc.is_err() {
acc
} else {
let mut acc = acc.unwrap();
let l = line.unwrap();
let mut sp = l.split_whitespace();
let ifname = sp.nth(0);
let ifprio = sp.nth(1);
if ifname.is_none() || ifprio.is_none() {
Err(CgroupError::ParseError)
self.open_path("net_prio.ifpriomap", false)
.and_then(|file| {
let bf = BufReader::new(file);
bf.lines().fold(Ok(HashMap::new()), |acc, line| {
if acc.is_err() {
acc
} else {
let ifname = ifname.unwrap();
let ifprio = ifprio.unwrap().trim().parse();
if ifprio.is_err() {
let mut acc = acc.unwrap();
let l = line.unwrap();
let mut sp = l.split_whitespace();
let ifname = sp.nth(0);
let ifprio = sp.nth(1);
if ifname.is_none() || ifprio.is_none() {
Err(CgroupError::ParseError)
} else {
acc.insert(ifname.to_string(), ifprio.unwrap());
Ok(acc)
let ifname = ifname.unwrap();
let ifprio = ifprio.unwrap().trim().parse();
if ifprio.is_err() {
Err(CgroupError::ParseError)
} else {
acc.insert(ifname.to_string(), ifprio.unwrap());
Ok(acc)
}
}
}
}
})
})
})
}
/// Set the priority of the network traffic on `eif` to be `prio`.
pub fn set_if_prio(&self, eif: &String, prio: u64) -> Result<(), CgroupError> {
self.open_path("net_prio.ifpriomap", true).and_then(|mut file| {
file.write_all(format!("{} {}", eif, prio).as_ref()).map_err(CgroupError::WriteError)
})
self.open_path("net_prio.ifpriomap", true)
.and_then(|mut file| {
file.write_all(format!("{} {}", eif, prio).as_ref())
.map_err(CgroupError::WriteError)
})
}
}

View File

@@ -1,10 +1,10 @@
//! This module contains the implementation of the `perf_event` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [tools/perf/Documentation/perf-record.txt](https://raw.githubusercontent.com/torvalds/linux/master/tools/perf/Documentation/perf-record.txt)
use std::path::PathBuf;
use {CgroupError, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
use {CgroupError, ControllIdentifier, Controller, Controllers, Resources, Subsystem};
/// A controller that allows controlling the `perf_event` subsystem of a Cgroup.
///
@@ -17,10 +17,18 @@ pub struct PerfEventController {
}
impl Controller for PerfEventController {
fn control_type(&self) -> Controllers { Controllers::PerfEvent }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::PerfEvent
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, _res: &Resources) -> Result<(), CgroupError> {
Ok(())
@@ -41,7 +49,7 @@ impl<'a> From<&'a Subsystem> for &'a PerfEventController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}

View File

@@ -1,13 +1,15 @@
//! This module contains the implementation of the `pids` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroups-v1/pids.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt)
use std::path::PathBuf;
use std::io::{Write, Read};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use {CgroupError, Resources, PidResources, Controller, ControllIdentifier, Subsystem, Controllers};
use CgroupError::*;
use {
CgroupError, ControllIdentifier, Controller, Controllers, PidResources, Resources, Subsystem,
};
/// A controller that allows controlling the `pids` subsystem of a Cgroup.
#[derive(Debug, Clone)]
@@ -33,10 +35,18 @@ impl Default for PidMax {
}
impl Controller for PidController {
fn control_type(&self) -> Controllers { Controllers::Pids }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::Pids
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, res: &Resources) -> Result<(), CgroupError> {
/* get the resources that apply to this controller */
@@ -45,7 +55,7 @@ impl Controller for PidController {
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(());
@@ -78,7 +88,7 @@ impl<'a> From<&'a Subsystem> for &'a PidController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -109,14 +119,12 @@ impl PidController {
self.open_path("pids.events", false).and_then(|mut file| {
let mut string = String::new();
match file.read_to_string(&mut string) {
Ok(_) => {
match string.split_whitespace().nth(1) {
Some(elem) => match elem.parse() {
Ok(val) => Ok(val),
Err(_) => Err(CgroupError::ParseError),
},
None => Err(CgroupError::ParseError),
}
Ok(_) => match string.split_whitespace().nth(1) {
Some(elem) => match elem.parse() {
Ok(val) => Ok(val),
Err(_) => Err(CgroupError::ParseError),
},
None => Err(CgroupError::ParseError),
},
Err(e) => Err(CgroupError::ReadError(e)),
}
@@ -125,7 +133,8 @@ impl PidController {
/// The number of processes currently.
pub fn get_pid_current(&self) -> Result<u64, CgroupError> {
self.open_path("pids.current", false).and_then(read_u64_from)
self.open_path("pids.current", false)
.and_then(read_u64_from)
}
/// The maximum number of processes that can exist at one time in the control group.

View File

@@ -1,12 +1,12 @@
//! This module contains the implementation of the `rdma` cgroup subsystem.
//!
//!
//! See the Kernel's documentation for more information about this subsystem, found at:
//! [Documentation/cgroup-v1/rdma.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/rdma.txt)
use std::path::PathBuf;
use std::io::{Write, Read};
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use {CgroupError, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
use {CgroupError, ControllIdentifier, Controller, Controllers, Resources, Subsystem};
/// A controller that allows controlling the `rdma` subsystem of a Cgroup.
///
@@ -19,10 +19,18 @@ pub struct RdmaController {
}
impl Controller for RdmaController {
fn control_type(&self) -> Controllers { Controllers::Rdma }
fn get_path(&self) -> &PathBuf { &self.path }
fn get_path_mut(&mut self) -> &mut PathBuf { &mut self.path }
fn get_base(&self) -> &PathBuf { &self.base }
fn control_type(&self) -> Controllers {
Controllers::Rdma
}
fn get_path(&self) -> &PathBuf {
&self.path
}
fn get_path_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
fn get_base(&self) -> &PathBuf {
&self.base
}
fn apply(&self, _res: &Resources) -> Result<(), CgroupError> {
Ok(())
@@ -43,7 +51,7 @@ impl<'a> From<&'a Subsystem> for &'a RdmaController {
_ => {
assert_eq!(1, 0);
::std::mem::uninitialized()
},
}
}
}
}
@@ -77,7 +85,8 @@ impl RdmaController {
/// Set a maximum usage for each RDMA/IB resource.
pub fn set_max(&self, max: &String) -> Result<(), CgroupError> {
self.open_path("rdma.max", true).and_then(|mut file| {
file.write_all(max.as_ref()).map_err(CgroupError::WriteError)
file.write_all(max.as_ref())
.map_err(CgroupError::WriteError)
})
}
}

View File

@@ -2,8 +2,8 @@
extern crate cgroups;
use cgroups::{Cgroup, CgroupPid};
extern crate nix;
extern crate libc;
extern crate nix;
#[test]
fn test_tasks_iterator() {
@@ -17,7 +17,7 @@ fn test_tasks_iterator() {
// Verify that the task is indeed in the control group
assert_eq!(tasks.next(), Some(CgroupPid::from(pid)));
assert_eq!(tasks.next(), None);
// Now, try removing it.
cg.remove_task(CgroupPid::from(pid));
tasks = cg.tasks().into_iter();

View File

@@ -1,7 +1,7 @@
extern crate cgroups;
use cgroups::{Cgroup, CgroupError};
use cgroups::cpuset::CpuSetController;
use cgroups::{Cgroup, CgroupError};
#[test]
fn test_cpuset_memory_pressure_root_cg() {

View File

@@ -1,8 +1,8 @@
//! Integration tests about the devices subsystem
extern crate cgroups;
use cgroups::devices::{DevicePermissions, DeviceType, DevicesController};
use cgroups::{Cgroup, DeviceResource};
use cgroups::devices::{DevicesController, DevicePermissions, DeviceType};
#[test]
fn test_devices_parsing() {
@@ -12,7 +12,16 @@ 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,
],
);
// 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.
@@ -25,13 +34,16 @@ fn test_devices_parsing() {
assert!(allowed_devices.is_ok());
let allowed_devices = allowed_devices.unwrap();
assert_eq!(allowed_devices.len(), 1);
assert_eq!(allowed_devices[0], DeviceResource {
allow: true,
devtype: DeviceType::Char,
major: 1,
minor: 3,
access: vec![DevicePermissions::MkNod],
});
assert_eq!(
allowed_devices[0],
DeviceResource {
allow: true,
devtype: DeviceType::Char,
major: 1,
minor: 3,
access: vec![DevicePermissions::MkNod],
}
);
// Now deny, this device explicitly.
devices.deny_device(DeviceType::Char, 1, 3, &DevicePermissions::all());

View File

@@ -1,12 +1,12 @@
//! Integration tests about the pids subsystem
extern crate cgroups;
use cgroups::{CgroupError, CgroupPid, Cgroup, Resources, PidResources};
use cgroups::pid::{PidController, PidMax};
use cgroups::Controller;
use cgroups::{Cgroup, CgroupError, CgroupPid, PidResources, Resources};
extern crate nix;
use nix::unistd::{Pid, fork, ForkResult};
use nix::sys::wait::{waitpid, WaitStatus};
use nix::unistd::{fork, ForkResult, Pid};
extern crate libc;
use libc::pid_t;
@@ -86,16 +86,14 @@ fn test_pid_events_is_not_zero() {
let events = pids.get_pid_events();
assert!(events.is_ok());
assert_eq!(events.unwrap(), before + 1);
},
Ok(ForkResult::Child) => {
loop {
let pids_max = pids.get_pid_max();
if pids_max.is_ok() && pids_max.unwrap() == PidMax::Value(1) {
if let Err(_) = fork() {
unsafe { libc::exit(0) };
} else {
unsafe { libc::exit(1) };
}
}
Ok(ForkResult::Child) => loop {
let pids_max = pids.get_pid_max();
if pids_max.is_ok() && pids_max.unwrap() == PidMax::Value(1) {
if let Err(_) = fork() {
unsafe { libc::exit(0) };
} else {
unsafe { libc::exit(1) };
}
}
},

View File

@@ -1,8 +1,8 @@
//! Integration test about setting resources using `apply()`
extern crate cgroups;
use cgroups::{Cgroup, Resources, PidResources};
use cgroups::pid::{PidController, PidMax};
use cgroups::{Cgroup, PidResources, Resources};
#[test]
fn pid_resources() {