mirror of
https://github.com/kata-containers/cgroups-rs.git
synced 2026-08-05 02:13:23 +00:00
4
.gitignore
vendored
4
.gitignore
vendored
@@ -8,3 +8,7 @@ Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
|
||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
@@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "cgroups-rs"
|
||||
version = "0.1.0"
|
||||
authors = ["Levente Kurusa <lkurusa@acm.org>"]
|
||||
|
||||
[dependencies]
|
||||
274
src/blkio.rs
Normal file
274
src/blkio.rs
Normal file
@@ -0,0 +1,274 @@
|
||||
/* block IO controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Read, Write};
|
||||
use std::fs::File;
|
||||
|
||||
use {BlkIoResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BlkIoController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BlkIoThrottle {
|
||||
pub io_service_bytes: String,
|
||||
pub io_service_bytes_recursive: String,
|
||||
pub io_serviced: String,
|
||||
pub io_serviced_recursive: String,
|
||||
pub read_bps_device: String,
|
||||
pub read_iops_device: String,
|
||||
pub write_bps_device: String,
|
||||
pub write_iops_device: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BlkIo {
|
||||
pub io_merged: String,
|
||||
pub io_merged_recursive: String,
|
||||
pub io_queued: String,
|
||||
pub io_queued_recursive: String,
|
||||
pub io_service_bytes: String,
|
||||
pub io_service_bytes_recursive: String,
|
||||
pub io_serviced: String,
|
||||
pub io_serviced_recursive: String,
|
||||
pub io_service_time: String,
|
||||
pub io_service_time_recursive: String,
|
||||
pub io_wait_time: String,
|
||||
pub io_wait_time_recursive: String,
|
||||
pub leaf_weight: u64,
|
||||
pub leaf_weight_device: String,
|
||||
pub sectors: String,
|
||||
pub sectors_recursive: String,
|
||||
pub throttle: BlkIoThrottle,
|
||||
pub time: String,
|
||||
pub time_recursive: String,
|
||||
pub weight: u64,
|
||||
pub weight_device: String,
|
||||
}
|
||||
|
||||
impl Controller for BlkIoController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::BlkIo }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, res: &Resources) {
|
||||
/* get the resources that apply to this controller */
|
||||
let res: &BlkIoResources = &res.blkio;
|
||||
|
||||
if res.update_values {
|
||||
self.set_weight(res.weight as u64);
|
||||
self.set_leaf_weight(res.leaf_weight as u64);
|
||||
|
||||
for dev in &res.weight_device {
|
||||
self.set_weight_for_device(format!("{}:{} {}",
|
||||
dev.major, dev.minor, dev.weight));
|
||||
}
|
||||
|
||||
for dev in &res.throttle_read_bps_device {
|
||||
self.throttle_read_bps_for_device(dev.major, dev.minor, dev.rate);
|
||||
}
|
||||
|
||||
for dev in &res.throttle_write_bps_device {
|
||||
self.throttle_write_bps_for_device(dev.major, dev.minor, dev.rate);
|
||||
}
|
||||
|
||||
for dev in &res.throttle_read_iops_device {
|
||||
self.throttle_read_iops_for_device(dev.major, dev.minor, dev.rate);
|
||||
}
|
||||
|
||||
for dev in &res.throttle_write_iops_device {
|
||||
self.throttle_write_iops_for_device(dev.major, dev.minor, dev.rate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for BlkIoController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::BlkIo
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a BlkIoController {
|
||||
fn from(sub: &'a Subsystem) -> &'a BlkIoController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::BlkIo(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_string_from(mut file: File) -> Option<String> {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}
|
||||
|
||||
fn read_u64_from(mut file: File) -> Option<u64> {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
string.trim().parse().ok()
|
||||
}
|
||||
|
||||
impl BlkIoController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
pub fn blkio(self: &Self) -> BlkIo {
|
||||
BlkIo {
|
||||
io_merged: self.open_path("blkio.io_merged", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_merged_recursive: self.open_path("blkio.io_merged_recursive", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_queued: self.open_path("blkio.io_queued", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_queued_recursive: self.open_path("blkio.io_queued_recursive", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_service_bytes: self.open_path("blkio.io_service_bytes", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_service_bytes_recursive: self.open_path("blkio.io_service_bytes_recursive", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_serviced: self.open_path("blkio.io_serviced", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_serviced_recursive: self.open_path("blkio.io_serviced_recursive", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_service_time: self.open_path("blkio.io_service_time", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_service_time_recursive: self.open_path("blkio.io_service_time_recursive", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_wait_time: self.open_path("blkio.io_wait_time", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_wait_time_recursive: self.open_path("blkio.io_wait_time_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(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_service_bytes_recursive: self.open_path("blkio.throttle.io_service_bytes_recursive", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
io_serviced: self.open_path("blkio.throttle.io_serviced", 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(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
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).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
time_recursive: self.open_path("blkio.time_recursive", false).and_then(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
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(|file| {
|
||||
read_string_from(file)
|
||||
}).unwrap_or("".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_leaf_weight(self: &Self, w: u64) {
|
||||
self.open_path("blkio.leaf_weight", true).and_then(|mut file| {
|
||||
file.write_all(w.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_leaf_weight_for_device(self: &Self, d: String) {
|
||||
self.open_path("blkio.leaf_weight_device", true).and_then(|mut file| {
|
||||
file.write_all(d.as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn reset_stats(self: &Self) {
|
||||
self.open_path("blkio.leaf_weight_device", true).and_then(|mut file| {
|
||||
file.write_all("1".to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn throttle_read_bps_for_device(self: &Self, major: u64, minor: u64, bps: u64) {
|
||||
self.open_path("blkio.throttle.read_bps_device", true).and_then(|mut file| {
|
||||
file.write_all(format!("{}:{} {}", major, minor, bps).to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn throttle_read_iops_for_device(self: &Self, major: u64, minor: u64, iops: u64) {
|
||||
self.open_path("blkio.throttle.read_iops_device", true).and_then(|mut file| {
|
||||
file.write_all(format!("{}:{} {}", major, minor, iops).to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn throttle_write_bps_for_device(self: &Self, major: u64, minor: u64, bps: u64) {
|
||||
self.open_path("blkio.throttle.write_bps_device", true).and_then(|mut file| {
|
||||
file.write_all(format!("{}:{} {}", major, minor, bps).to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn throttle_write_iops_for_device(self: &Self, major: u64, minor: u64, iops: u64) {
|
||||
self.open_path("blkio.throttle.write_iops_device", true).and_then(|mut file| {
|
||||
file.write_all(format!("{}:{} {}", major, minor, iops).to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_weight(self: &Self, w: u64) {
|
||||
self.open_path("blkio.leaf_weight", true).and_then(|mut file| {
|
||||
file.write_all(w.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_weight_for_device(self: &Self, d: String) {
|
||||
self.open_path("blkio.weight_device", true).and_then(|mut file| {
|
||||
file.write_all(d.as_ref()).ok()
|
||||
});
|
||||
}
|
||||
}
|
||||
83
src/cgroup.rs
Normal file
83
src/cgroup.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
use {CgroupPid, Resources, ControllIdentifier, Controller, Hierarchy, Subsystem};
|
||||
|
||||
use std::convert::From;
|
||||
|
||||
|
||||
/* Describe a cgroup in a simple fashion */
|
||||
pub struct Cgroup {
|
||||
/// Name of the cgroup
|
||||
//name: String,
|
||||
/// The list of subsystems that control this cgroup
|
||||
subsystems: Vec<Subsystem>,
|
||||
}
|
||||
|
||||
impl Cgroup {
|
||||
fn create(self: &Self) {
|
||||
for subsystem in &self.subsystems {
|
||||
subsystem.to_controller().create();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(hier: &Hierarchy, path: String, _resources: i64) -> Cgroup {
|
||||
let mut subsystems = hier.subsystems();
|
||||
subsystems = subsystems.into_iter().map(|x| x.enter(&path)).collect::<Vec<_>>();
|
||||
|
||||
let cg = Cgroup {
|
||||
//name: path,
|
||||
subsystems: subsystems,
|
||||
};
|
||||
|
||||
cg.create();
|
||||
cg
|
||||
}
|
||||
|
||||
pub fn subsystems(self: &Self) -> &Vec<Subsystem> {
|
||||
&self.subsystems
|
||||
}
|
||||
|
||||
pub fn delete(self: 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(),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn apply(self: &Self, res: &Resources) {
|
||||
for subsystem in &self.subsystems {
|
||||
subsystem.to_controller().apply(res);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn controller_of<'a, T>(self: &'a Self) -> Option<&'a T>
|
||||
where &'a T: From<&'a Subsystem>,
|
||||
T: Controller + ControllIdentifier,
|
||||
{
|
||||
for i in &self.subsystems {
|
||||
if i.to_controller().control_type() == T::controller_type() {
|
||||
/*
|
||||
* N.B.:
|
||||
* https://play.rust-lang.org/?gist=978b2846bacebdaa00be62374f4f4334&version=stable&mode=debug&edition=2015
|
||||
*/
|
||||
return Some(i.into());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn add_task(self: &Self, pid: CgroupPid) {
|
||||
self.subsystems().iter().for_each(|sub| sub.to_controller().add_task(&pid));
|
||||
}
|
||||
}
|
||||
94
src/cpu.rs
Normal file
94
src/cpu.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
/* CPU controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use {CpuResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CpuController{
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Cpu {
|
||||
pub stat: String,
|
||||
}
|
||||
|
||||
impl Controller for CpuController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::Cpu}
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, res: &Resources) {
|
||||
/* get the resources that apply to this controller */
|
||||
let res: &CpuResources = &res.cpu;
|
||||
|
||||
if res.update_values {
|
||||
/* apply pid_max */
|
||||
self.set_shares(res.shares);
|
||||
self.set_cfs_period(res.period);
|
||||
self.set_cfs_quota(res.quota as u64);
|
||||
/* TODO: rt properties (CONFIG_RT_GROUP_SCHED) are not yet supported */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for CpuController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::Cpu
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a CpuController {
|
||||
fn from(sub: &'a Subsystem) -> &'a CpuController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::Cpu(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CpuController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
pub fn cpu(self: &Self) -> Cpu {
|
||||
Cpu {
|
||||
stat: self.open_path("cpu.stat", false).and_then(|mut file| {
|
||||
let mut s = String::new();
|
||||
let _ = file.read_to_string(&mut s);
|
||||
Some(s)
|
||||
}).unwrap_or("".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_shares(self: &Self, shares: u64) {
|
||||
self.open_path("cpu.shares", true).and_then(|mut file| {
|
||||
file.write_all(shares.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_cfs_period(self: &Self, us: u64) {
|
||||
self.open_path("cpu.cfs_period_us", true).and_then(|mut file| {
|
||||
file.write_all(us.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_cfs_quota(self: &Self, us: u64) {
|
||||
self.open_path("cpu.cfs_quota_us", true).and_then(|mut file| {
|
||||
file.write_all(us.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
}
|
||||
118
src/cpuacct.rs
Normal file
118
src/cpuacct.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
/* cpuacct controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Read, Write};
|
||||
use std::fs::File;
|
||||
|
||||
use {Controllers, Resources, Subsystem, ControllIdentifier, Controller};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CpuAcctController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
pub struct CpuAcct {
|
||||
pub stat: String,
|
||||
pub usage: u64,
|
||||
pub usage_all: String,
|
||||
pub usage_percpu: String,
|
||||
pub usage_percpu_sys: String,
|
||||
pub usage_percpu_user: String,
|
||||
pub usage_sys: u64,
|
||||
pub usage_user: u64,
|
||||
}
|
||||
|
||||
impl Controller for CpuAcctController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::CpuAcct }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, _res: &Resources) {
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for CpuAcctController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::CpuAcct
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a CpuAcctController {
|
||||
fn from(sub: &'a Subsystem) -> &'a CpuAcctController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::CpuAcct(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_u64_from(mut file: File) -> Option<u64> {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
string.trim().parse().ok()
|
||||
}
|
||||
|
||||
impl CpuAcctController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
pub fn cpuacct(self: &Self) -> CpuAcct {
|
||||
CpuAcct {
|
||||
stat: self.open_path("cpuacct.stat", false)
|
||||
.and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).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(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap_or("".to_string()),
|
||||
usage_percpu: self.open_path("cpuacct.usage_percpu", false)
|
||||
.and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap_or("".to_string()),
|
||||
usage_percpu_sys: self.open_path("cpuacct.usage_percpu_sys", false)
|
||||
.and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap_or("".to_string()),
|
||||
usage_percpu_user: self.open_path("cpuacct.usage_percpu_user", false)
|
||||
.and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).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),
|
||||
}
|
||||
}
|
||||
pub fn reset(self: &Self) {
|
||||
self.open_path("cpuacct.usage", true).and_then(|mut file| {
|
||||
file.write_all(b"0").ok()
|
||||
});
|
||||
}
|
||||
}
|
||||
267
src/cpuset.rs
Normal file
267
src/cpuset.rs
Normal file
@@ -0,0 +1,267 @@
|
||||
/* cpuset controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Read, Write};
|
||||
use std::fs::File;
|
||||
|
||||
use {CpuResources, Resources, Controller, ControllIdentifier, Subsystem, Controllers};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CpuSetController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
pub struct CpuSet {
|
||||
pub cpu_exclusive: bool,
|
||||
pub cpus: String,
|
||||
pub effective_cpus: String,
|
||||
pub effective_mems: String,
|
||||
pub mem_exclusive: bool,
|
||||
pub mem_hardwall: bool,
|
||||
pub memory_migrate: bool,
|
||||
pub memory_pressure: u64,
|
||||
pub memory_pressure_enabled: Option<bool>,
|
||||
pub memory_spread_page: bool,
|
||||
pub memory_spread_slab: bool,
|
||||
pub mems: String,
|
||||
pub sched_load_balance: bool,
|
||||
pub sched_relax_domain_level: u64,
|
||||
|
||||
}
|
||||
|
||||
impl Controller for CpuSetController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::CpuSet }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, res: &Resources) {
|
||||
/* get the resources that apply to this controller */
|
||||
let res: &CpuResources = &res.cpu;
|
||||
|
||||
if res.update_values {
|
||||
/* apply pid_max */
|
||||
self.set_cpus(&res.cpus);
|
||||
self.set_mems(&res.mems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for CpuSetController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::CpuSet
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a CpuSetController {
|
||||
fn from(sub: &'a Subsystem) -> &'a CpuSetController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::CpuSet(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_u64_from(mut file: File) -> Option<u64> {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
string.trim().parse().ok()
|
||||
}
|
||||
|
||||
impl CpuSetController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cpuset(self: &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)
|
||||
},
|
||||
cpus: {
|
||||
self.open_path("cpuset.cpus", false).and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap()
|
||||
},
|
||||
effective_cpus: {
|
||||
self.open_path("cpuset.effective_cpus", false).and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap()
|
||||
},
|
||||
effective_mems: {
|
||||
self.open_path("cpuset.effective_mems", false).and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap()
|
||||
},
|
||||
mem_exclusive: {
|
||||
self.open_path("cpuset.mem_exclusive", false).and_then(|file| {
|
||||
read_u64_from(file)
|
||||
}).map(|x| x == 1).unwrap_or(false)
|
||||
},
|
||||
mem_hardwall: {
|
||||
self.open_path("cpuset.mem_hardwall", false).and_then(|file| {
|
||||
read_u64_from(file)
|
||||
}).map(|x| x == 1).unwrap_or(false)
|
||||
},
|
||||
memory_migrate: {
|
||||
self.open_path("cpuset.memory_migrate", false).and_then(|file| {
|
||||
read_u64_from(file)
|
||||
}).map(|x| x == 1).unwrap_or(false)
|
||||
},
|
||||
memory_pressure: {
|
||||
self.open_path("cpuset.memory_pressure", false).and_then(|file| {
|
||||
read_u64_from(file)
|
||||
}).unwrap_or(0)
|
||||
},
|
||||
memory_pressure_enabled: {
|
||||
self.open_path("cpuset.memory_pressure_enabled", false).and_then(|file| {
|
||||
read_u64_from(file)
|
||||
}).map(|x| x == 1)
|
||||
},
|
||||
memory_spread_page: {
|
||||
self.open_path("cpuset.memory_spread_page", false).and_then(|file| {
|
||||
read_u64_from(file)
|
||||
}).map(|x| x == 1).unwrap_or(false)
|
||||
},
|
||||
memory_spread_slab: {
|
||||
self.open_path("cpuset.memory_spread_slab", false).and_then(|file| {
|
||||
read_u64_from(file)
|
||||
}).map(|x| x == 1).unwrap_or(false)
|
||||
},
|
||||
mems: {
|
||||
self.open_path("cpuset.mems", false).and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap()
|
||||
},
|
||||
sched_load_balance: {
|
||||
self.open_path("cpuset.sched_load_balance", false).and_then(|file| {
|
||||
read_u64_from(file)
|
||||
}).map(|x| x == 1).unwrap_or(false)
|
||||
},
|
||||
sched_relax_domain_level: {
|
||||
self.open_path("cpuset.sched_relax_domain_level", false).and_then(|file| {
|
||||
read_u64_from(file)
|
||||
}).unwrap_or(0)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_cpu_exclusive(self: &Self, b: bool) {
|
||||
self.open_path("cpuset.cpu_exclusive", true).and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").ok()
|
||||
} else {
|
||||
file.write_all(b"0").ok()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_mem_exclusive(self: &Self, b: bool) {
|
||||
self.open_path("cpuset.mem_exclusive", true).and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").ok()
|
||||
} else {
|
||||
file.write_all(b"0").ok()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_cpus(self: &Self, cpus: &String) {
|
||||
self.open_path("cpuset.cpus", true).and_then(|mut file| {
|
||||
file.write_all(cpus.as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_mems(self: &Self, mems: &String) {
|
||||
self.open_path("cpuset.mems", true).and_then(|mut file| {
|
||||
file.write_all(mems.as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_hardwall(self: &Self, b: bool) {
|
||||
self.open_path("cpuset.mem_hardwall", true).and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").ok()
|
||||
} else {
|
||||
file.write_all(b"0").ok()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_load_balancing(self: &Self, b: bool) {
|
||||
self.open_path("cpuset.sched_load_balance", true).and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").ok()
|
||||
} else {
|
||||
file.write_all(b"0").ok()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_rebalance_relax_domain_level(self: &Self, i: i64) {
|
||||
self.open_path("cpuset.sched_relax_domain_level", true).and_then(|mut file| {
|
||||
file.write_all(i.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_memory_migration(self: &Self, b: bool) {
|
||||
self.open_path("cpuset.memory_migrate", true).and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").ok()
|
||||
} else {
|
||||
file.write_all(b"0").ok()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_memory_spread_page(self: &Self, b: bool) {
|
||||
self.open_path("cpuset.memory_spread_page", true).and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").ok()
|
||||
} else {
|
||||
file.write_all(b"0").ok()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_memory_spread_slab(self: &Self, b: bool) {
|
||||
self.open_path("cpuset.memory_spread_slab", true).and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").ok()
|
||||
} else {
|
||||
file.write_all(b"0").ok()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_enable_memory_pressure(self: &Self, b: bool) {
|
||||
/* XXX: this file should only be present in the root cpuset cg */
|
||||
self.open_path("cpuset.memory_pressure_enabled", true).and_then(|mut file| {
|
||||
if b {
|
||||
file.write_all(b"1").ok()
|
||||
} else {
|
||||
file.write_all(b"0").ok()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
85
src/devices.rs
Normal file
85
src/devices.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
/* Devices controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use {DeviceResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DevicesController{
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl Controller for DevicesController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::Devices }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, res: &Resources) {
|
||||
/* get the resources that apply to this controller */
|
||||
let res: &DeviceResources = &res.devices;
|
||||
|
||||
if res.update_values {
|
||||
for i in &res.devices {
|
||||
let wstr = format!("{} {}:{} {}",
|
||||
i.devtype, i.major, i.minor, i.access);
|
||||
if i.allow {
|
||||
self.allow_device(&wstr);
|
||||
} else {
|
||||
self.deny_device(&wstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for DevicesController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::Devices
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a DevicesController {
|
||||
fn from(sub: &'a Subsystem) -> &'a DevicesController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::Devices(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DevicesController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
pub fn allow_device(self: &Self, dev: &String) {
|
||||
self.open_path("devices.allow", true).and_then(|mut file| {
|
||||
file.write_all(dev.as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn deny_device(self: &Self, dev: &String) {
|
||||
self.open_path("devices.deny", true).and_then(|mut file| {
|
||||
file.write_all(dev.as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn allowed_devices(self: &Self) -> String {
|
||||
self.open_path("devices.list", false).and_then(|mut file| {
|
||||
let mut s = String::new();
|
||||
let _ = file.read_to_string(&mut s);
|
||||
Some(s)
|
||||
}).unwrap_or("".to_string())
|
||||
}
|
||||
}
|
||||
82
src/freezer.rs
Normal file
82
src/freezer.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
/* Freezer controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use {Controllers, Controller, Resources, ControllIdentifier, Subsystem};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FreezerController{
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
pub enum FreezerState {
|
||||
Thawed,
|
||||
Freezing,
|
||||
Frozen,
|
||||
}
|
||||
|
||||
impl Controller for FreezerController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::Freezer }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, _res: &Resources) {
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for FreezerController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::Freezer
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a FreezerController {
|
||||
fn from(sub: &'a Subsystem) -> &'a FreezerController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::Freezer(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FreezerController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
pub fn freeze(self: &Self) {
|
||||
self.open_path("freezer.state", true).and_then(|mut file| {
|
||||
file.write_all("FROZEN".to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn thaw(self: &Self) {
|
||||
self.open_path("freezer.state", true).and_then(|mut file| {
|
||||
file.write_all("THAWED".to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn state(self: &Self) -> FreezerState {
|
||||
self.open_path("freezer.state", false).and_then(|mut file| {
|
||||
let mut s = String::new();
|
||||
let _ = file.read_to_string(&mut s);
|
||||
match s.as_ref() {
|
||||
"FROZEN" => Some(FreezerState::Frozen),
|
||||
"THAWED" => Some(FreezerState::Thawed),
|
||||
"FREEZING" => Some(FreezerState::Freezing),
|
||||
_ => None,
|
||||
}
|
||||
}).unwrap_or(FreezerState::Thawed)
|
||||
}
|
||||
}
|
||||
130
src/hierarchies.rs
Normal file
130
src/hierarchies.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
use std::io::BufRead;
|
||||
use std::io::BufReader;
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
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;
|
||||
|
||||
pub struct V1 {
|
||||
mount_point: String,
|
||||
}
|
||||
|
||||
impl Hierarchy for V1 {
|
||||
fn subsystems(self: &Self) -> Vec<Subsystem> {
|
||||
let mut subs = vec![];
|
||||
if self.check_support(Controllers::Pids) {
|
||||
subs.push(Subsystem::Pid(PidController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::Mem) {
|
||||
subs.push(Subsystem::Mem(MemController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::CpuSet) {
|
||||
subs.push(Subsystem::CpuSet(CpuSetController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::CpuAcct) {
|
||||
subs.push(Subsystem::CpuAcct(CpuAcctController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::Cpu) {
|
||||
subs.push(Subsystem::Cpu(CpuController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::Devices) {
|
||||
subs.push(Subsystem::Devices(DevicesController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::Freezer) {
|
||||
subs.push(Subsystem::Freezer(FreezerController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::NetCls) {
|
||||
subs.push(Subsystem::NetCls(NetClsController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::BlkIo) {
|
||||
subs.push(Subsystem::BlkIo(BlkIoController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::PerfEvent) {
|
||||
subs.push(Subsystem::PerfEvent(PerfEventController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::NetPrio) {
|
||||
subs.push(Subsystem::NetPrio(NetPrioController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::HugeTlb) {
|
||||
subs.push(Subsystem::HugeTlb(HugeTlbController::new(self.root())));
|
||||
}
|
||||
if self.check_support(Controllers::Rdma) {
|
||||
subs.push(Subsystem::Rdma(RdmaController::new(self.root())));
|
||||
}
|
||||
|
||||
subs
|
||||
}
|
||||
|
||||
fn check_support(self: &Self, sub: Controllers) -> bool {
|
||||
let root = self.root().read_dir().unwrap();
|
||||
for entry in root {
|
||||
if let Ok(entry) = entry {
|
||||
if entry.file_name().into_string().unwrap() == sub.to_string() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn root(self: &Self) -> PathBuf {
|
||||
PathBuf::from(self.mount_point.clone())
|
||||
}
|
||||
|
||||
fn can_create_cgroup(self: &Self) -> bool {
|
||||
/*
|
||||
* V1 hierarchies do not support creating cgroups,
|
||||
* they have to be created in a subsystem
|
||||
*/
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl V1 {
|
||||
pub fn new() -> Self {
|
||||
let mount_point = find_v1_mount().unwrap();
|
||||
V1 {
|
||||
mount_point: mount_point,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_v1_mount() -> Option<String> {
|
||||
/* Open mountinfo so we can get a parseable mount list */
|
||||
let mountinfo_path = Path::new("/proc/self/mountinfo");
|
||||
|
||||
/* If /proc isn't mounted, or something else happens, then bail out */
|
||||
if mountinfo_path.exists() == false {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mountinfo_file = File::open(mountinfo_path).unwrap();
|
||||
let mountinfo_reader = BufReader::new(&mountinfo_file);
|
||||
for _line in mountinfo_reader.lines() {
|
||||
let line = _line.unwrap();
|
||||
let mut fields = line.split_whitespace();
|
||||
let index = line.find(" - ").unwrap();
|
||||
let mut more_fields = line[index + 3..].split_whitespace().collect::<Vec<_>>();
|
||||
let fstype = more_fields[0];
|
||||
if fstype == "tmpfs" && more_fields[2].contains("ro") {
|
||||
let cgroups_mount = fields.nth(4).unwrap();
|
||||
println!("found cgroups at {:?}", cgroups_mount);
|
||||
return Some(cgroups_mount.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
97
src/hugetlb.rs
Normal file
97
src/hugetlb.rs
Normal file
@@ -0,0 +1,97 @@
|
||||
/* Hugetlb controller */
|
||||
use std::path::PathBuf;
|
||||
use std::fs::File;
|
||||
use std::io::{Write, Read};
|
||||
|
||||
use {HugePageResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HugeTlbController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl Controller for HugeTlbController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::HugeTlb }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, res: &Resources) {
|
||||
/* get the resources that apply to this controller */
|
||||
let res: &HugePageResources = &res.hugepages;
|
||||
|
||||
if res.update_values {
|
||||
for i in &res.limits {
|
||||
self.set_limit_in_bytes(&i.size, i.limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for HugeTlbController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::HugeTlb
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a HugeTlbController {
|
||||
fn from(sub: &'a Subsystem) -> &'a HugeTlbController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::HugeTlb(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_u64_from(mut file: File) -> Option<u64> {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
string.trim().parse().ok()
|
||||
}
|
||||
|
||||
impl HugeTlbController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
pub fn size_supported(self: &Self, _hugetlb_size: String) -> bool {
|
||||
/* TODO */
|
||||
true
|
||||
}
|
||||
|
||||
pub fn failcnt(self: &Self, hugetlb_size: &String) -> Option<u64> {
|
||||
self.open_path(&format!("hugetlb.{}.failcnt", hugetlb_size), false)
|
||||
.and_then(read_u64_from)
|
||||
}
|
||||
|
||||
pub fn limit_in_bytes(self: &Self, hugetlb_size: &String) -> Option<u64> {
|
||||
self.open_path(&format!("hugetlb.{}.limit_in_bytes", hugetlb_size), false)
|
||||
.and_then(read_u64_from)
|
||||
}
|
||||
|
||||
pub fn usage_in_bytes(self: &Self, hugetlb_size: &String) -> Option<u64> {
|
||||
self.open_path(&format!("hugetlb.{}.usage_in_bytes", hugetlb_size), false)
|
||||
.and_then(read_u64_from)
|
||||
}
|
||||
pub fn max_usage_in_bytes(self: &Self, hugetlb_size: &String) -> Option<u64> {
|
||||
self.open_path(&format!("hugetlb.{}.max_usage_in_bytes", hugetlb_size), false)
|
||||
.and_then(read_u64_from)
|
||||
}
|
||||
|
||||
pub fn set_limit_in_bytes(self: &Self, hugetlb_size: &String, limit: u64) {
|
||||
self.open_path(&format!("hugetlb.{}.limit_in_bytes", hugetlb_size), false)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
}
|
||||
435
src/lib.rs
Normal file
435
src/lib.rs
Normal file
@@ -0,0 +1,435 @@
|
||||
use std::path::PathBuf;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
|
||||
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 hugetlb;
|
||||
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 hugetlb::HugeTlbController;
|
||||
use rdma::RdmaController;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Subsystem {
|
||||
Pid(PidController),
|
||||
Mem(MemController),
|
||||
CpuSet(CpuSetController),
|
||||
CpuAcct(CpuAcctController),
|
||||
Cpu(CpuController),
|
||||
Devices(DevicesController),
|
||||
Freezer(FreezerController),
|
||||
NetCls(NetClsController),
|
||||
BlkIo(BlkIoController),
|
||||
PerfEvent(PerfEventController),
|
||||
NetPrio(NetPrioController),
|
||||
HugeTlb(HugeTlbController),
|
||||
Rdma(RdmaController),
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub enum Controllers {
|
||||
Pids,
|
||||
Mem,
|
||||
CpuSet,
|
||||
CpuAcct,
|
||||
Cpu,
|
||||
Devices,
|
||||
Freezer,
|
||||
NetCls,
|
||||
BlkIo,
|
||||
PerfEvent,
|
||||
NetPrio,
|
||||
HugeTlb,
|
||||
Rdma,
|
||||
}
|
||||
|
||||
impl Controllers {
|
||||
pub fn to_string(self: &Self) -> String {
|
||||
match self {
|
||||
Controllers::Pids => return "pids".to_string(),
|
||||
Controllers::Mem => return "memory".to_string(),
|
||||
Controllers::CpuSet => return "cpuset".to_string(),
|
||||
Controllers::CpuAcct => return "cpuacct".to_string(),
|
||||
Controllers::Cpu => return "cpu".to_string(),
|
||||
Controllers::Devices => return "devices".to_string(),
|
||||
Controllers::Freezer => return "freezer".to_string(),
|
||||
Controllers::NetCls => return "net_cls".to_string(),
|
||||
Controllers::BlkIo => return "blkio".to_string(),
|
||||
Controllers::PerfEvent => return "perf_event".to_string(),
|
||||
Controllers::NetPrio => return "net_prio".to_string(),
|
||||
Controllers::HugeTlb => return "hugetlb".to_string(),
|
||||
Controllers::Rdma => return "rdma".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Controller {
|
||||
/* actual API */
|
||||
fn apply(self: &Self, res: &Resources);
|
||||
|
||||
/* meta stuff */
|
||||
fn control_type(self: &Self) -> Controllers;
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf;
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf;
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf;
|
||||
|
||||
fn verify_path(self: &Self) -> bool {
|
||||
self.get_path().starts_with(self.get_base())
|
||||
}
|
||||
|
||||
fn create(self: &Self) {
|
||||
if self.verify_path() {
|
||||
match ::std::fs::create_dir(self.get_path()) {
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("error create_dir {:?}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn exists(self: &Self) -> bool {
|
||||
self.get_path().exists()
|
||||
}
|
||||
|
||||
fn delete(self: &Self) {
|
||||
if self.get_path().exists() {
|
||||
let _ = ::std::fs::remove_dir(self.get_path());
|
||||
}
|
||||
}
|
||||
|
||||
fn open_path(self: &Self, p: &str, w: bool) -> Option<File> {
|
||||
let mut path = self.get_path().clone();
|
||||
path.push(p);
|
||||
|
||||
if !self.verify_path() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if w {
|
||||
match File::create(&path) {
|
||||
Err(_) => return None,
|
||||
Ok(file) => return Some(file),
|
||||
}
|
||||
} else {
|
||||
match File::open(&path) {
|
||||
Err(_) => return None,
|
||||
Ok(file) => return Some(file),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_task(self: &Self, pid: &CgroupPid) {
|
||||
self.open_path("tasks", true).and_then(|mut file| {
|
||||
file.write_all(pid.pid.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ControllIdentifier {
|
||||
fn controller_type() -> Controllers;
|
||||
}
|
||||
|
||||
pub trait Hierarchy {
|
||||
fn subsystems(self: &Self) -> Vec<Subsystem>;
|
||||
fn can_create_cgroup(self: &Self) -> bool;
|
||||
fn root(self: &Self) -> PathBuf;
|
||||
fn check_support(self: &Self, sub: Controllers) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct MemoryResources {
|
||||
pub update_values: bool,
|
||||
pub kernel_memory_limit: u64,
|
||||
pub memory_hard_limit: u64,
|
||||
pub memory_soft_limit: u64,
|
||||
pub kernel_tcp_memory_limit: u64,
|
||||
pub memory_swap_limit: u64,
|
||||
pub swappiness: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct PidResources {
|
||||
pub update_values: bool,
|
||||
pub maximum_number_of_processes: pid::PidMax,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct CpuResources {
|
||||
pub update_values: bool,
|
||||
/* cpuset */
|
||||
pub cpus: String,
|
||||
pub mems: String,
|
||||
/* cpu */
|
||||
pub shares: u64,
|
||||
pub quota: i64,
|
||||
pub period: u64,
|
||||
pub realtime_runtime: i64,
|
||||
pub realtime_period: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct DeviceResource {
|
||||
pub allow: bool,
|
||||
pub devtype: String,
|
||||
pub major: u64,
|
||||
pub minor: u64,
|
||||
pub access: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct DeviceResources {
|
||||
pub update_values: bool,
|
||||
pub devices: Vec<DeviceResource>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct NetworkPriority {
|
||||
pub name: String,
|
||||
pub priority: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct NetworkResources {
|
||||
pub update_values: bool,
|
||||
pub class_id: u64,
|
||||
pub priorities: Vec<NetworkPriority>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct HugePageResource {
|
||||
pub size: String,
|
||||
pub limit: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct HugePageResources {
|
||||
pub update_values: bool,
|
||||
pub limits: Vec<HugePageResource>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct BlkIoDeviceResource {
|
||||
pub major: u64,
|
||||
pub minor: u64,
|
||||
pub weight: u16,
|
||||
pub leaf_weight: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct BlkIoDeviceThrottleResource {
|
||||
pub major: u64,
|
||||
pub minor: u64,
|
||||
pub rate: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct BlkIoResources {
|
||||
pub update_values: bool,
|
||||
pub weight: u16,
|
||||
pub leaf_weight: u16,
|
||||
pub weight_device: Vec<BlkIoDeviceResource>,
|
||||
pub throttle_read_bps_device: Vec<BlkIoDeviceThrottleResource>,
|
||||
pub throttle_read_iops_device: Vec<BlkIoDeviceThrottleResource>,
|
||||
pub throttle_write_bps_device: Vec<BlkIoDeviceThrottleResource>,
|
||||
pub throttle_write_iops_device: Vec<BlkIoDeviceThrottleResource>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Default)]
|
||||
pub struct Resources {
|
||||
pub memory: MemoryResources,
|
||||
pub pid: PidResources,
|
||||
pub cpu: CpuResources,
|
||||
pub devices: DeviceResources,
|
||||
pub network: NetworkResources,
|
||||
pub hugepages: HugePageResources,
|
||||
pub blkio: BlkIoResources,
|
||||
}
|
||||
|
||||
pub struct CgroupPid {
|
||||
pub pid: u64,
|
||||
}
|
||||
|
||||
impl From<u64> for CgroupPid {
|
||||
fn from(u: u64) -> CgroupPid {
|
||||
CgroupPid {
|
||||
pid: u,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Subsystem {
|
||||
fn enter(self: Self, path: &String) -> Self {
|
||||
match self {
|
||||
Subsystem::Pid(cont) => Subsystem::Pid({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::Mem(cont) => Subsystem::Mem({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::CpuSet(cont) => Subsystem::CpuSet({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::CpuAcct(cont) => Subsystem::CpuAcct({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::Cpu(cont) => Subsystem::Cpu({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::Devices(cont) => Subsystem::Devices({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::Freezer(cont) => Subsystem::Freezer({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::NetCls(cont) => Subsystem::NetCls({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::BlkIo(cont) => Subsystem::BlkIo({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::PerfEvent(cont) => Subsystem::PerfEvent({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::NetPrio(cont) => Subsystem::NetPrio({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::HugeTlb(cont) => Subsystem::HugeTlb({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
Subsystem::Rdma(cont) => Subsystem::Rdma({
|
||||
let mut c = cont.clone();
|
||||
c.get_path_mut().push(path);
|
||||
c
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_controller(self: &Self) -> &dyn Controller {
|
||||
match self {
|
||||
Subsystem::Pid(cont) => cont,
|
||||
Subsystem::Mem(cont) => cont,
|
||||
Subsystem::CpuSet(cont) => cont,
|
||||
Subsystem::CpuAcct(cont) => cont,
|
||||
Subsystem::Cpu(cont) => cont,
|
||||
Subsystem::Devices(cont) => cont,
|
||||
Subsystem::Freezer(cont) => cont,
|
||||
Subsystem::NetCls(cont) => cont,
|
||||
Subsystem::BlkIo(cont) => cont,
|
||||
Subsystem::PerfEvent(cont) => cont,
|
||||
Subsystem::NetPrio(cont) => cont,
|
||||
Subsystem::HugeTlb(cont) => cont,
|
||||
Subsystem::Rdma(cont) => cont,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use {Resources, PidResources, Hierarchy, Controller, Controllers, Subsystem};
|
||||
use pid::{PidMax, PidController};
|
||||
use cgroup::Cgroup;
|
||||
|
||||
#[test]
|
||||
fn create_and_delete_cgroup() {
|
||||
let hier = ::hierarchies::V1::new();
|
||||
let cg = Cgroup::new(&hier, String::from("ltest2"), 0);
|
||||
{
|
||||
let pidcontroller: &PidController = cg.controller_of().unwrap();
|
||||
pidcontroller.set_pid_max(PidMax::Value(1337));
|
||||
assert_eq!(pidcontroller.get_pid_max(), Some(PidMax::Value(1337)));
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pid_pids_current_is_zero() {
|
||||
let hier = ::hierarchies::V1::new();
|
||||
let cg = Cgroup::new(&hier, String::from("ltest3"), 0);
|
||||
{
|
||||
let pidcontroller: &PidController = cg.controller_of().unwrap();
|
||||
assert_eq!(pidcontroller.get_pid_current(), 0);
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pid_pids_events_is_zero() {
|
||||
let hier = ::hierarchies::V1::new();
|
||||
let cg = Cgroup::new(&hier, String::from("ltest4"), 0);
|
||||
{
|
||||
let pidcontroller: &PidController = cg.controller_of().unwrap();
|
||||
assert_eq!(pidcontroller.get_pid_events(), 0);
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_setting_resources() {
|
||||
let hier = ::hierarchies::V1::new();
|
||||
let cg = Cgroup::new(&hier, String::from("ltest5"), 0);
|
||||
{
|
||||
let res = Resources {
|
||||
pid: PidResources {
|
||||
update_values: true,
|
||||
maximum_number_of_processes: PidMax::Value(512),
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
cg.apply(&res);
|
||||
|
||||
/* verify */
|
||||
let pidcontroller: &PidController = cg.controller_of().unwrap();
|
||||
assert_eq!(pidcontroller.get_pid_max(), Some(PidMax::Value(512)));
|
||||
}
|
||||
cg.delete();
|
||||
}
|
||||
|
||||
}
|
||||
253
src/memory.rs
Normal file
253
src/memory.rs
Normal file
@@ -0,0 +1,253 @@
|
||||
/* Memory controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Write, Read};
|
||||
use std::fs::File;
|
||||
|
||||
use {Resources, MemoryResources, Controller, Controllers, Subsystem, ControllIdentifier};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MemController{
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MemSwap {
|
||||
pub fail_cnt: u64,
|
||||
pub limit_in_bytes: u64,
|
||||
pub usage_in_bytes: u64,
|
||||
pub max_usage_in_bytes: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Memory {
|
||||
pub fail_cnt: u64,
|
||||
pub limit_in_bytes: u64,
|
||||
pub usage_in_bytes: u64,
|
||||
pub max_usage_in_bytes: u64,
|
||||
pub move_charge_at_immigrate: u64,
|
||||
/* TODO: parse this */
|
||||
pub numa_stat: String,
|
||||
/* TODO: parse this */
|
||||
pub oom_control: String,
|
||||
pub soft_limit_in_bytes: u64,
|
||||
/* TODO: parse this */
|
||||
pub stat: String,
|
||||
pub swappiness: u64,
|
||||
pub use_hierarchy: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Tcp {
|
||||
pub fail_cnt: u64,
|
||||
pub limit_in_bytes: u64,
|
||||
pub usage_in_bytes: u64,
|
||||
pub max_usage_in_bytes: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Kmem {
|
||||
pub fail_cnt: u64,
|
||||
pub limit_in_bytes: u64,
|
||||
pub usage_in_bytes: u64,
|
||||
pub max_usage_in_bytes: u64,
|
||||
pub slabinfo: String,
|
||||
}
|
||||
|
||||
impl Controller for MemController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::Mem }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, res: &Resources) {
|
||||
/* get the resources that apply to this controller */
|
||||
let memres: &MemoryResources = &res.memory;
|
||||
|
||||
if memres.update_values {
|
||||
self.set_limit(memres.memory_hard_limit);
|
||||
self.set_soft_limit(memres.memory_soft_limit);
|
||||
self.set_kmem_limit(memres.kernel_memory_limit);
|
||||
self.set_memswap_limit(memres.memory_swap_limit);
|
||||
self.set_tcp_limit(memres.kernel_tcp_memory_limit);
|
||||
self.set_swappiness(memres.swappiness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MemController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn memory_stat(self: &Self) -> Memory {
|
||||
Memory {
|
||||
fail_cnt: self.open_path("memory.failcnt", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
limit_in_bytes: self.open_path("memory.limit_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
usage_in_bytes: self.open_path("memory.usage_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
max_usage_in_bytes: self.open_path("memory.max_usage_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
move_charge_at_immigrate: self.open_path("memory.move_charge_at_immigrate", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
numa_stat: self.open_path("memory.numa_stat", false)
|
||||
.and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap_or("".to_string()),
|
||||
oom_control: self.open_path("memory.oom_control", false)
|
||||
.and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap_or("".to_string()),
|
||||
soft_limit_in_bytes: self.open_path("memory.soft_limit_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
stat: self.open_path("memory.stat", false)
|
||||
.and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap_or("".to_string()),
|
||||
swappiness: self.open_path("memory.swappiness", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
use_hierarchy: self.open_path("memory.use_hierarchy", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kmem_stat(self: &Self) -> Kmem {
|
||||
Kmem {
|
||||
fail_cnt: self.open_path("memory.kmem.failcnt", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
limit_in_bytes: self.open_path("memory.kmem.limit_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
usage_in_bytes: self.open_path("memory.kmem.usage_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
max_usage_in_bytes: self.open_path("memory.kmem.max_usage_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
slabinfo: self.open_path("memory.kmem.slabinfo", false)
|
||||
.and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}).unwrap_or("".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kmem_tcp_stat(self: &Self) -> Tcp {
|
||||
Tcp {
|
||||
fail_cnt: self.open_path("memory.kmem.tcp.failcnt", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
limit_in_bytes: self.open_path("memory.kmem.tcp.limit_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
usage_in_bytes: self.open_path("memory.kmem.tcp.usage_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
max_usage_in_bytes: self.open_path("memory.kmem.tcp.max_usage_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn memswap(self: &Self) -> MemSwap {
|
||||
MemSwap {
|
||||
fail_cnt: self.open_path("memory.memsw.failcnt", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
limit_in_bytes: self.open_path("memory.memsw.limit_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
usage_in_bytes: self.open_path("memory.memsw.usage_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
max_usage_in_bytes: self.open_path("memory.memsw.max_usage_in_bytes", false)
|
||||
.and_then(|file| read_u64_from(file))
|
||||
.unwrap_or(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_limit(self: &Self, limit: u64) {
|
||||
self.open_path("memory.limit_in_bytes", true).and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_kmem_limit(self: &Self, limit: u64) {
|
||||
self.open_path("memory.kmem.limit_in_bytes", true).and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_memswap_limit(self: &Self, limit: u64) {
|
||||
self.open_path("memory.memsw.limit_in_bytes", true).and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_tcp_limit(self: &Self, limit: u64) {
|
||||
self.open_path("memory.kmem.tcp.limit_in_bytes", true).and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_soft_limit(self: &Self, limit: u64) {
|
||||
self.open_path("memory.soft_limit_in_bytes", true).and_then(|mut file| {
|
||||
file.write_all(limit.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn set_swappiness(self: &Self, swp: u64) {
|
||||
self.open_path("memory.swappiness", true).and_then(|mut file| {
|
||||
file.write_all(swp.to_string().as_ref()).ok()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for MemController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::Mem
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a MemController {
|
||||
fn from(sub: &'a Subsystem) -> &'a MemController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::Mem(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_u64_from(mut file: File) -> Option<u64> {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
string.trim().parse().ok()
|
||||
}
|
||||
78
src/net_cls.rs
Normal file
78
src/net_cls.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
/* Network classifier controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Read, Write};
|
||||
use std::fs::File;
|
||||
|
||||
use {NetworkResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NetClsController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
|
||||
impl Controller for NetClsController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::NetCls }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, res: &Resources) {
|
||||
/* get the resources that apply to this controller */
|
||||
let res: &NetworkResources = &res.network;
|
||||
|
||||
if res.update_values {
|
||||
self.set_class(res.class_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for NetClsController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::NetCls
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a NetClsController {
|
||||
fn from(sub: &'a Subsystem) -> &'a NetClsController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::NetCls(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_u64_from(mut file: File) -> Option<u64> {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
string.trim().parse().ok()
|
||||
}
|
||||
|
||||
impl NetClsController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
pub fn set_class(self: &Self, class: u64) {
|
||||
self.open_path("net_cls.classid", true).and_then(|mut file| {
|
||||
let s = format!("{:#08X}", class);
|
||||
file.write_all(s.as_ref()).ok()
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_class(self: &Self) -> u64 {
|
||||
self.open_path("net_cls.classid", false).and_then(|file| {
|
||||
read_u64_from(file)
|
||||
}).unwrap_or(0u64)
|
||||
}
|
||||
}
|
||||
93
src/net_prio.rs
Normal file
93
src/net_prio.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
/* Network priority controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{BufReader, BufRead, Write, Read};
|
||||
use std::fs::File;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use {NetworkResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct NetPrioController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl Controller for NetPrioController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::NetPrio }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, res: &Resources) {
|
||||
/* get the resources that apply to this controller */
|
||||
let res: &NetworkResources = &res.network;
|
||||
|
||||
if res.update_values {
|
||||
for i in &res.priorities {
|
||||
self.set_if_prio(&i.name, i.priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for NetPrioController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::NetPrio
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a NetPrioController {
|
||||
fn from(sub: &'a Subsystem) -> &'a NetPrioController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::NetPrio(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_u64_from(mut file: File) -> Option<u64> {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
string.trim().parse().ok()
|
||||
}
|
||||
|
||||
impl NetPrioController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
pub fn prio_idx(self: &Self) -> u64 {
|
||||
self.open_path("net_prio.prioidx", false)
|
||||
.and_then(read_u64_from)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn ifpriomap(self: &Self) -> HashMap<String, u64> {
|
||||
self.open_path("net_prio.ifpriomap", false)
|
||||
.and_then(|file| {
|
||||
let bf = BufReader::new(file);
|
||||
Some(bf.lines().map(|line| {
|
||||
let l = line.unwrap();
|
||||
let mut sp = l.split_whitespace();
|
||||
(sp.nth(0).unwrap().to_string(),
|
||||
sp.nth(1).unwrap().trim().parse().unwrap())
|
||||
}).collect())
|
||||
}).unwrap_or(HashMap::new())
|
||||
}
|
||||
|
||||
pub fn set_if_prio(self: &Self, eif: &String, prio: u64) {
|
||||
self.open_path("net_prio.ifpriomap", true)
|
||||
.and_then(|mut file| {
|
||||
Some(file.write_all(format!("{} {}", eif, prio).as_ref()))
|
||||
});
|
||||
}
|
||||
}
|
||||
51
src/perf_event.rs
Normal file
51
src/perf_event.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
/* Perf event controller */
|
||||
use std::path::PathBuf;
|
||||
|
||||
use {Controllers, Controller, Resources, ControllIdentifier, Subsystem};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PerfEventController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl Controller for PerfEventController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::PerfEvent }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, _res: &Resources) {
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for PerfEventController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::PerfEvent
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a PerfEventController {
|
||||
fn from(sub: &'a Subsystem) -> &'a PerfEventController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::PerfEvent(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PerfEventController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
}
|
||||
122
src/pid.rs
Normal file
122
src/pid.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
/* PID controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Write, Read};
|
||||
|
||||
use {Resources, PidResources, Controller, ControllIdentifier, Subsystem, Controllers};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PidController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
|
||||
pub enum PidMax {
|
||||
Max,
|
||||
Value(i64),
|
||||
}
|
||||
|
||||
impl Default for PidMax {
|
||||
fn default() -> Self {
|
||||
PidMax::Max
|
||||
}
|
||||
}
|
||||
|
||||
impl Controller for PidController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::Pids }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, res: &Resources) {
|
||||
/* get the resources that apply to this controller */
|
||||
let pidres: &PidResources = &res.pid;
|
||||
|
||||
if pidres.update_values {
|
||||
/* apply pid_max */
|
||||
self.set_pid_max(pidres.maximum_number_of_processes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*impl<'a> ControllIdentifier for &'a PidController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::Pids
|
||||
}
|
||||
}*/
|
||||
|
||||
impl ControllIdentifier for PidController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::Pids
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a PidController {
|
||||
fn from(sub: &'a Subsystem) -> &'a PidController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::Pid(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PidController {
|
||||
pub fn supported_at(_path: PathBuf) -> bool {
|
||||
true
|
||||
}
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pid_events(self: &Self) -> i64 {
|
||||
self.open_path("pids.events", false).and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.split_whitespace().nth(1).unwrap().parse().unwrap_or(0))
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_pid_current(self: &Self) -> i64 {
|
||||
self.open_path("pids.current", false).and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().parse().unwrap_or(0))
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
pub fn get_pid_max(self: &Self) -> Option<PidMax> {
|
||||
self.open_path("pids.max", false).and_then(|mut file| {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
if string.trim() == "max" {
|
||||
Some(PidMax::Max)
|
||||
} else {
|
||||
Some(PidMax::Value(string.trim().parse().unwrap_or(0)))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_pid_max(self: &Self, max_pid: PidMax) {
|
||||
self.open_path("pids.max", true).and_then(|mut file| {
|
||||
let string_to_write = match max_pid {
|
||||
PidMax::Max => "max".to_string(),
|
||||
PidMax::Value(num) => num.to_string(),
|
||||
};
|
||||
match file.write_all(string_to_write.as_ref()) {
|
||||
Ok(_) => (),
|
||||
Err(e) => println!("error {:?}", e),
|
||||
}
|
||||
Some(0i64)
|
||||
});
|
||||
}
|
||||
}
|
||||
71
src/rdma.rs
Normal file
71
src/rdma.rs
Normal file
@@ -0,0 +1,71 @@
|
||||
/* RDMA controller */
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Write, Read};
|
||||
use std::fs::File;
|
||||
|
||||
use {Controllers, Controller, Resources, ControllIdentifier, Subsystem};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RdmaController {
|
||||
base: PathBuf,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl Controller for RdmaController {
|
||||
fn control_type(self: &Self) -> Controllers { Controllers::Rdma }
|
||||
fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path }
|
||||
fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf { &mut self.path }
|
||||
fn get_base<'a>(self: &'a Self) -> &'a PathBuf { &self.base }
|
||||
|
||||
fn apply(self: &Self, _res: &Resources) {
|
||||
}
|
||||
}
|
||||
|
||||
impl ControllIdentifier for RdmaController {
|
||||
fn controller_type() -> Controllers {
|
||||
Controllers::Rdma
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Subsystem> for &'a RdmaController {
|
||||
fn from(sub: &'a Subsystem) -> &'a RdmaController {
|
||||
unsafe {
|
||||
match sub {
|
||||
Subsystem::Rdma(c) => c,
|
||||
_ => {
|
||||
assert_eq!(1, 0);
|
||||
::std::mem::uninitialized()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_string_from(mut file: File) -> Option<String> {
|
||||
let mut string = String::new();
|
||||
let _ = file.read_to_string(&mut string);
|
||||
Some(string.trim().to_string())
|
||||
}
|
||||
|
||||
impl RdmaController {
|
||||
pub fn new(oroot: PathBuf) -> Self {
|
||||
let mut root = oroot;
|
||||
root.push(Self::controller_type().to_string());
|
||||
Self {
|
||||
base: root.clone(),
|
||||
path: root,
|
||||
}
|
||||
}
|
||||
pub fn current(self: &Self) -> String {
|
||||
self.open_path("rdma.current", false)
|
||||
.and_then(read_string_from)
|
||||
.unwrap_or("".to_string())
|
||||
}
|
||||
|
||||
pub fn set_max(self: &Self, max: &String) {
|
||||
self.open_path("rdma.max", true)
|
||||
.and_then(|mut file| {
|
||||
file.write_all(max.as_ref()).ok()
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user