mirror of
https://github.com/kata-containers/cgroups-rs.git
synced 2026-08-05 02:13:23 +00:00
135
src/blkio.rs
135
src/blkio.rs
@@ -12,8 +12,8 @@ use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{
|
||||
BlkIoResources, ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem,
|
||||
@@ -27,7 +27,7 @@ use crate::{
|
||||
pub struct BlkIoController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
v2: bool,
|
||||
v2: bool,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
@@ -124,7 +124,7 @@ fn parse_io_service(s: String) -> Result<Vec<IoService>> {
|
||||
}
|
||||
|
||||
fn get_value(s: &str) -> String {
|
||||
let arr = s.split(':').collect::<Vec<&str>>();
|
||||
let arr = s.split(':').collect::<Vec<&str>>();
|
||||
if arr.len() != 2 {
|
||||
return "0".to_string();
|
||||
}
|
||||
@@ -134,7 +134,8 @@ fn get_value(s: &str) -> String {
|
||||
fn parse_io_stat(s: String) -> Result<Vec<IoStat>> {
|
||||
// line:
|
||||
// 8:0 rbytes=180224 wbytes=0 rios=3 wios=0 dbytes=0 dios=0
|
||||
let v = s.lines()
|
||||
let v = s
|
||||
.lines()
|
||||
.filter(|x| x.split_whitespace().collect::<Vec<_>>().len() == 7)
|
||||
.map(|x| {
|
||||
let arr = x.split_whitespace().collect::<Vec<&str>>();
|
||||
@@ -356,7 +357,8 @@ impl ControllerInternal for BlkIoController {
|
||||
let _ = self.set_weight_for_device(dev.major, dev.minor, weight as u64);
|
||||
}
|
||||
if let Some(leaf_weight) = dev.leaf_weight {
|
||||
let _ = self.set_leaf_weight_for_device(dev.major, dev.minor, leaf_weight as u64);
|
||||
let _ =
|
||||
self.set_leaf_weight_for_device(dev.major, dev.minor, leaf_weight as u64);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,7 +414,10 @@ fn read_string_from(mut file: File) -> Result<String> {
|
||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
||||
let mut string = String::new();
|
||||
match file.read_to_string(&mut string) {
|
||||
Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Ok(_) => string
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
||||
}
|
||||
}
|
||||
@@ -421,23 +426,23 @@ impl BlkIoController {
|
||||
/// Constructs a new `BlkIoController` with `oroot` serving as the root of the control group.
|
||||
pub fn new(oroot: PathBuf, v2: bool) -> Self {
|
||||
let mut root = oroot;
|
||||
if !v2{
|
||||
if !v2 {
|
||||
root.push(Self::controller_type().to_string());
|
||||
}
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
v2: v2,
|
||||
v2: v2,
|
||||
}
|
||||
}
|
||||
|
||||
fn blkio_v2(&self) -> BlkIo {
|
||||
let mut blkio: BlkIo = Default::default();
|
||||
blkio.io_stat = self
|
||||
.open_path("io.stat", false)
|
||||
.and_then(read_string_from)
|
||||
.and_then(parse_io_stat)
|
||||
.unwrap_or(Vec::new());
|
||||
.open_path("io.stat", false)
|
||||
.and_then(read_string_from)
|
||||
.and_then(parse_io_stat)
|
||||
.unwrap_or(Vec::new());
|
||||
|
||||
blkio
|
||||
}
|
||||
@@ -684,12 +689,7 @@ impl BlkIoController {
|
||||
}
|
||||
|
||||
/// Same as `set_leaf_weight()`, but settable per each block device.
|
||||
pub fn set_leaf_weight_for_device(
|
||||
&self,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
weight: u64,
|
||||
) -> Result<()> {
|
||||
pub fn set_leaf_weight_for_device(&self, major: u64, minor: u64, weight: u64) -> Result<()> {
|
||||
self.open_path("blkio.leaf_weight_device", true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(format!("{}:{} {}", major, minor, weight).as_ref())
|
||||
@@ -708,85 +708,61 @@ impl BlkIoController {
|
||||
|
||||
/// Throttle the bytes per second rate of read operation affecting the block device
|
||||
/// `major:minor` to `bps`.
|
||||
pub fn throttle_read_bps_for_device(
|
||||
&self,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
bps: u64,
|
||||
) -> Result<()> {
|
||||
pub fn throttle_read_bps_for_device(&self, major: u64, minor: u64, bps: u64) -> Result<()> {
|
||||
let mut file = "blkio.throttle.read_bps_device";
|
||||
let mut content = format!("{}:{} {}", major, minor, bps);
|
||||
if self.v2 {
|
||||
file = "io.max";
|
||||
content = format!("{}:{} rbps={}", major, minor, bps);
|
||||
}
|
||||
self.open_path(file, true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(content.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path(file, true).and_then(|mut file| {
|
||||
file.write_all(content.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
|
||||
/// Throttle the I/O operations per second rate of read operation affecting the block device
|
||||
/// `major:minor` to `bps`.
|
||||
pub fn throttle_read_iops_for_device(
|
||||
&self,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
iops: u64,
|
||||
) -> Result<()> {
|
||||
pub fn throttle_read_iops_for_device(&self, major: u64, minor: u64, iops: u64) -> Result<()> {
|
||||
let mut file = "blkio.throttle.read_iops_device";
|
||||
let mut content = format!("{}:{} {}", major, minor, iops);
|
||||
if self.v2 {
|
||||
file = "io.max";
|
||||
content = format!("{}:{} riops={}", major, minor, iops);
|
||||
}
|
||||
self.open_path(file, true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(content.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path(file, true).and_then(|mut file| {
|
||||
file.write_all(content.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
/// Throttle the bytes per second rate of write operation affecting the block device
|
||||
/// `major:minor` to `bps`.
|
||||
pub fn throttle_write_bps_for_device(
|
||||
&self,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
bps: u64,
|
||||
) -> Result<()> {
|
||||
pub fn throttle_write_bps_for_device(&self, major: u64, minor: u64, bps: u64) -> Result<()> {
|
||||
let mut file = "blkio.throttle.write_bps_device";
|
||||
let mut content = format!("{}:{} {}", major, minor, bps);
|
||||
if self.v2 {
|
||||
file = "io.max";
|
||||
content = format!("{}:{} wbps={}", major, minor, bps);
|
||||
}
|
||||
self.open_path(file, true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(content.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path(file, true).and_then(|mut file| {
|
||||
file.write_all(content.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
|
||||
/// Throttle the I/O operations per second rate of write operation affecting the block device
|
||||
/// `major:minor` to `bps`.
|
||||
pub fn throttle_write_iops_for_device(
|
||||
&self,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
iops: u64,
|
||||
) -> Result<()> {
|
||||
pub fn throttle_write_iops_for_device(&self, major: u64, minor: u64, iops: u64) -> Result<()> {
|
||||
let mut file = "blkio.throttle.write_iops_device";
|
||||
let mut content = format!("{}:{} {}", major, minor, iops);
|
||||
if self.v2 {
|
||||
file = "io.max";
|
||||
content = format!("{}:{} wiops={}", major, minor, iops);
|
||||
}
|
||||
self.open_path(file, true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(content.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path(file, true).and_then(|mut file| {
|
||||
file.write_all(content.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the weight of the control group's tasks.
|
||||
@@ -796,20 +772,14 @@ impl BlkIoController {
|
||||
if self.v2 {
|
||||
file = "io.bfq.weight";
|
||||
}
|
||||
self.open_path(file, true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(w.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path(file, true).and_then(|mut file| {
|
||||
file.write_all(w.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
|
||||
/// Same as `set_weight()`, but settable per each block device.
|
||||
pub fn set_weight_for_device(
|
||||
&self,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
weight: u64,
|
||||
) -> Result<()> {
|
||||
pub fn set_weight_for_device(&self, major: u64, minor: u64, weight: u64) -> Result<()> {
|
||||
let mut file = "blkio.weight_device";
|
||||
if self.v2 {
|
||||
// Attation: there is no weight for device in runc
|
||||
@@ -817,11 +787,10 @@ impl BlkIoController {
|
||||
// may depends on IO schedulers https://wiki.ubuntu.com/Kernel/Reference/IOSchedulers
|
||||
file = "io.bfq.weight";
|
||||
}
|
||||
self.open_path(file, true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(format!("{}:{} {}", major, minor, weight).as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path(file, true).and_then(|mut file| {
|
||||
file.write_all(format!("{}:{} {}", major, minor, weight).as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -887,10 +856,7 @@ Total 61823067136
|
||||
#[test]
|
||||
fn test_parse_io_service_total() {
|
||||
let ok = parse_io_service_total(TEST_VALUE.to_string()).unwrap();
|
||||
assert_eq!(
|
||||
ok,
|
||||
61823067136
|
||||
);
|
||||
assert_eq!(ok, 61823067136);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -938,10 +904,7 @@ Total 61823067136
|
||||
]
|
||||
);
|
||||
let err = parse_io_service(TEST_WRONG_VALUE.to_string()).unwrap_err();
|
||||
assert_eq!(
|
||||
err.kind(),
|
||||
&ErrorKind::ParseError,
|
||||
);
|
||||
assert_eq!(err.kind(), &ErrorKind::ParseError,);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
//! This module handles cgroup operations. Start here!
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::libc_rmdir;
|
||||
|
||||
@@ -85,7 +85,11 @@ impl<'b> Cgroup<'b> {
|
||||
///
|
||||
/// Note that if the handle goes out of scope and is dropped, the control group is _not_
|
||||
/// destroyed.
|
||||
pub fn new_with_relative_paths<P: AsRef<Path>>(hier: Box<&'b dyn Hierarchy>, path: P, relative_paths: HashMap<String, String>) -> Cgroup<'b> {
|
||||
pub fn new_with_relative_paths<P: AsRef<Path>>(
|
||||
hier: Box<&'b dyn Hierarchy>,
|
||||
path: P,
|
||||
relative_paths: HashMap<String, String>,
|
||||
) -> Cgroup<'b> {
|
||||
let cg = Cgroup::load_with_relative_paths(hier, path, relative_paths);
|
||||
cg.create();
|
||||
cg
|
||||
@@ -99,7 +103,11 @@ impl<'b> Cgroup<'b> {
|
||||
///
|
||||
/// Note that if the handle goes out of scope and is dropped, the control group is _not_
|
||||
/// destroyed.
|
||||
pub fn load_with_relative_paths<P: AsRef<Path>>(hier: Box<&'b dyn Hierarchy>, path: P, relative_paths: HashMap<String, String>) -> Cgroup<'b> {
|
||||
pub fn load_with_relative_paths<P: AsRef<Path>>(
|
||||
hier: Box<&'b dyn Hierarchy>,
|
||||
path: P,
|
||||
relative_paths: HashMap<String, String>,
|
||||
) -> Cgroup<'b> {
|
||||
let path = path.as_ref();
|
||||
let mut subsystems = hier.subsystems();
|
||||
if path.as_os_str() != "" {
|
||||
@@ -147,7 +155,7 @@ impl<'b> Cgroup<'b> {
|
||||
p.push(self.path);
|
||||
libc_rmdir(p.to_str().unwrap());
|
||||
}
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
self.subsystems.into_iter().for_each(|sub| match sub {
|
||||
@@ -220,8 +228,8 @@ impl<'b> Cgroup<'b> {
|
||||
}
|
||||
} else {
|
||||
self.subsystems()
|
||||
.iter()
|
||||
.try_for_each(|sub| sub.to_controller().add_task(&pid))
|
||||
.iter()
|
||||
.try_for_each(|sub| sub.to_controller().add_task(&pid))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,8 +246,7 @@ impl<'b> Cgroup<'b> {
|
||||
vec![]
|
||||
}
|
||||
} else {
|
||||
self
|
||||
.subsystems()
|
||||
self.subsystems()
|
||||
.iter()
|
||||
.map(|x| x.to_controller().tasks())
|
||||
.fold(vec![], |mut acc, mut x| {
|
||||
@@ -259,16 +266,19 @@ pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup";
|
||||
fn enable_controllers(controllers: &Vec<String>, path: &PathBuf) {
|
||||
let mut f = path.clone();
|
||||
f.push("cgroup.subtree_control");
|
||||
for c in controllers{
|
||||
for c in controllers {
|
||||
let body = format!("+{}", c);
|
||||
let _rest = fs::write(f.as_path(), body.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
fn supported_controllers(p: &PathBuf) -> Vec<String>{
|
||||
fn supported_controllers(p: &PathBuf) -> Vec<String> {
|
||||
let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers");
|
||||
let ret = fs::read_to_string(p.as_str());
|
||||
ret.unwrap_or(String::new()).split(" ").map(|x| x.to_string() ).collect::<Vec<String>>()
|
||||
ret.unwrap_or(String::new())
|
||||
.split(" ")
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
}
|
||||
|
||||
fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> {
|
||||
@@ -281,16 +291,16 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> {
|
||||
|
||||
// path: "a/b/c"
|
||||
let elements = path.split("/").collect::<Vec<&str>>();
|
||||
let last_index = elements.len() - 1 ;
|
||||
let last_index = elements.len() - 1;
|
||||
for (i, ele) in elements.iter().enumerate() {
|
||||
// ROOT/a
|
||||
fp.push(ele);
|
||||
// create dir, need not check if is a file or directory
|
||||
if !fp.exists(){
|
||||
if !fp.exists() {
|
||||
match ::std::fs::create_dir(fp.clone()) {
|
||||
Err(e) => return Err(Error::with_cause(ErrorKind::FsError, e)),
|
||||
Ok(_) => {},
|
||||
}
|
||||
Ok(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
if i < last_index {
|
||||
@@ -304,7 +314,8 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> {
|
||||
|
||||
pub fn get_cgroups_relative_paths() -> Result<HashMap<String, String>> {
|
||||
let mut m = HashMap::new();
|
||||
let content = fs::read_to_string("/proc/self/cgroup").map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
let content =
|
||||
fs::read_to_string("/proc/self/cgroup").map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
for l in content.lines() {
|
||||
let fl: Vec<&str> = l.split(':').collect();
|
||||
if fl.len() != 3 {
|
||||
|
||||
@@ -62,7 +62,10 @@
|
||||
//! ```
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{pid, BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy, HugePageResource, MaxValue, NetworkPriority, Resources};
|
||||
use crate::{
|
||||
pid, BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy,
|
||||
HugePageResource, MaxValue, NetworkPriority, Resources,
|
||||
};
|
||||
|
||||
macro_rules! gen_setter {
|
||||
($res:ident, $cont:ident, $func:ident, $name:ident, $ty:ty) => {
|
||||
@@ -72,7 +75,7 @@ macro_rules! gen_setter {
|
||||
self.cgroup.resources.$res.$name = $name;
|
||||
self
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// A control group builder instance
|
||||
@@ -97,46 +100,34 @@ impl<'a> CgroupBuilder<'a> {
|
||||
|
||||
/// Builds the memory resources of the control group.
|
||||
pub fn memory(self) -> MemoryResourceBuilder<'a> {
|
||||
MemoryResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
MemoryResourceBuilder { cgroup: self }
|
||||
}
|
||||
|
||||
/// Builds the pid resources of the control group.
|
||||
pub fn pid(self) -> PidResourceBuilder<'a> {
|
||||
PidResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
PidResourceBuilder { cgroup: self }
|
||||
}
|
||||
|
||||
/// Builds the cpu resources of the control group.
|
||||
pub fn cpu(self) -> CpuResourceBuilder<'a> {
|
||||
CpuResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
CpuResourceBuilder { cgroup: self }
|
||||
}
|
||||
|
||||
/// Builds the devices resources of the control group, disallowing or
|
||||
/// allowing access to certain devices in the system.
|
||||
pub fn devices(self) -> DeviceResourceBuilder<'a> {
|
||||
DeviceResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
DeviceResourceBuilder { cgroup: self }
|
||||
}
|
||||
|
||||
/// Builds the network resources of the control group, setting class id, or
|
||||
/// various priorities on networking interfaces.
|
||||
pub fn network(self) -> NetworkResourceBuilder<'a> {
|
||||
NetworkResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
NetworkResourceBuilder { cgroup: self }
|
||||
}
|
||||
|
||||
/// Builds the hugepage/hugetlb resources available to the control group.
|
||||
pub fn hugepages(self) -> HugepagesResourceBuilder<'a> {
|
||||
HugepagesResourceBuilder {
|
||||
cgroup: self,
|
||||
}
|
||||
HugepagesResourceBuilder { cgroup: self }
|
||||
}
|
||||
|
||||
/// Builds the block I/O resources available for the control group.
|
||||
@@ -161,12 +152,35 @@ pub struct MemoryResourceBuilder<'a> {
|
||||
}
|
||||
|
||||
impl<'a> MemoryResourceBuilder<'a> {
|
||||
|
||||
gen_setter!(memory, MemController, set_kmem_limit, kernel_memory_limit, i64);
|
||||
gen_setter!(
|
||||
memory,
|
||||
MemController,
|
||||
set_kmem_limit,
|
||||
kernel_memory_limit,
|
||||
i64
|
||||
);
|
||||
gen_setter!(memory, MemController, set_limit, memory_hard_limit, i64);
|
||||
gen_setter!(memory, MemController, set_soft_limit, memory_soft_limit, i64);
|
||||
gen_setter!(memory, MemController, set_tcp_limit, kernel_tcp_memory_limit, i64);
|
||||
gen_setter!(memory, MemController, set_memswap_limit, memory_swap_limit, i64);
|
||||
gen_setter!(
|
||||
memory,
|
||||
MemController,
|
||||
set_soft_limit,
|
||||
memory_soft_limit,
|
||||
i64
|
||||
);
|
||||
gen_setter!(
|
||||
memory,
|
||||
MemController,
|
||||
set_tcp_limit,
|
||||
kernel_tcp_memory_limit,
|
||||
i64
|
||||
);
|
||||
gen_setter!(
|
||||
memory,
|
||||
MemController,
|
||||
set_memswap_limit,
|
||||
memory_swap_limit,
|
||||
i64
|
||||
);
|
||||
gen_setter!(memory, MemController, set_swappiness, swappiness, u64);
|
||||
|
||||
/// Finish the construction of the memory resources of a control group.
|
||||
@@ -181,8 +195,13 @@ pub struct PidResourceBuilder<'a> {
|
||||
}
|
||||
|
||||
impl<'a> PidResourceBuilder<'a> {
|
||||
|
||||
gen_setter!(pid, PidController, set_pid_max, maximum_number_of_processes, MaxValue);
|
||||
gen_setter!(
|
||||
pid,
|
||||
PidController,
|
||||
set_pid_max,
|
||||
maximum_number_of_processes,
|
||||
MaxValue
|
||||
);
|
||||
|
||||
/// Finish the construction of the pid resources of a control group.
|
||||
pub fn done(self) -> CgroupBuilder<'a> {
|
||||
@@ -196,7 +215,6 @@ pub struct CpuResourceBuilder<'a> {
|
||||
}
|
||||
|
||||
impl<'a> CpuResourceBuilder<'a> {
|
||||
|
||||
// FIXME this should all changed to options.
|
||||
gen_setter!(cpu, CpuSetController, set_cpus, cpus, Option<String>);
|
||||
gen_setter!(cpu, CpuSetController, set_mems, mems, String);
|
||||
@@ -218,22 +236,22 @@ pub struct DeviceResourceBuilder<'a> {
|
||||
}
|
||||
|
||||
impl<'a> DeviceResourceBuilder<'a> {
|
||||
|
||||
/// Restrict (or allow) a device to the tasks inside the control group.
|
||||
pub fn device(mut self,
|
||||
major: i64,
|
||||
minor: i64,
|
||||
devtype: crate::devices::DeviceType,
|
||||
allow: bool,
|
||||
access: Vec<crate::devices::DevicePermissions>)
|
||||
-> DeviceResourceBuilder<'a> {
|
||||
pub fn device(
|
||||
mut self,
|
||||
major: i64,
|
||||
minor: i64,
|
||||
devtype: crate::devices::DeviceType,
|
||||
allow: bool,
|
||||
access: Vec<crate::devices::DevicePermissions>,
|
||||
) -> DeviceResourceBuilder<'a> {
|
||||
self.cgroup.resources.devices.update_values = true;
|
||||
self.cgroup.resources.devices.devices.push(DeviceResource {
|
||||
major,
|
||||
minor,
|
||||
devtype,
|
||||
allow,
|
||||
access
|
||||
access,
|
||||
});
|
||||
self
|
||||
}
|
||||
@@ -250,18 +268,17 @@ pub struct NetworkResourceBuilder<'a> {
|
||||
}
|
||||
|
||||
impl<'a> NetworkResourceBuilder<'a> {
|
||||
|
||||
gen_setter!(network, NetclsController, set_class, class_id, u64);
|
||||
|
||||
/// Set the priority of the tasks when operating on a networking device defined by `name` to be
|
||||
/// `priority`.
|
||||
pub fn priority(mut self, name: String, priority: u64)
|
||||
-> NetworkResourceBuilder<'a> {
|
||||
pub fn priority(mut self, name: String, priority: u64) -> NetworkResourceBuilder<'a> {
|
||||
self.cgroup.resources.network.update_values = true;
|
||||
self.cgroup.resources.network.priorities.push(NetworkPriority {
|
||||
name,
|
||||
priority,
|
||||
});
|
||||
self.cgroup
|
||||
.resources
|
||||
.network
|
||||
.priorities
|
||||
.push(NetworkPriority { name, priority });
|
||||
self
|
||||
}
|
||||
|
||||
@@ -277,15 +294,14 @@ pub struct HugepagesResourceBuilder<'a> {
|
||||
}
|
||||
|
||||
impl<'a> HugepagesResourceBuilder<'a> {
|
||||
|
||||
/// Limit the usage of certain hugepages (determined by `size`) to be at most `limit` bytes.
|
||||
pub fn limit(mut self, size: String, limit: u64)
|
||||
-> HugepagesResourceBuilder<'a> {
|
||||
pub fn limit(mut self, size: String, limit: u64) -> HugepagesResourceBuilder<'a> {
|
||||
self.cgroup.resources.hugepages.update_values = true;
|
||||
self.cgroup.resources.hugepages.limits.push(HugePageResource {
|
||||
size,
|
||||
limit,
|
||||
});
|
||||
self.cgroup
|
||||
.resources
|
||||
.hugepages
|
||||
.limits
|
||||
.push(HugePageResource { size, limit });
|
||||
self
|
||||
}
|
||||
|
||||
@@ -302,24 +318,34 @@ pub struct BlkIoResourcesBuilder<'a> {
|
||||
}
|
||||
|
||||
impl<'a> BlkIoResourcesBuilder<'a> {
|
||||
|
||||
gen_setter!(blkio, BlkIoController, set_weight, weight, Option<u16>);
|
||||
gen_setter!(blkio, BlkIoController, set_leaf_weight, leaf_weight, Option<u16>);
|
||||
gen_setter!(
|
||||
blkio,
|
||||
BlkIoController,
|
||||
set_leaf_weight,
|
||||
leaf_weight,
|
||||
Option<u16>
|
||||
);
|
||||
|
||||
/// Set the weight of a certain device.
|
||||
pub fn weight_device(mut self,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
weight: Option<u16>,
|
||||
leaf_weight: Option<u16>)
|
||||
-> BlkIoResourcesBuilder<'a> {
|
||||
pub fn weight_device(
|
||||
mut self,
|
||||
major: u64,
|
||||
minor: u64,
|
||||
weight: Option<u16>,
|
||||
leaf_weight: Option<u16>,
|
||||
) -> BlkIoResourcesBuilder<'a> {
|
||||
self.cgroup.resources.blkio.update_values = true;
|
||||
self.cgroup.resources.blkio.weight_device.push(BlkIoDeviceResource {
|
||||
major,
|
||||
minor,
|
||||
weight,
|
||||
leaf_weight,
|
||||
});
|
||||
self.cgroup
|
||||
.resources
|
||||
.blkio
|
||||
.weight_device
|
||||
.push(BlkIoDeviceResource {
|
||||
major,
|
||||
minor,
|
||||
weight,
|
||||
leaf_weight,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
@@ -336,35 +362,41 @@ impl<'a> BlkIoResourcesBuilder<'a> {
|
||||
}
|
||||
|
||||
/// Limit the read rate of the current metric for a certain device.
|
||||
pub fn read(mut self, major: u64, minor: u64, rate: u64)
|
||||
-> BlkIoResourcesBuilder<'a> {
|
||||
pub fn read(mut self, major: u64, minor: u64, rate: u64) -> BlkIoResourcesBuilder<'a> {
|
||||
self.cgroup.resources.blkio.update_values = true;
|
||||
let throttle = BlkIoDeviceThrottleResource {
|
||||
major,
|
||||
minor,
|
||||
rate,
|
||||
};
|
||||
let throttle = BlkIoDeviceThrottleResource { major, minor, rate };
|
||||
if self.throttling_iops {
|
||||
self.cgroup.resources.blkio.throttle_read_iops_device.push(throttle);
|
||||
self.cgroup
|
||||
.resources
|
||||
.blkio
|
||||
.throttle_read_iops_device
|
||||
.push(throttle);
|
||||
} else {
|
||||
self.cgroup.resources.blkio.throttle_read_bps_device.push(throttle);
|
||||
self.cgroup
|
||||
.resources
|
||||
.blkio
|
||||
.throttle_read_bps_device
|
||||
.push(throttle);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Limit the write rate of the current metric for a certain device.
|
||||
pub fn write(mut self, major: u64, minor: u64, rate: u64)
|
||||
-> BlkIoResourcesBuilder<'a> {
|
||||
pub fn write(mut self, major: u64, minor: u64, rate: u64) -> BlkIoResourcesBuilder<'a> {
|
||||
self.cgroup.resources.blkio.update_values = true;
|
||||
let throttle = BlkIoDeviceThrottleResource {
|
||||
major,
|
||||
minor,
|
||||
rate,
|
||||
};
|
||||
let throttle = BlkIoDeviceThrottleResource { major, minor, rate };
|
||||
if self.throttling_iops {
|
||||
self.cgroup.resources.blkio.throttle_write_iops_device.push(throttle);
|
||||
self.cgroup
|
||||
.resources
|
||||
.blkio
|
||||
.throttle_write_iops_device
|
||||
.push(throttle);
|
||||
} else {
|
||||
self.cgroup.resources.blkio.throttle_write_bps_device.push(throttle);
|
||||
self.cgroup
|
||||
.resources
|
||||
.blkio
|
||||
.throttle_write_bps_device
|
||||
.push(throttle);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
37
src/cpu.rs
37
src/cpu.rs
@@ -13,8 +13,8 @@ use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{
|
||||
ControllIdentifier, ControllerInternal, Controllers, CpuResources, Resources, Subsystem,
|
||||
@@ -29,7 +29,7 @@ use crate::{
|
||||
pub struct CpuController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
v2: bool,
|
||||
v2: bool,
|
||||
}
|
||||
|
||||
/// The current state of the control group and its processes.
|
||||
@@ -112,7 +112,10 @@ impl<'a> From<&'a Subsystem> for &'a CpuController {
|
||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
||||
let mut string = String::new();
|
||||
match file.read_to_string(&mut string) {
|
||||
Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Ok(_) => string
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
||||
}
|
||||
}
|
||||
@@ -127,7 +130,7 @@ impl CpuController {
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
v2: v2,
|
||||
v2: v2,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +146,8 @@ impl CpuController {
|
||||
Ok(_) => Ok(s),
|
||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
||||
}
|
||||
}).unwrap_or("".to_string()),
|
||||
})
|
||||
.unwrap_or("".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,22 +219,21 @@ impl CpuController {
|
||||
return self.set_cfs_period(period);
|
||||
}
|
||||
let mut line = "max".to_string();
|
||||
if quota > 0 {
|
||||
line = quota.to_string();
|
||||
if quota > 0 {
|
||||
line = quota.to_string();
|
||||
}
|
||||
|
||||
let mut p = period;
|
||||
if period == 0 {
|
||||
// This default value is documented in
|
||||
// https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
|
||||
p = 100000
|
||||
}
|
||||
if period == 0 {
|
||||
// This default value is documented in
|
||||
// https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html
|
||||
p = 100000
|
||||
}
|
||||
line = format!("{} {}", line, p);
|
||||
self.open_path("cpu.max", true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(line.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path("cpu.max", true).and_then(|mut file| {
|
||||
file.write_all(line.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_rt_runtime(&self, us: i64) -> Result<()> {
|
||||
|
||||
@@ -11,8 +11,8 @@ use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
|
||||
|
||||
@@ -167,7 +167,9 @@ impl CpuAcctController {
|
||||
|
||||
/// Reset the statistics the kernel has gathered about the control group.
|
||||
pub fn reset(&self) -> Result<()> {
|
||||
self.open_path("cpuacct.usage", true)
|
||||
.and_then(|mut file| file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e)))
|
||||
self.open_path("cpuacct.usage", true).and_then(|mut file| {
|
||||
file.write_all(b"0")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{
|
||||
ControllIdentifier, ControllerInternal, Controllers, CpuResources, Resources, Subsystem,
|
||||
@@ -29,7 +29,7 @@ use crate::{
|
||||
pub struct CpuSetController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
v2: bool,
|
||||
v2: bool,
|
||||
}
|
||||
|
||||
/// The current state of the `cpuset` controller for this control group.
|
||||
@@ -111,7 +111,7 @@ impl ControllerInternal for CpuSetController {
|
||||
let res: &CpuResources = &res.cpu;
|
||||
|
||||
if res.update_values {
|
||||
if res.cpus.is_some(){
|
||||
if res.cpus.is_some() {
|
||||
let _ = self.set_cpus(res.cpus.as_ref().unwrap().as_str());
|
||||
}
|
||||
let _ = self.set_mems(&res.mems);
|
||||
@@ -120,9 +120,9 @@ impl ControllerInternal for CpuSetController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn post_create(&self){
|
||||
if self.is_v2(){
|
||||
return
|
||||
fn post_create(&self) {
|
||||
if self.is_v2() {
|
||||
return;
|
||||
}
|
||||
let current = self.get_path();
|
||||
let parent = match current.parent() {
|
||||
@@ -132,11 +132,11 @@ impl ControllerInternal for CpuSetController {
|
||||
|
||||
if current != self.get_base() {
|
||||
match copy_from_parent(current.to_str().unwrap(), "cpuset.cpus") {
|
||||
Ok(_)=>(),
|
||||
Ok(_) => (),
|
||||
Err(err) => error!("error create_dir for cpuset.cpus {:?}", err),
|
||||
}
|
||||
match copy_from_parent(current.to_str().unwrap(), "cpuset.mems") {
|
||||
Ok(_)=>(),
|
||||
Ok(_) => (),
|
||||
Err(err) => error!("error create_dir for cpuset.mems {:?}", err),
|
||||
}
|
||||
}
|
||||
@@ -148,10 +148,11 @@ fn find_no_empty_parent(from: &str, file: &str) -> Result<(String, Vec<PathBuf>)
|
||||
let mut v = vec![];
|
||||
|
||||
loop {
|
||||
let current_value = match ::std::fs::read_to_string(current_path.clone().join(file).to_str().unwrap()) {
|
||||
Ok(cpus) => String::from(cpus.trim()),
|
||||
Err(e) => return Err(Error::with_cause(ReadFailed, e)),
|
||||
};
|
||||
let current_value =
|
||||
match ::std::fs::read_to_string(current_path.clone().join(file).to_str().unwrap()) {
|
||||
Ok(cpus) => String::from(cpus.trim()),
|
||||
Err(e) => return Err(Error::with_cause(ReadFailed, e)),
|
||||
};
|
||||
|
||||
if current_value != "" {
|
||||
return Ok((current_value, v));
|
||||
@@ -221,7 +222,10 @@ fn read_string_from(mut file: File) -> Result<String> {
|
||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
||||
let mut string = String::new();
|
||||
match file.read_to_string(&mut string) {
|
||||
Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Ok(_) => string
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
||||
}
|
||||
}
|
||||
@@ -267,7 +271,7 @@ impl CpuSetController {
|
||||
/// Contructs a new `CpuSetController` with `oroot` serving as the root of the control group.
|
||||
pub fn new(oroot: PathBuf, v2: bool) -> Self {
|
||||
let mut root = oroot;
|
||||
if !v2{
|
||||
if !v2 {
|
||||
root.push(Self::controller_type().to_string());
|
||||
}
|
||||
Self {
|
||||
@@ -372,9 +376,11 @@ impl CpuSetController {
|
||||
self.open_path("cpuset.cpu_exclusive", true)
|
||||
.and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"1")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
} else {
|
||||
file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"0")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -385,9 +391,11 @@ impl CpuSetController {
|
||||
self.open_path("cpuset.mem_exclusive", true)
|
||||
.and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"1")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
} else {
|
||||
file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"0")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -422,9 +430,11 @@ impl CpuSetController {
|
||||
self.open_path("cpuset.mem_hardwall", true)
|
||||
.and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"1")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
} else {
|
||||
file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"0")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -435,9 +445,11 @@ impl CpuSetController {
|
||||
self.open_path("cpuset.sched_load_balance", true)
|
||||
.and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"1")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
} else {
|
||||
file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"0")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -459,9 +471,11 @@ impl CpuSetController {
|
||||
self.open_path("cpuset.memory_migrate", true)
|
||||
.and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"1")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
} else {
|
||||
file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"0")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -472,9 +486,11 @@ impl CpuSetController {
|
||||
self.open_path("cpuset.memory_spread_page", true)
|
||||
.and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"1")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
} else {
|
||||
file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"0")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -485,9 +501,11 @@ impl CpuSetController {
|
||||
self.open_path("cpuset.memory_spread_slab", true)
|
||||
.and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"1")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
} else {
|
||||
file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"0")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -504,9 +522,11 @@ impl CpuSetController {
|
||||
self.open_path("cpuset.memory_pressure_enabled", true)
|
||||
.and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"1")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
} else {
|
||||
file.write_all(b"0").map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(b"0")
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ use std::path::PathBuf;
|
||||
|
||||
use log::*;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{
|
||||
ControllIdentifier, ControllerInternal, Controllers, DeviceResource, DeviceResources,
|
||||
@@ -129,8 +129,7 @@ impl DevicePermissions {
|
||||
return Ok(v);
|
||||
}
|
||||
for e in s.chars() {
|
||||
let perm = DevicePermissions::from_char(e)
|
||||
.ok_or_else(|| Error::new(ParseError))?;
|
||||
let perm = DevicePermissions::from_char(e).ok_or_else(|| Error::new(ParseError))?;
|
||||
v.push(perm);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,10 +83,7 @@ impl Error {
|
||||
}
|
||||
}
|
||||
pub(crate) fn new(kind: ErrorKind) -> Self {
|
||||
Self {
|
||||
kind,
|
||||
cause: None,
|
||||
}
|
||||
Self { kind, cause: None }
|
||||
}
|
||||
|
||||
pub(crate) fn with_cause<E>(kind: ErrorKind, cause: E) -> Self
|
||||
|
||||
@@ -12,9 +12,8 @@ use std::path::{Path, PathBuf};
|
||||
use std::sync::mpsc::{self, Receiver};
|
||||
use std::thread;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
|
||||
use crate::error::*;
|
||||
|
||||
// notify_on_oom returns channel on which you can expect event about OOM,
|
||||
// if process died without OOM this channel will be closed.
|
||||
@@ -31,7 +30,10 @@ pub fn notify_on_oom_v1(key: &str, dir: &PathBuf) -> Result<Receiver<String>> {
|
||||
// level is one of "low", "medium", or "critical"
|
||||
pub fn notify_memory_pressure(key: &str, dir: &PathBuf, level: &str) -> Result<Receiver<String>> {
|
||||
if level != "low" && level != "medium" && level != "critical" {
|
||||
return Err(Error::from_string(format!("invalid pressure level {}", level)));
|
||||
return Err(Error::from_string(format!(
|
||||
"invalid pressure level {}",
|
||||
level
|
||||
)));
|
||||
}
|
||||
|
||||
register_memory_event(key, dir, "memory.pressure_level", level)
|
||||
@@ -46,7 +48,8 @@ fn register_memory_event(
|
||||
let path = cg_dir.join(event_name);
|
||||
let event_file = File::open(path).map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
|
||||
let eventfd = eventfd(0, EfdFlags::EFD_CLOEXEC).map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
let eventfd =
|
||||
eventfd(0, EfdFlags::EFD_CLOEXEC).map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
|
||||
let event_control_path = cg_dir.join("cgroup.event_control");
|
||||
let data;
|
||||
@@ -71,8 +74,7 @@ fn register_memory_event(
|
||||
Err(err) => {
|
||||
return;
|
||||
}
|
||||
Ok(_) => {
|
||||
}
|
||||
Ok(_) => {}
|
||||
}
|
||||
|
||||
// When a cgroup is destroyed, an event is sent to eventfd.
|
||||
@@ -85,4 +87,4 @@ fn register_memory_event(
|
||||
});
|
||||
|
||||
Ok(receiver)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subs
|
||||
pub struct FreezerController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
v2: bool,
|
||||
v2: bool,
|
||||
}
|
||||
|
||||
/// The current state of the control group
|
||||
@@ -90,7 +90,7 @@ impl FreezerController {
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
v2: v2,
|
||||
v2: v2,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ pub struct V2 {
|
||||
}
|
||||
|
||||
impl Hierarchy for V1 {
|
||||
|
||||
fn v2(&self) -> bool {
|
||||
false
|
||||
}
|
||||
@@ -71,7 +70,10 @@ impl Hierarchy for V1 {
|
||||
subs.push(Subsystem::Devices(DevicesController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::Freezer) {
|
||||
subs.push(Subsystem::Freezer(FreezerController::new(self.root(), false)));
|
||||
subs.push(Subsystem::Freezer(FreezerController::new(
|
||||
self.root(),
|
||||
false,
|
||||
)));
|
||||
}
|
||||
if self.check_support(Controllers::NetCls) {
|
||||
subs.push(Subsystem::NetCls(NetClsController::new(self.root())));
|
||||
@@ -86,20 +88,26 @@ impl Hierarchy for V1 {
|
||||
subs.push(Subsystem::NetPrio(NetPrioController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::HugeTlb) {
|
||||
subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root(), false)));
|
||||
subs.push(Subsystem::HugeTlb(HugeTlbController::new(
|
||||
self.root(),
|
||||
false,
|
||||
)));
|
||||
}
|
||||
if self.check_support(Controllers::Rdma) {
|
||||
subs.push(Subsystem::Rdma(RdmaController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::Systemd) {
|
||||
subs.push(Subsystem::Systemd(SystemdController::new(self.root(), false)));
|
||||
subs.push(Subsystem::Systemd(SystemdController::new(
|
||||
self.root(),
|
||||
false,
|
||||
)));
|
||||
}
|
||||
|
||||
subs
|
||||
}
|
||||
|
||||
fn root_control_group(&self) -> Cgroup {
|
||||
let b : &Hierarchy = self as &Hierarchy;
|
||||
let b: &Hierarchy = self as &Hierarchy;
|
||||
Cgroup::load(Box::new(&*b), "".to_string())
|
||||
}
|
||||
|
||||
@@ -136,17 +144,37 @@ impl Hierarchy for V2 {
|
||||
|
||||
let controllers = ret.unwrap().trim().to_string();
|
||||
let controller_list: Vec<&str> = controllers.split(' ').collect();
|
||||
|
||||
|
||||
for s in controller_list {
|
||||
match s {
|
||||
"cpu" => {subs.push(Subsystem::Cpu(CpuController::new(self.root(), true)));},
|
||||
"io" => {subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), true)));},
|
||||
"cpuset" => {subs.push(Subsystem::CpuSet(CpuSetController::new(self.root(), true)));},
|
||||
"memory" => {subs.push(Subsystem::Mem(MemController::new(self.root(), true)));},
|
||||
"pids" => {subs.push(Subsystem::Pid(PidController::new(self.root(), true)));},
|
||||
"freezer" => {subs.push(Subsystem::Freezer(FreezerController::new(self.root(), true)));},
|
||||
"hugetlb" => {subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root(), true)));},
|
||||
_ => {},
|
||||
"cpu" => {
|
||||
subs.push(Subsystem::Cpu(CpuController::new(self.root(), true)));
|
||||
}
|
||||
"io" => {
|
||||
subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), true)));
|
||||
}
|
||||
"cpuset" => {
|
||||
subs.push(Subsystem::CpuSet(CpuSetController::new(self.root(), true)));
|
||||
}
|
||||
"memory" => {
|
||||
subs.push(Subsystem::Mem(MemController::new(self.root(), true)));
|
||||
}
|
||||
"pids" => {
|
||||
subs.push(Subsystem::Pid(PidController::new(self.root(), true)));
|
||||
}
|
||||
"freezer" => {
|
||||
subs.push(Subsystem::Freezer(FreezerController::new(
|
||||
self.root(),
|
||||
true,
|
||||
)));
|
||||
}
|
||||
"hugetlb" => {
|
||||
subs.push(Subsystem::HugeTlb(HugeTlbController::new(
|
||||
self.root(),
|
||||
true,
|
||||
)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +182,7 @@ impl Hierarchy for V2 {
|
||||
}
|
||||
|
||||
fn root_control_group(&self) -> Cgroup {
|
||||
let b : &Hierarchy = self as &Hierarchy;
|
||||
let b: &Hierarchy = self as &Hierarchy;
|
||||
Cgroup::load(Box::new(&*b), "".to_string())
|
||||
}
|
||||
|
||||
@@ -195,7 +223,7 @@ pub fn is_cgroup2_unified_mode() -> bool {
|
||||
let path = Path::new(UNIFIED_MOUNTPOINT);
|
||||
let fs_stat = statfs::statfs(path);
|
||||
if fs_stat.is_err() {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME notwork, nix will not compile CGROUP2_SUPER_MAGIC because not(target_env = "musl")
|
||||
@@ -208,10 +236,10 @@ pub const INIT_CGROUP_PATHS: &'static str = "/proc/1/cgroup";
|
||||
pub fn is_cgroup2_unified_mode() -> bool {
|
||||
let lines = fs::read_to_string(INIT_CGROUP_PATHS);
|
||||
if lines.is_err() {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
for line in lines.unwrap().lines(){
|
||||
for line in lines.unwrap().lines() {
|
||||
let fields: Vec<&str> = line.split(':').collect();
|
||||
if fields.len() != 3 {
|
||||
continue;
|
||||
@@ -227,7 +255,7 @@ pub fn is_cgroup2_unified_mode() -> bool {
|
||||
pub fn auto() -> Box<dyn Hierarchy> {
|
||||
if is_cgroup2_unified_mode() {
|
||||
Box::new(V2::new())
|
||||
}else{
|
||||
} else {
|
||||
Box::new(V1::new())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,13 +12,12 @@ use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
use crate::flat_keyed_to_vec;
|
||||
|
||||
use crate::{
|
||||
ControllIdentifier, ControllerInternal, Controllers, HugePageResources, Resources,
|
||||
Subsystem,
|
||||
ControllIdentifier, ControllerInternal, Controllers, HugePageResources, Resources, Subsystem,
|
||||
};
|
||||
|
||||
/// A controller that allows controlling the `hugetlb` subsystem of a Cgroup.
|
||||
@@ -27,10 +26,10 @@ use crate::{
|
||||
/// the control group.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HugeTlbController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
sizes: Vec<String>,
|
||||
v2: bool,
|
||||
v2: bool,
|
||||
}
|
||||
|
||||
impl ControllerInternal for HugeTlbController {
|
||||
@@ -90,7 +89,10 @@ impl<'a> From<&'a Subsystem> for &'a HugeTlbController {
|
||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
||||
let mut string = String::new();
|
||||
match file.read_to_string(&mut string) {
|
||||
Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Ok(_) => string
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
||||
}
|
||||
}
|
||||
@@ -107,7 +109,7 @@ impl HugeTlbController {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
sizes: sizes,
|
||||
v2: v2,
|
||||
v2: v2,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,7 +117,7 @@ impl HugeTlbController {
|
||||
pub fn size_supported(&self, hugetlb_size: &str) -> bool {
|
||||
for s in &self.sizes {
|
||||
if s == hugetlb_size {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
@@ -130,7 +132,10 @@ impl HugeTlbController {
|
||||
.and_then(flat_keyed_to_vec)
|
||||
.and_then(|x| {
|
||||
if x.len() == 0 {
|
||||
return Err(Error::from_string(format!("get empty from hugetlb.{}.events", hugetlb_size)));
|
||||
return Err(Error::from_string(format!(
|
||||
"get empty from hugetlb.{}.events",
|
||||
hugetlb_size
|
||||
)));
|
||||
}
|
||||
Ok(x[0].1 as u64)
|
||||
})
|
||||
@@ -168,7 +173,8 @@ impl HugeTlbController {
|
||||
self.open_path(
|
||||
&format!("hugetlb.{}.max_usage_in_bytes", hugetlb_size),
|
||||
false,
|
||||
).and_then(read_u64_from)
|
||||
)
|
||||
.and_then(read_u64_from)
|
||||
}
|
||||
|
||||
/// Set the limit (in bytes) of how much memory can be backed by hugepages of a certain size
|
||||
@@ -178,15 +184,13 @@ impl HugeTlbController {
|
||||
if self.v2 {
|
||||
file = format!("hugetlb.{}.max", hugetlb_size);
|
||||
}
|
||||
self.open_path(&file, true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path(&file, true).and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub const HUGEPAGESIZE_DIR: &'static str = "/sys/kernel/mm/hugepages";
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
@@ -206,7 +210,7 @@ fn get_hugepage_sizes() -> Result<Vec<String>> {
|
||||
if parts.len() != 2 {
|
||||
continue;
|
||||
}
|
||||
let bmap= get_binary_size_map();
|
||||
let bmap = get_binary_size_map();
|
||||
let size = parse_size(parts[1], &bmap)?;
|
||||
let dabbrs = get_decimal_abbrs();
|
||||
m.push(custom_size(size as f64, 1024.0, &dabbrs));
|
||||
@@ -215,7 +219,6 @@ fn get_hugepage_sizes() -> Result<Vec<String>> {
|
||||
Ok(m)
|
||||
}
|
||||
|
||||
|
||||
pub const KB: u128 = 1000;
|
||||
pub const MB: u128 = 1000 * KB;
|
||||
pub const GB: u128 = 1000 * MB;
|
||||
@@ -228,7 +231,6 @@ pub const GiB: u128 = 1024 * MiB;
|
||||
pub const TiB: u128 = 1024 * GiB;
|
||||
pub const PiB: u128 = 1024 * TiB;
|
||||
|
||||
|
||||
pub fn get_binary_size_map() -> HashMap<String, u128> {
|
||||
let mut m = HashMap::new();
|
||||
m.insert("k".to_string(), KiB);
|
||||
@@ -249,7 +251,7 @@ pub fn get_decimal_size_map() -> HashMap<String, u128> {
|
||||
m
|
||||
}
|
||||
|
||||
pub fn get_decimal_abbrs() -> Vec<String> {
|
||||
pub fn get_decimal_abbrs() -> Vec<String> {
|
||||
let m = vec![
|
||||
"B".to_string(),
|
||||
"KB".to_string(),
|
||||
@@ -275,7 +277,7 @@ fn parse_size(s: &str, m: &HashMap<String, u128>) -> Result<u128> {
|
||||
let num = caps.name("num");
|
||||
let size: u128 = if num.is_some() {
|
||||
let n = num.unwrap().as_str().trim().parse::<u128>();
|
||||
if n.is_err(){
|
||||
if n.is_err() {
|
||||
return Err(Error::new(InvalidBytesSize));
|
||||
}
|
||||
n.unwrap()
|
||||
@@ -307,4 +309,3 @@ fn custom_size(mut size: f64, base: f64, m: &Vec<String>) -> String {
|
||||
|
||||
format!("{}{}", size, m[i].as_str())
|
||||
}
|
||||
|
||||
|
||||
59
src/lib.rs
59
src/lib.rs
@@ -8,11 +8,12 @@ use log::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, BufRead, BufReader, Write};
|
||||
use std::io::{BufRead, BufReader, Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub mod blkio;
|
||||
pub mod cgroup;
|
||||
pub mod cgroup_builder;
|
||||
pub mod cpu;
|
||||
pub mod cpuacct;
|
||||
pub mod cpuset;
|
||||
@@ -29,15 +30,14 @@ pub mod perf_event;
|
||||
pub mod pid;
|
||||
pub mod rdma;
|
||||
pub mod systemd;
|
||||
pub mod cgroup_builder;
|
||||
|
||||
use crate::blkio::BlkIoController;
|
||||
use crate::cpu::CpuController;
|
||||
use crate::cpuacct::CpuAcctController;
|
||||
use crate::cpuset::CpuSetController;
|
||||
use crate::devices::DevicesController;
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
use crate::freezer::FreezerController;
|
||||
use crate::hugetlb::HugeTlbController;
|
||||
use crate::memory::MemController;
|
||||
@@ -136,8 +136,7 @@ mod sealed {
|
||||
fn get_base(&self) -> &PathBuf;
|
||||
|
||||
/// Hooks running after controller crated, if have
|
||||
fn post_create(&self){
|
||||
}
|
||||
fn post_create(&self) {}
|
||||
|
||||
fn is_v2(&self) -> bool {
|
||||
false
|
||||
@@ -189,7 +188,6 @@ mod sealed {
|
||||
|
||||
std::path::Path::new(p).exists()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +225,10 @@ pub trait Controller {
|
||||
fn v2(&self) -> bool;
|
||||
}
|
||||
|
||||
impl<T> Controller for T where T: ControllerInternal {
|
||||
impl<T> Controller for T
|
||||
where
|
||||
T: ControllerInternal,
|
||||
{
|
||||
fn control_type(&self) -> Controllers {
|
||||
ControllerInternal::control_type(self)
|
||||
}
|
||||
@@ -244,7 +245,8 @@ impl<T> Controller for T where T: ControllerInternal {
|
||||
|
||||
/// Create this controller
|
||||
fn create(&self) {
|
||||
self.verify_path().expect(format!("path should be valid: {:?}", self.path()).as_str());
|
||||
self.verify_path()
|
||||
.expect(format!("path should be valid: {:?}", self.path()).as_str());
|
||||
|
||||
match ::std::fs::create_dir_all(self.get_path()) {
|
||||
Ok(_) => self.post_create(),
|
||||
@@ -293,13 +295,13 @@ impl<T> Controller for T where T: ControllerInternal {
|
||||
}
|
||||
}
|
||||
Ok(v.into_iter().map(CgroupPid::from).collect())
|
||||
}).unwrap_or(vec![])
|
||||
})
|
||||
.unwrap_or(vec![])
|
||||
}
|
||||
|
||||
fn v2(&self) -> bool {
|
||||
self.is_v2()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
@@ -641,8 +643,6 @@ impl Subsystem {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// The values for `memory.hight` or `pids.max`
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum MaxValue {
|
||||
@@ -676,7 +676,7 @@ impl MaxValue {
|
||||
|
||||
pub fn parse_max_value(s: &String) -> Result<MaxValue> {
|
||||
if s.trim() == "max" {
|
||||
return Ok(MaxValue::Max)
|
||||
return Ok(MaxValue::Max);
|
||||
}
|
||||
match s.trim().parse() {
|
||||
Ok(val) => Ok(MaxValue::Value(val)),
|
||||
@@ -689,18 +689,20 @@ pub fn parse_max_value(s: &String) -> Result<MaxValue> {
|
||||
// KEY1 VAL1\n
|
||||
pub fn flat_keyed_to_vec(mut file: File) -> Result<Vec<(String, i64)>> {
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content).map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
file.read_to_string(&mut content)
|
||||
.map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
|
||||
let mut v = Vec::new();
|
||||
for line in content.lines() {
|
||||
let parts: Vec<&str> = line.split(' ').collect();
|
||||
if parts.len() == 2 {
|
||||
match parts[1].parse::<i64>() {
|
||||
Ok(i) => { v.push((parts[0].to_string(), i)); } ,
|
||||
Err(_) => {},
|
||||
Ok(i) => {
|
||||
v.push((parts[0].to_string(), i));
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
@@ -710,18 +712,20 @@ pub fn flat_keyed_to_vec(mut file: File) -> Result<Vec<(String, i64)>> {
|
||||
// KEY1 VAL1\n
|
||||
pub fn flat_keyed_to_hashmap(mut file: File) -> Result<HashMap<String, i64>> {
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content).map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
file.read_to_string(&mut content)
|
||||
.map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
|
||||
let mut h = HashMap::new();
|
||||
for line in content.lines() {
|
||||
let parts: Vec<&str> = line.split(' ').collect();
|
||||
if parts.len() == 2 {
|
||||
match parts[1].parse::<i64>() {
|
||||
Ok(i) => { h.insert(parts[0].to_string(), i); } ,
|
||||
Err(_) => {},
|
||||
Ok(i) => {
|
||||
h.insert(parts[0].to_string(), i);
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Ok(h)
|
||||
}
|
||||
@@ -731,7 +735,8 @@ pub fn flat_keyed_to_hashmap(mut file: File) -> Result<HashMap<String, i64>> {
|
||||
// KEY1 SUB_KEY0=VAL10 SUB_KEY1=VAL11...
|
||||
pub fn nested_keyed_to_hashmap(mut file: File) -> Result<HashMap<String, HashMap<String, i64>>> {
|
||||
let mut content = String::new();
|
||||
file.read_to_string(&mut content).map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
file.read_to_string(&mut content)
|
||||
.map_err(|e| Error::with_cause(ReadFailed, e))?;
|
||||
|
||||
let mut h = HashMap::new();
|
||||
for line in content.lines() {
|
||||
@@ -744,8 +749,10 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result<HashMap<String, HashMap
|
||||
let fields: Vec<&str> = item.split('=').collect();
|
||||
if fields.len() == 2 {
|
||||
match fields[1].parse::<i64>() {
|
||||
Ok(i) => { th.insert(fields[0].to_string(), i); } ,
|
||||
Err(_) => {},
|
||||
Ok(i) => {
|
||||
th.insert(fields[0].to_string(), i);
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -759,7 +766,5 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result<HashMap<String, HashMap
|
||||
/// with error: `Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" }`
|
||||
pub fn libc_rmdir(p: &str) {
|
||||
// with int return value
|
||||
let _ = unsafe {
|
||||
libc::rmdir(p.as_ptr() as *const i8)
|
||||
};
|
||||
let _ = unsafe { libc::rmdir(p.as_ptr() as *const i8) };
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc::{Receiver};
|
||||
use std::sync::mpsc::Receiver;
|
||||
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
@@ -21,7 +21,8 @@ use crate::events;
|
||||
use crate::flat_keyed_to_hashmap;
|
||||
|
||||
use crate::{
|
||||
ControllIdentifier, ControllerInternal, Controllers, MaxValue, MemoryResources, Resources, Subsystem,
|
||||
ControllIdentifier, ControllerInternal, Controllers, MaxValue, MemoryResources, Resources,
|
||||
Subsystem,
|
||||
};
|
||||
|
||||
/// A controller that allows controlling the `memory` subsystem of a Cgroup.
|
||||
@@ -33,10 +34,9 @@ use crate::{
|
||||
pub struct MemController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
v2: bool,
|
||||
v2: bool,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
pub struct SetMemory {
|
||||
pub low: Option<MaxValue>,
|
||||
@@ -476,25 +476,29 @@ impl MemController {
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
v2: v2,
|
||||
v2: v2,
|
||||
}
|
||||
}
|
||||
|
||||
// for v2
|
||||
pub fn set_mem(&self, m: SetMemory) -> Result<()> {
|
||||
let values = vec![(m.high, "memory.high"),(m.low, "memory.low"),(m.max, "memory.max"),(m.min, "memory.min")];
|
||||
for value in values{
|
||||
pub fn set_mem(&self, m: SetMemory) -> Result<()> {
|
||||
let values = vec![
|
||||
(m.high, "memory.high"),
|
||||
(m.low, "memory.low"),
|
||||
(m.max, "memory.max"),
|
||||
(m.min, "memory.min"),
|
||||
];
|
||||
for value in values {
|
||||
let v = value.0;
|
||||
let f = value.1;
|
||||
if v.is_some() {
|
||||
let v = v.unwrap().to_string();
|
||||
self.open_path(f, true)
|
||||
.and_then(|mut file| {
|
||||
self.open_path(f, true).and_then(|mut file| {
|
||||
file.write_all(v.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -652,9 +656,8 @@ impl MemController {
|
||||
fail_cnt: self
|
||||
.open_path("memory.swap.events", false)
|
||||
.and_then(flat_keyed_to_hashmap)
|
||||
.and_then(|x| {
|
||||
Ok(*x.get("fail").unwrap_or(&0) as u64)
|
||||
}).unwrap(),
|
||||
.and_then(|x| Ok(*x.get("fail").unwrap_or(&0) as u64))
|
||||
.unwrap(),
|
||||
limit_in_bytes: self
|
||||
.open_path("memory.swap.max", false)
|
||||
.and_then(read_i64_from)
|
||||
@@ -735,11 +738,10 @@ impl MemController {
|
||||
if self.v2 {
|
||||
file = "memory.max";
|
||||
}
|
||||
self.open_path(file, true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path(file, true).and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
|
||||
/// Set the kernel memory limit of the control group, in bytes.
|
||||
@@ -757,11 +759,10 @@ impl MemController {
|
||||
if self.v2 {
|
||||
file = "memory.swap.max";
|
||||
}
|
||||
self.open_path(file, true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path(file, true).and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
|
||||
/// Set how much kernel memory can be used for TCP-related buffers by the control group.
|
||||
@@ -782,11 +783,10 @@ impl MemController {
|
||||
if self.v2 {
|
||||
file = "memory.low"
|
||||
}
|
||||
self.open_path(file, true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
self.open_path(file, true).and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
|
||||
/// Set how likely the kernel is to swap out parts of the address space used by the control
|
||||
@@ -809,10 +809,10 @@ impl MemController {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn register_oom_event(&self, key: &str) -> Result<Receiver<String>>{
|
||||
if self.v2{
|
||||
pub fn register_oom_event(&self, key: &str) -> Result<Receiver<String>> {
|
||||
if self.v2 {
|
||||
events::notify_on_oom_v2(key, self.get_path())
|
||||
}else {
|
||||
} else {
|
||||
events::notify_on_oom_v1(key, self.get_path())
|
||||
}
|
||||
}
|
||||
@@ -870,10 +870,10 @@ fn read_string_from(mut file: File) -> Result<String> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
use crate::memory::{
|
||||
parse_memory_stat, parse_numa_stat, parse_oom_control, MemoryStat, NumaStat, OomControl,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
|
||||
static GOOD_VALUE: &str = "\
|
||||
total=51189 N0=51189 N1=123
|
||||
|
||||
@@ -11,12 +11,11 @@ use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{
|
||||
ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources,
|
||||
Subsystem,
|
||||
ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, Subsystem,
|
||||
};
|
||||
|
||||
/// A controller that allows controlling the `net_cls` subsystem of a Cgroup.
|
||||
@@ -81,7 +80,10 @@ impl<'a> From<&'a Subsystem> for &'a NetClsController {
|
||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
||||
let mut string = String::new();
|
||||
match file.read_to_string(&mut string) {
|
||||
Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Ok(_) => string
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
||||
}
|
||||
}
|
||||
@@ -102,7 +104,8 @@ impl NetClsController {
|
||||
self.open_path("net_cls.classid", true)
|
||||
.and_then(|mut file| {
|
||||
let s = format!("{:#08X}", class);
|
||||
file.write_all(s.as_ref()).map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
file.write_all(s.as_ref())
|
||||
.map_err(|e| Error::with_cause(WriteFailed, e))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,11 @@ use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{
|
||||
ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources,
|
||||
Subsystem,
|
||||
ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, Subsystem,
|
||||
};
|
||||
|
||||
/// A controller that allows controlling the `net_prio` subsystem of a Cgroup.
|
||||
@@ -82,7 +81,10 @@ impl<'a> From<&'a Subsystem> for &'a NetPrioController {
|
||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
||||
let mut string = String::new();
|
||||
match file.read_to_string(&mut string) {
|
||||
Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Ok(_) => string
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
||||
}
|
||||
}
|
||||
|
||||
14
src/pid.rs
14
src/pid.rs
@@ -12,11 +12,12 @@ use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{
|
||||
ControllIdentifier, ControllerInternal, Controllers, MaxValue, parse_max_value, PidResources, Resources, Subsystem,
|
||||
parse_max_value, ControllIdentifier, ControllerInternal, Controllers, MaxValue, PidResources,
|
||||
Resources, Subsystem,
|
||||
};
|
||||
|
||||
/// A controller that allows controlling the `pids` subsystem of a Cgroup.
|
||||
@@ -24,7 +25,7 @@ use crate::{
|
||||
pub struct PidController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
v2: bool,
|
||||
v2: bool,
|
||||
}
|
||||
|
||||
impl ControllerInternal for PidController {
|
||||
@@ -94,7 +95,10 @@ impl<'a> From<&'a Subsystem> for &'a PidController {
|
||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
||||
let mut string = String::new();
|
||||
match file.read_to_string(&mut string) {
|
||||
Ok(_) => string.trim().parse().map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Ok(_) => string
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
||||
}
|
||||
}
|
||||
@@ -110,7 +114,7 @@ impl PidController {
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
v2: v2,
|
||||
v2: v2,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
//!
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::error::*;
|
||||
use crate::error::ErrorKind::*;
|
||||
use crate::error::*;
|
||||
|
||||
use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
|
||||
|
||||
@@ -18,7 +18,7 @@ use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subs
|
||||
pub struct SystemdController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
v2: bool,
|
||||
v2: bool,
|
||||
}
|
||||
|
||||
impl ControllerInternal for SystemdController {
|
||||
@@ -64,14 +64,13 @@ impl SystemdController {
|
||||
/// Constructs a new `SystemdController` with `oroot` serving as the root of the control group.
|
||||
pub fn new(oroot: PathBuf, v2: bool) -> Self {
|
||||
let mut root = oroot;
|
||||
if !v2{
|
||||
if !v2 {
|
||||
root.push(Self::controller_type().to_string());
|
||||
}
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
v2: v2,
|
||||
v2: v2,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,15 +5,15 @@
|
||||
//
|
||||
|
||||
//! Some simple tests covering the builder pattern for control groups.
|
||||
use cgroups::*;
|
||||
use cgroups::cpu::*;
|
||||
use cgroups::devices::*;
|
||||
use cgroups::pid::*;
|
||||
use cgroups::memory::*;
|
||||
use cgroups::net_cls::*;
|
||||
use cgroups::hugetlb::*;
|
||||
use cgroups::blkio::*;
|
||||
use cgroups::cgroup_builder::*;
|
||||
use cgroups::cpu::*;
|
||||
use cgroups::devices::*;
|
||||
use cgroups::hugetlb::*;
|
||||
use cgroups::memory::*;
|
||||
use cgroups::net_cls::*;
|
||||
use cgroups::pid::*;
|
||||
use cgroups::*;
|
||||
|
||||
#[test]
|
||||
pub fn test_cpu_res_build() {
|
||||
@@ -21,8 +21,8 @@ pub fn test_cpu_res_build() {
|
||||
let h = Box::new(&*h);
|
||||
let cg: Cgroup = CgroupBuilder::new("test_cpu_res_build", h)
|
||||
.cpu()
|
||||
.shares(85)
|
||||
.done()
|
||||
.shares(85)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
@@ -40,10 +40,10 @@ pub fn test_memory_res_build() {
|
||||
let h = Box::new(&*h);
|
||||
let cg: Cgroup = CgroupBuilder::new("test_memory_res_build", h)
|
||||
.memory()
|
||||
.kernel_memory_limit(128 * 1024 * 1024)
|
||||
.swappiness(70)
|
||||
.memory_hard_limit(1024 * 1024 * 1024)
|
||||
.done()
|
||||
.kernel_memory_limit(128 * 1024 * 1024)
|
||||
.swappiness(70)
|
||||
.memory_hard_limit(1024 * 1024 * 1024)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
@@ -64,8 +64,8 @@ pub fn test_pid_res_build() {
|
||||
let h = Box::new(&*h);
|
||||
let cg: Cgroup = CgroupBuilder::new("test_pid_res_build", h)
|
||||
.pid()
|
||||
.maximum_number_of_processes(MaxValue::Value(123))
|
||||
.done()
|
||||
.maximum_number_of_processes(MaxValue::Value(123))
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
@@ -84,23 +84,23 @@ pub fn test_devices_res_build() {
|
||||
let h = Box::new(&*h);
|
||||
let cg: Cgroup = CgroupBuilder::new("test_devices_res_build", h)
|
||||
.devices()
|
||||
.device(1, 6, DeviceType::Char, true,
|
||||
vec![DevicePermissions::Read])
|
||||
.done()
|
||||
.device(1, 6, DeviceType::Char, true, vec![DevicePermissions::Read])
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
let c: &DevicesController = cg.controller_of().unwrap();
|
||||
assert!(c.allowed_devices().is_ok());
|
||||
assert_eq!(c.allowed_devices().unwrap(), vec![
|
||||
DeviceResource {
|
||||
allow: true,
|
||||
devtype: DeviceType::Char,
|
||||
major: 1,
|
||||
minor: 6,
|
||||
access: vec![DevicePermissions::Read],
|
||||
}
|
||||
]);
|
||||
assert_eq!(
|
||||
c.allowed_devices().unwrap(),
|
||||
vec![DeviceResource {
|
||||
allow: true,
|
||||
devtype: DeviceType::Char,
|
||||
major: 1,
|
||||
minor: 6,
|
||||
access: vec![DevicePermissions::Read],
|
||||
}]
|
||||
);
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
@@ -110,13 +110,13 @@ pub fn test_network_res_build() {
|
||||
let h = cgroups::hierarchies::auto();
|
||||
if h.v2() {
|
||||
// FIXME add cases for v2
|
||||
return
|
||||
return;
|
||||
}
|
||||
let h = Box::new(&*h);
|
||||
let cg: Cgroup = CgroupBuilder::new("test_network_res_build", h)
|
||||
.network()
|
||||
.class_id(1337)
|
||||
.done()
|
||||
.class_id(1337)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
@@ -132,19 +132,22 @@ pub fn test_hugepages_res_build() {
|
||||
let h = cgroups::hierarchies::auto();
|
||||
if h.v2() {
|
||||
// FIXME add cases for v2
|
||||
return
|
||||
return;
|
||||
}
|
||||
let h = Box::new(&*h);
|
||||
let cg: Cgroup = CgroupBuilder::new("test_hugepages_res_build", h)
|
||||
.hugepages()
|
||||
.limit("2MB".to_string(), 4 * 2 * 1024 * 1024)
|
||||
.done()
|
||||
.limit("2MB".to_string(), 4 * 2 * 1024 * 1024)
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
let c: &HugeTlbController = cg.controller_of().unwrap();
|
||||
assert!(c.limit_in_bytes(&"2MB".to_string()).is_ok());
|
||||
assert_eq!(c.limit_in_bytes(&"2MB".to_string()).unwrap(), 4 * 2 * 1024 * 1024);
|
||||
assert_eq!(
|
||||
c.limit_in_bytes(&"2MB".to_string()).unwrap(),
|
||||
4 * 2 * 1024 * 1024
|
||||
);
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
@@ -156,8 +159,8 @@ pub fn test_blkio_res_build() {
|
||||
let h = Box::new(&*h);
|
||||
let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build", h)
|
||||
.blkio()
|
||||
.weight(Some(100))
|
||||
.done()
|
||||
.weight(Some(100))
|
||||
.done()
|
||||
.build();
|
||||
|
||||
{
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
//
|
||||
|
||||
//! Simple unit tests about the control groups system.
|
||||
use cgroups::{Cgroup, CgroupPid, Hierarchy, Subsystem};
|
||||
use cgroups::memory::{MemController, SetMemory};
|
||||
use cgroups::Controller;
|
||||
use cgroups::{Cgroup, CgroupPid, Hierarchy, Subsystem};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[test]
|
||||
@@ -38,11 +38,10 @@ fn test_tasks_iterator() {
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_cgroup_with_relative_paths() {
|
||||
if cgroups::hierarchies::is_cgroup2_unified_mode() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
let h = cgroups::hierarchies::auto();
|
||||
let cgroup_root = h.root();
|
||||
@@ -60,14 +59,30 @@ fn test_cgroup_with_relative_paths() {
|
||||
let cgroup_path = c.path().to_str().unwrap();
|
||||
let relative_path = "/pids/";
|
||||
// cgroup_path = cgroup_root + relative_path + cgroup_name
|
||||
assert_eq!(cgroup_path, format!("{}{}{}", cgroup_root.to_str().unwrap(), relative_path, cgroup_name));
|
||||
},
|
||||
assert_eq!(
|
||||
cgroup_path,
|
||||
format!(
|
||||
"{}{}{}",
|
||||
cgroup_root.to_str().unwrap(),
|
||||
relative_path,
|
||||
cgroup_name
|
||||
)
|
||||
);
|
||||
}
|
||||
Subsystem::Mem(c) => {
|
||||
let cgroup_path = c.path().to_str().unwrap();
|
||||
// cgroup_path = cgroup_root + relative_path + cgroup_name
|
||||
assert_eq!(cgroup_path, format!("{}/memory{}/{}", cgroup_root.to_str().unwrap(), mem_relative_path, cgroup_name));
|
||||
},
|
||||
_ => {},
|
||||
assert_eq!(
|
||||
cgroup_path,
|
||||
format!(
|
||||
"{}/memory{}/{}",
|
||||
cgroup_root.to_str().unwrap(),
|
||||
mem_relative_path,
|
||||
cgroup_name
|
||||
)
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
cg.delete();
|
||||
@@ -76,14 +91,14 @@ fn test_cgroup_with_relative_paths() {
|
||||
#[test]
|
||||
fn test_cgroup_v2() {
|
||||
if !cgroups::hierarchies::is_cgroup2_unified_mode() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
let h = cgroups::hierarchies::auto();
|
||||
let h = Box::new(&*h);
|
||||
let cg = Cgroup::new_with_relative_paths(h, String::from("test_v2"), HashMap::new());
|
||||
|
||||
let mem_controller: &MemController = cg.controller_of().unwrap();
|
||||
let (mem, swp, rev) = (4 * 1024 * 1000, 2 * 1024* 1000, 1024 * 1000);
|
||||
let (mem, swp, rev) = (4 * 1024 * 1000, 2 * 1024 * 1000, 1024 * 1000);
|
||||
|
||||
let _ = mem_controller.set_limit(mem);
|
||||
let _ = mem_controller.set_memswap_limit(swp);
|
||||
|
||||
@@ -25,7 +25,6 @@ fn test_cpuset_memory_pressure_root_cg() {
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_cpuset_set_cpus() {
|
||||
let h = cgroups::hierarchies::auto();
|
||||
@@ -48,10 +47,11 @@ fn test_cpuset_set_cpus() {
|
||||
|
||||
let set = cpuset.cpuset();
|
||||
assert_eq!(1, set.cpus.len());
|
||||
assert_eq!((0,0), set.cpus[0]);
|
||||
assert_eq!((0, 0), set.cpus[0]);
|
||||
|
||||
// all cpus in system
|
||||
let cpus = fs::read_to_string("/sys/fs/cgroup/cpuset.cpus.effective").unwrap_or("".to_string());
|
||||
let cpus =
|
||||
fs::read_to_string("/sys/fs/cgroup/cpuset.cpus.effective").unwrap_or("".to_string());
|
||||
let cpus = cpus.trim();
|
||||
if cpus != "" {
|
||||
let r = cpuset.set_cpus(&cpus);
|
||||
@@ -93,4 +93,4 @@ fn test_cpuset_set_cpus_add_task() {
|
||||
assert_eq!(0, tasks.len());
|
||||
|
||||
cg.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use cgroups::{Cgroup, DeviceResource, Hierarchy};
|
||||
fn test_devices_parsing() {
|
||||
// now only v2
|
||||
if cgroups::hierarchies::is_cgroup2_unified_mode() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
let h = cgroups::hierarchies::auto();
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
//! Integration tests about the hugetlb subsystem
|
||||
use cgroups::hugetlb::HugeTlbController;
|
||||
use cgroups::{Cgroup, Hierarchy};
|
||||
use cgroups::Controller;
|
||||
use cgroups::{Cgroup, Hierarchy};
|
||||
|
||||
use cgroups::error::ErrorKind::*;
|
||||
use cgroups::error::*;
|
||||
@@ -15,7 +15,7 @@ use cgroups::error::*;
|
||||
fn test_hugetlb_sizes() {
|
||||
// now only v2
|
||||
if cgroups::hierarchies::is_cgroup2_unified_mode() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
let h = cgroups::hierarchies::auto();
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
//! Integration tests about the hugetlb subsystem
|
||||
use cgroups::memory::{MemController, SetMemory};
|
||||
use cgroups::{Cgroup, Hierarchy, MaxValue};
|
||||
use cgroups::Controller;
|
||||
use cgroups::{Cgroup, Hierarchy, MaxValue};
|
||||
|
||||
use cgroups::error::ErrorKind::*;
|
||||
use cgroups::error::*;
|
||||
@@ -24,7 +24,7 @@ fn test_disable_oom_killer() {
|
||||
assert_eq!(m.oom_control.oom_kill_disable, false);
|
||||
|
||||
// FIXME only v1
|
||||
if !mem_controller.v2(){
|
||||
if !mem_controller.v2() {
|
||||
// disable oom killer
|
||||
let r = mem_controller.disable_oom_killer();
|
||||
assert_eq!(r.is_err(), false);
|
||||
@@ -33,7 +33,6 @@ fn test_disable_oom_killer() {
|
||||
let m = mem_controller.memory_stat();
|
||||
assert_eq!(m.oom_control.oom_kill_disable, true);
|
||||
}
|
||||
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
@@ -42,7 +41,7 @@ fn test_disable_oom_killer() {
|
||||
fn set_mem_v2() {
|
||||
let h = cgroups::hierarchies::auto();
|
||||
if !h.v2() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
let h = Box::new(&*h);
|
||||
@@ -59,10 +58,10 @@ fn set_mem_v2() {
|
||||
assert_eq!(m.max, Some(MaxValue::Max));
|
||||
|
||||
// case 2: set parts
|
||||
let m = SetMemory{
|
||||
low: Some(MaxValue::Value(1024*1024* 2)),
|
||||
high: Some(MaxValue::Value(1024*1024*1024* 2)),
|
||||
min: Some(MaxValue::Value(1024*1024* 3)),
|
||||
let m = SetMemory {
|
||||
low: Some(MaxValue::Value(1024 * 1024 * 2)),
|
||||
high: Some(MaxValue::Value(1024 * 1024 * 1024 * 2)),
|
||||
min: Some(MaxValue::Value(1024 * 1024 * 3)),
|
||||
max: None,
|
||||
};
|
||||
let r = mem_controller.set_mem(m);
|
||||
@@ -70,17 +69,15 @@ fn set_mem_v2() {
|
||||
|
||||
let m = mem_controller.get_mem().unwrap();
|
||||
// get
|
||||
assert_eq!(m.low, Some(MaxValue::Value(1024*1024* 2)));
|
||||
assert_eq!(m.min, Some(MaxValue::Value(1024*1024* 3)));
|
||||
assert_eq!(m.high, Some(MaxValue::Value(1024*1024*1024* 2)));
|
||||
assert_eq!(m.low, Some(MaxValue::Value(1024 * 1024 * 2)));
|
||||
assert_eq!(m.min, Some(MaxValue::Value(1024 * 1024 * 3)));
|
||||
assert_eq!(m.high, Some(MaxValue::Value(1024 * 1024 * 1024 * 2)));
|
||||
assert_eq!(m.max, Some(MaxValue::Max));
|
||||
|
||||
|
||||
|
||||
// case 3: set parts
|
||||
let m = SetMemory{
|
||||
max: Some(MaxValue::Value(1024*1024*1024* 2)),
|
||||
min: Some(MaxValue::Value(1024*1024* 4)),
|
||||
let m = SetMemory {
|
||||
max: Some(MaxValue::Value(1024 * 1024 * 1024 * 2)),
|
||||
min: Some(MaxValue::Value(1024 * 1024 * 4)),
|
||||
high: Some(MaxValue::Max),
|
||||
low: None,
|
||||
};
|
||||
@@ -89,9 +86,9 @@ fn set_mem_v2() {
|
||||
|
||||
let m = mem_controller.get_mem().unwrap();
|
||||
// get
|
||||
assert_eq!(m.low, Some(MaxValue::Value(1024*1024* 2)));
|
||||
assert_eq!(m.min, Some(MaxValue::Value(1024*1024* 4)));
|
||||
assert_eq!(m.max, Some(MaxValue::Value(1024*1024*1024* 2)));
|
||||
assert_eq!(m.low, Some(MaxValue::Value(1024 * 1024 * 2)));
|
||||
assert_eq!(m.min, Some(MaxValue::Value(1024 * 1024 * 4)));
|
||||
assert_eq!(m.max, Some(MaxValue::Value(1024 * 1024 * 1024 * 2)));
|
||||
assert_eq!(m.high, Some(MaxValue::Max));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//
|
||||
|
||||
//! Integration tests about the pids subsystem
|
||||
use cgroups::pid::{PidController};
|
||||
use cgroups::pid::PidController;
|
||||
use cgroups::Controller;
|
||||
use cgroups::{Cgroup, CgroupPid, Hierarchy, MaxValue, PidResources, Resources};
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//
|
||||
|
||||
//! Integration test about setting resources using `apply()`
|
||||
use cgroups::pid::{PidController};
|
||||
use cgroups::pid::PidController;
|
||||
use cgroups::{Cgroup, Hierarchy, MaxValue, PidResources, Resources};
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user