Compare commits

...

36 Commits

Author SHA1 Message Date
Fupan Li
8f6a7e0a31 Merge pull request #19 from Tim-Zhang/0.2.0
Ready to release 0.2.0
2020-12-21 11:21:07 +08:00
Tim Zhang
9baa065226 release: v0.2.0
Bump vertion to 0.2.0

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
e160df0751 Make read_i64_from private and merge read_str_from to its caller
Also remove duplicated read_i64_from.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
e1e05d3a1c Make new_with_relative_paths=new and load_with_relative_paths=new in v2
Because the relative_paths is only valid for cgroup v1, the v2 use
unified hierarchy.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Qingyuan Hou
a89f4a062e Support set notify_on_release & release_agent
Support set notify_on_release & release_agent

Signed-off-by: Qingyuan Hou <qingyuan.hou@linux.alibaba.com>
2020-12-17 17:56:46 +08:00
Tim Zhang
61a0957a65 Fix set_swappiness in cgroup v2
The file should be memory.swap.max in cgroup v2.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
059204589c Ignore kmem in cgroup v2
Because there is no kmem in cgroup v2.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
c254fffbe0 Update readme
Update readme

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
438d774866 Fix test
Fix test

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
42ee1bafbd Make Cgroup can be stored in struct
- Change type of hier to remove lifetimes
- impl Clone, Default, Debug for Cgroup

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
b6bb5ae947 docs: Hide Re-exports
Make `pub use crate::cgroup::Cgroup` display as struct in docs.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
d2882b1d85 Print cause when println!("{}")
> Print like following:
unable to write to a control group file caused by: Os { code: 22, kind: InvalidInput, message: "Invalid argument" }) }

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
abcb5ed031 Add more logs for create_dir error in controller.create
We need know the path name which failed to create.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
1f188be405 Detect subsystems and get root from /proc/self/mountinfo
Delete check_support and stop detecting subsystems by finding in the
root folders because the detecting method is not accurate.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
fbd7164c29 Fix warnings in tests
Remove following warnings
- unused import
- unused Result

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
f34225411e Remove Box wrap of Cgroup.hire
It's unnecessary.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
cd998f3f9b Do not place cgroup under relative path read from cgroup by default
Add new_with_corresponding_relative_paths to do the original action.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
1ac76b69ba Make function find_v1_mount pub
The function find_v1_mount is useful for customized impl for Hierarchy.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
121f78d8e8 Expose deletion error
So that users can retry or do some aftercare.

Fixes: #18

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
0f76570677 Avoid exception caused by cgroup writeback feature
The cgroup writeback feature requires cooperation
between memcgs and blkcgs.
To avoid exceptions, we should add_task for blkcg before
memcg(push BlkIo before Mem).

For more Information:
https://www.alibabacloud.com/help/doc-detail/155509.ht

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
10650e2b16 Update tests to adapt new type of fields in resource
The type has been changed to Option type.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:46 +08:00
Tim Zhang
567cdb43b3 Use Option as resource fields, remove the update switch: update_values
Use idiomatic Option::None to represent optional fields.
This enables updates where not all fields need to be specified.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 17:56:41 +08:00
Tim Zhang
0c18b0855e Support customized attributes for CpuController and MemController
Customized attributes are useful for customized kernels.

Usage:
	let resource = &mut cgroups::Resources::default();
	resource.cpu.attrs.insert("cpu.cfs_init_buffer_us", "10".to_string());
	// apply here

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 16:45:41 +08:00
Yang, Wei
ca610bb57e add add_task_by_tgid
Add task by writing thread group id to cgroup.procs.

Signed-off-by: Yang, Wei <wei.yang1@linux.alibaba.com>
Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-12-17 15:57:22 +08:00
Fupan Li
af6fc63bed Merge pull request #17 from Tim-Zhang/minor-updates
Minor updates
2020-10-30 10:15:05 +08:00
Tim Zhang
6f9e89572e MemController: add method reset_max_usage
We need a method to reset the max memory usage recorded.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-10-29 19:35:39 +08:00
Tim Zhang
42eb32765b Make methods to_controller and controller_name of Subsystem public
We need these functions to detect whether subsystem path exists.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-10-29 19:32:55 +08:00
Tim Zhang
efb98108fc Fix warnings
Got:
cargo build --target x86_64-unknown-linux-musl
   Compiling cgroups v0.1.1-alpha.0 (/home/tim/project/cgroups-rs)
warning: unused import: `nix::sys::statfs`
   --> src/hierarchies.rs:220:5
    |
220 | use nix::sys::statfs;
    |     ^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(unused_imports)]` on by default

warning: 1 warning emitted

Signed-off-by: Tim Zhang <tim@hyper.sh>
2020-10-29 19:31:55 +08:00
James O. D. Hunt
c310b30c52 Merge pull request #14 from liubin/enhancement/13-fix-warnings
fix build warnings
2020-10-01 17:28:16 +01:00
bin liu
152af17f8f fix build warnings
And in Travis CI, treat warnings as error
to keep from merging codes with warning.

Fixes: #13

Signed-off-by: bin liu <bin@hyper.sh>
2020-09-23 16:19:51 +08:00
Bin Liu
d18b3bac2f Merge pull request #16 from liubin/enhancement/15-add-workflow-checks
add basic GitHub workflow for basic checks
2020-09-23 16:17:33 +08:00
bin liu
414fa281cc add basic github workflow for basic checks
Basic checks includes:

- Must have commit title/body
- Must have DCO(SoC)
- Title/Body line length are limited 75/72
- Add wip/do-not-merge to label PRs that could be merged

Fixes: #15

Signed-off-by: bin liu <bin@hyper.sh>
2020-09-23 16:15:08 +08:00
Peng Tao
f0eac7859a Merge pull request #12 from liubin/fix/11-add-trivas
update Travis configs
2020-09-23 14:01:37 +08:00
bin liu
db40fe8cd3 update Travis configs
Fixes: #11

Signed-off-by: bin liu <bin@hyper.sh>
2020-09-22 20:39:18 +08:00
Fupan Li
8717524f2c Merge pull request #10 from Kvasscn/fix-type-i8-compile-error-in-aarch64
lib: fix compiling error for type i8 in aarch64 environment
2020-09-22 10:36:14 +08:00
zhanghj
cd7e737149 lib: fix compiling error for type i8 in aarch64 environment
c_char is equal to i8 on x86, but it is equal to u8 on arm arch,
so we need to use type c_char instead of i8 to avoid compiling error.

Fixes: #9

Signed-off-by: zhanghj <zhanghj.lc@inspur.com>
2020-09-21 05:40:57 -04:00
34 changed files with 724 additions and 634 deletions

21
.github/workflows/PR-wip-checks.yaml vendored Normal file
View File

@@ -0,0 +1,21 @@
name: Pull request WIP checks
on:
pull_request:
types:
- opened
- synchronize
- reopened
- edited
- labeled
- unlabeled
jobs:
pr_wip_check:
runs-on: ubuntu-latest
name: WIP Check
steps:
- name: WIP Check
uses: tim-actions/wip-check@1c2a1ca6c110026b3e2297bb2ef39e1747b5a755
with:
labels: '["do-not-merge", "wip", "rfc"]'
keywords: '["WIP", "wip", "RFC", "rfc", "dnm", "DNM", "do-not-merge"]'

View File

@@ -0,0 +1,53 @@
name: Commit Message Check
on:
pull_request:
types:
- opened
- reopened
- synchronize
env:
error_msg: |+
See the document below for help on formatting commits for the project.
https://github.com/kata-containers/community/blob/master/CONTRIBUTING.md#patch-forma
jobs:
commit-message-check:
runs-on: ubuntu-latest
name: Commit Message Check
steps:
- name: Get PR Commits
id: 'get-pr-commits'
uses: tim-actions/get-pr-commits@v1.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: DCO Check
uses: tim-actions/dco@2fd0504dc0d27b33f542867c300c60840c6dcb20
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}
- name: Commit Body Missing Check
if: ${{ success() || failure() }}
uses: tim-actions/commit-body-check@v1.0.2
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}
- name: Check Subject Line Length
if: ${{ success() || failure() }}
uses: tim-actions/commit-message-checker-with-regex@v0.3.1
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}
pattern: '^.{0,75}(\n.*)*$'
error: 'Subject too long (max 75)'
post_error: ${{ env.error_msg }}
- name: Check Body Line Length
if: ${{ success() || failure() }}
uses: tim-actions/commit-message-checker-with-regex@v0.3.1
with:
commits: ${{ steps.get-pr-commits.outputs.commits }}
pattern: '^.+(\n.{0,72})*$|^.+\n\s*[^a-zA-Z\s\n]|^.+\n\S+$'
error: 'Body line too long (max 72)'
post_error: ${{ env.error_msg }}

View File

@@ -1,11 +1,31 @@
# Copyright (c) 2018 Levente Kurusa
# Copyright (c) 2020 Ant Group
#
# SPDX-License-Identifier: Apache-2.0
#
dist: bionic
os: linux
language: rust language: rust
cache: cargo
arch:
- amd64
- arm64
install:
- rustup component add rustfmt
script:
- RUSTFLAGS="--deny warnings" cargo build
- if [ "$TRAVIS_CPU_ARCH" == "amd64" ]; then cargo test -- --color always --nocapture ; fi
- cargo fmt -- --check
rust: rust:
- stable - 1.44.1
- beta
- nightly - nightly
matrix:
jobs:
allow_failures: allow_failures:
- rust: nightly - rust: nightly
fast_finish: true fast_finish: true
script:
- cargo build --verbose --all

View File

@@ -5,7 +5,7 @@ repository = "https://github.com/levex/cgroups-rs"
keywords = ["linux", "cgroup", "containers", "isolation"] keywords = ["linux", "cgroup", "containers", "isolation"]
categories = ["os", "api-bindings", "os::unix-apis"] categories = ["os", "api-bindings", "os::unix-apis"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
version = "0.1.1-alpha.0" version = "0.2.0"
authors = ["Levente Kurusa <lkurusa@acm.org>", "Sam Wilson <tecywiz121@hotmail.com>"] authors = ["Levente Kurusa <lkurusa@acm.org>", "Sam Wilson <tecywiz121@hotmail.com>"]
edition = "2018" edition = "2018"
@@ -14,6 +14,7 @@ log = "0.4"
regex = "1.1" regex = "1.1"
nix = "0.18.0" nix = "0.18.0"
libc = "0.2" libc = "0.2"
procinfo = "0.4.2"
[dev-dependencies] [dev-dependencies]
libc = "0.2.76" libc = "0.2.76"

View File

@@ -9,24 +9,29 @@ is planned for the Unified hierarchy.
## Create a control group using the builder pattern ## Create a control group using the builder pattern
``` rust ``` rust
// Acquire a handle for the V1 cgroup hierarchy.
let hier = ::hierarchies::V1::new();
use cgroups::*;
use cgroups::cgroup_builder::*;
// Acquire a handle for the cgroup hierarchy.
let hier = cgroups::hierarchies::auto();
// Use the builder pattern (see the documentation to create the control group) // Use the builder pattern (see the documentation to create the control group)
// //
// This creates a control group named "example" in the V1 hierarchy. // This creates a control group named "example" in the V1 hierarchy.
let cg: Cgroup = CgroupBuilder::new("example", &v1) let cg: Cgroup = CgroupBuilder::new("example")
.cpu() .cpu()
.shares(85) .shares(85)
.done() .done()
.build(); .build(hier);
// Now `cg` is a control group that gets 85% of the CPU time in relative to // Now `cg` is a control group that gets 85% of the CPU time in relative to
// other control groups. // other control groups.
// Get a handle to the CPU controller. // Get a handle to the CPU controller.
let cpus: &CpuController = cg.controller_of().unwrap(); let cpus: &cgroups::cpu::CpuController = cg.controller_of().unwrap();
cpus.add_task(1234u64); cpus.add_task(&CgroupPid::from(1234u64));
// [...] // [...]

View File

@@ -344,39 +344,36 @@ impl ControllerInternal for BlkIoController {
// get the resources that apply to this controller // get the resources that apply to this controller
let res: &BlkIoResources = &res.blkio; let res: &BlkIoResources = &res.blkio;
if res.update_values { if let Some(weight) = res.weight {
if let Some(weight) = res.weight { let _ = self.set_weight(weight as u64);
let _ = self.set_weight(weight as u64); }
} if let Some(leaf_weight) = res.leaf_weight {
if let Some(leaf_weight) = res.leaf_weight { let _ = self.set_leaf_weight(leaf_weight as u64);
let _ = self.set_leaf_weight(leaf_weight as u64); }
}
for dev in &res.weight_device { for dev in &res.weight_device {
if let Some(weight) = dev.weight { if let Some(weight) = dev.weight {
let _ = self.set_weight_for_device(dev.major, dev.minor, weight as u64); 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);
}
} }
if let Some(leaf_weight) = dev.leaf_weight {
let _ = self.set_leaf_weight_for_device(dev.major, dev.minor, leaf_weight as u64);
}
}
for dev in &res.throttle_read_bps_device { for dev in &res.throttle_read_bps_device {
let _ = self.throttle_read_bps_for_device(dev.major, dev.minor, dev.rate); let _ = self.throttle_read_bps_for_device(dev.major, dev.minor, dev.rate);
} }
for dev in &res.throttle_write_bps_device { for dev in &res.throttle_write_bps_device {
let _ = self.throttle_write_bps_for_device(dev.major, dev.minor, dev.rate); let _ = self.throttle_write_bps_for_device(dev.major, dev.minor, dev.rate);
} }
for dev in &res.throttle_read_iops_device { for dev in &res.throttle_read_iops_device {
let _ = self.throttle_read_iops_for_device(dev.major, dev.minor, dev.rate); let _ = self.throttle_read_iops_for_device(dev.major, dev.minor, dev.rate);
} }
for dev in &res.throttle_write_iops_device { for dev in &res.throttle_write_iops_device {
let _ = self.throttle_write_iops_for_device(dev.major, dev.minor, dev.rate); let _ = self.throttle_write_iops_for_device(dev.major, dev.minor, dev.rate);
}
} }
Ok(()) Ok(())
@@ -396,7 +393,8 @@ impl<'a> From<&'a Subsystem> for &'a BlkIoController {
Subsystem::BlkIo(c) => c, Subsystem::BlkIo(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -423,12 +421,8 @@ fn read_u64_from(mut file: File) -> Result<u64> {
} }
impl BlkIoController { impl BlkIoController {
/// Constructs a new `BlkIoController` with `oroot` serving as the root of the control group. /// Constructs a new `BlkIoController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf, v2: bool) -> Self { pub fn new(root: PathBuf, v2: bool) -> Self {
let mut root = oroot;
if !v2 {
root.push(Self::controller_type().to_string());
}
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -9,8 +9,6 @@
use crate::error::ErrorKind::*; use crate::error::ErrorKind::*;
use crate::error::*; use crate::error::*;
use crate::libc_rmdir;
use crate::{CgroupPid, ControllIdentifier, Controller, Hierarchy, Resources, Subsystem}; use crate::{CgroupPid, ControllIdentifier, Controller, Hierarchy, Resources, Subsystem};
use std::collections::HashMap; use std::collections::HashMap;
@@ -30,20 +28,41 @@ use std::path::{Path, PathBuf};
/// > specialized behaviour. /// > specialized behaviour.
/// ///
/// This crate is an attempt at providing a Rust-native way of managing these cgroups. /// This crate is an attempt at providing a Rust-native way of managing these cgroups.
pub struct Cgroup<'b> { #[derive(Debug)]
pub struct Cgroup {
/// The list of subsystems that control this cgroup /// The list of subsystems that control this cgroup
subsystems: Vec<Subsystem>, subsystems: Vec<Subsystem>,
/// The hierarchy. /// The hierarchy.
hier: Box<&'b dyn Hierarchy>, hier: Box<dyn Hierarchy>,
path: String, path: String,
} }
impl<'b> Cgroup<'b> { impl Clone for Cgroup {
fn clone(&self) -> Self {
Cgroup {
subsystems: self.subsystems.clone(),
path: self.path.clone(),
hier: crate::hierarchies::auto(),
}
}
}
impl Default for Cgroup {
fn default() -> Self {
Cgroup {
subsystems: Vec::new(),
hier: crate::hierarchies::auto(),
path: "".to_string(),
}
}
}
impl Cgroup {
/// Create this control group. /// Create this control group.
fn create(&self) { fn create(&self) {
if self.hier.v2() { if self.hier.v2() {
create_v2_cgroup(self.hier.root().clone(), &self.path); let _ret = create_v2_cgroup(self.hier.root().clone(), &self.path);
} else { } else {
for subsystem in &self.subsystems { for subsystem in &self.subsystems {
subsystem.to_controller().create(); subsystem.to_controller().create();
@@ -58,56 +77,66 @@ impl<'b> Cgroup<'b> {
/// Create a new control group in the hierarchy `hier`, with name `path`. /// Create a new control group in the hierarchy `hier`, with name `path`.
/// ///
/// Returns a handle to the control group that can be used to manipulate it. /// Returns a handle to the control group that can be used to manipulate it.
pub fn new<P: AsRef<Path>>(hier: Box<dyn Hierarchy>, path: P) -> Cgroup {
let cg = Cgroup::load(hier, path);
cg.create();
cg
}
/// Create a new control group in the hierarchy `hier`, with name `path` and `relative_paths`
/// ///
/// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// Returns a handle to the control group that can be used to manipulate it.
/// destroyed. ///
pub fn new<P: AsRef<Path>>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup<'b> { /// Note that this method is only meaningful for cgroup v1, call it is equivalent to call `new` in the v2 mode
let relative_paths = get_cgroups_relative_paths().unwrap(); pub fn new_with_relative_paths<P: AsRef<Path>>(
Cgroup::new_with_relative_paths(hier, path, relative_paths) hier: Box<dyn Hierarchy>,
path: P,
relative_paths: HashMap<String, String>,
) -> Cgroup {
let cg = Cgroup::load_with_relative_paths(hier, path, relative_paths);
cg.create();
cg
} }
/// Create a handle for a control group in the hierarchy `hier`, with name `path`. /// Create a handle for a control group in the hierarchy `hier`, with name `path`.
/// ///
/// Returns a handle to the control group (that possibly does not exist until `create()` has /// Returns a handle to the control group (that possibly does not exist until `create()` has
/// been called on the cgroup. /// been called on the cgroup.
/// pub fn load<P: AsRef<Path>>(hier: Box<dyn Hierarchy>, path: P) -> Cgroup {
/// Note that if the handle goes out of scope and is dropped, the control group is _not_ let path = path.as_ref();
/// destroyed. let mut subsystems = hier.subsystems();
pub fn load<P: AsRef<Path>>(hier: Box<&'b dyn Hierarchy>, path: P) -> Cgroup<'b> { if path.as_os_str() != "" {
let relative_paths = get_cgroups_relative_paths().unwrap(); subsystems = subsystems
Cgroup::load_with_relative_paths(hier, path, relative_paths) .into_iter()
} .map(|x| x.enter(path))
.collect::<Vec<_>>();
}
let cg = Cgroup {
path: path.to_str().unwrap().to_string(),
subsystems: subsystems,
hier,
};
/// Create a new control group in the hierarchy `hier`, with name `path`.
/// and relative paths from `/proc/self/cgroup`
///
/// Returns a handle to the control group that can be used to manipulate it.
///
/// 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> {
let cg = Cgroup::load_with_relative_paths(hier, path, relative_paths);
cg.create();
cg cg
} }
/// Create a handle for a control group in the hierarchy `hier`, with name `path`, /// Create a handle for a control group in the hierarchy `hier`, with name `path` and `relative_paths`
/// and relative paths from `/proc/self/cgroup`
/// ///
/// Returns a handle to the control group (that possibly does not exist until `create()` has /// Returns a handle to the control group (that possibly does not exist until `create()` has
/// been called on the cgroup. /// been called on the cgroup.
/// ///
/// Note that if the handle goes out of scope and is dropped, the control group is _not_ /// Note that this method is only meaningful for cgroup v1, call it is equivalent to call `load` in the v2 mode
/// destroyed.
pub fn load_with_relative_paths<P: AsRef<Path>>( pub fn load_with_relative_paths<P: AsRef<Path>>(
hier: Box<&'b dyn Hierarchy>, hier: Box<dyn Hierarchy>,
path: P, path: P,
relative_paths: HashMap<String, String>, relative_paths: HashMap<String, String>,
) -> Cgroup<'b> { ) -> Cgroup {
// relative_paths only valid for cgroup v1
if hier.v2() {
return Self::load(hier, path);
}
let path = path.as_ref(); let path = path.as_ref();
let mut subsystems = hier.subsystems(); let mut subsystems = hier.subsystems();
if path.as_os_str() != "" { if path.as_os_str() != "" {
@@ -130,7 +159,7 @@ impl<'b> Cgroup<'b> {
let cg = Cgroup { let cg = Cgroup {
subsystems: subsystems, subsystems: subsystems,
hier: hier, hier,
path: path.to_str().unwrap().to_string(), path: path.to_str().unwrap().to_string(),
}; };
@@ -148,17 +177,17 @@ impl<'b> Cgroup<'b> {
/// system call will fail if there are any descendants. Thus, one should check whether it was /// system call will fail if there are any descendants. Thus, one should check whether it was
/// actually removed, and remove the descendants first if not. In the future, this behavior /// actually removed, and remove the descendants first if not. In the future, this behavior
/// will change. /// will change.
pub fn delete(self) { pub fn delete(&self) -> Result<()> {
if self.v2() { if self.v2() {
if self.path != "" { if self.path != "" {
let mut p = self.hier.root().clone(); let mut p = self.hier.root().clone();
p.push(self.path); p.push(self.path.clone());
libc_rmdir(p.to_str().unwrap()); return fs::remove_dir(p).map_err(|e| Error::with_cause(RemoveFailed, e));
} }
return; return Ok(());
} }
self.subsystems.into_iter().for_each(|sub| match sub { self.subsystems.iter().try_for_each(|sub| match sub {
Subsystem::Pid(pidc) => pidc.delete(), Subsystem::Pid(pidc) => pidc.delete(),
Subsystem::Mem(c) => c.delete(), Subsystem::Mem(c) => c.delete(),
Subsystem::CpuSet(c) => c.delete(), Subsystem::CpuSet(c) => c.delete(),
@@ -173,7 +202,7 @@ impl<'b> Cgroup<'b> {
Subsystem::HugeTlb(c) => c.delete(), Subsystem::HugeTlb(c) => c.delete(),
Subsystem::Rdma(c) => c.delete(), Subsystem::Rdma(c) => c.delete(),
Subsystem::Systemd(c) => c.delete(), Subsystem::Systemd(c) => c.delete(),
}); })
} }
/// Apply a set of resource limits to the control group. /// Apply a set of resource limits to the control group.
@@ -233,6 +262,29 @@ impl<'b> Cgroup<'b> {
} }
} }
/// Attach a task to the control group by thread group id.
pub fn add_task_by_tgid(&self, pid: CgroupPid) -> Result<()> {
self.subsystems()
.iter()
.try_for_each(|sub| sub.to_controller().add_task_by_tgid(&pid))
}
/// Set notify_on_release to the control group.
pub fn set_notify_on_release(&self, enable: bool) -> Result<()> {
self.subsystems()
.iter()
.try_for_each(|sub| sub.to_controller().set_notify_on_release(enable))
}
/// Set release_agent
pub fn set_release_agent(&self, path: &str) -> Result<()> {
self.hier
.root_control_group()
.subsystems()
.iter()
.try_for_each(|sub| sub.to_controller().set_release_agent(path))
}
/// Returns an Iterator that can be used to iterate over the tasks that are currently in the /// Returns an Iterator that can be used to iterate over the tasks that are currently in the
/// control group. /// control group.
pub fn tasks(&self) -> Vec<CgroupPid> { pub fn tasks(&self) -> Vec<CgroupPid> {
@@ -272,7 +324,7 @@ fn enable_controllers(controllers: &Vec<String>, path: &PathBuf) {
} }
} }
fn supported_controllers(p: &PathBuf) -> Vec<String> { fn supported_controllers() -> Vec<String> {
let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers"); let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers");
let ret = fs::read_to_string(p.as_str()); let ret = fs::read_to_string(p.as_str());
ret.unwrap_or(String::new()) ret.unwrap_or(String::new())
@@ -283,7 +335,7 @@ fn supported_controllers(p: &PathBuf) -> Vec<String> {
fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> { fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> {
// controler list ["memory", "cpu"] // controler list ["memory", "cpu"]
let controllers = supported_controllers(&root); let controllers = supported_controllers();
let mut fp = root; let mut fp = root;
// enable for root // enable for root
@@ -324,13 +376,7 @@ pub fn get_cgroups_relative_paths() -> Result<HashMap<String, String>> {
let keys: Vec<&str> = fl[1].split(',').collect(); let keys: Vec<&str> = fl[1].split(',').collect();
for key in &keys { for key in &keys {
// this is a workaround, cgroup file are using `name=systemd`, m.insert(key.to_string(), fl[2].to_string());
// but if file system the name is `systemd`
if *key == "name=systemd" {
m.insert("systemd".to_string(), fl[2].to_string());
} else {
m.insert(key.to_string(), fl[2].to_string());
}
} }
} }
Ok(m) Ok(m)

View File

@@ -20,8 +20,7 @@
//! # use cgroups::devices::*; //! # use cgroups::devices::*;
//! # use cgroups::cgroup_builder::*; //! # use cgroups::cgroup_builder::*;
//! let h = cgroups::hierarchies::auto(); //! let h = cgroups::hierarchies::auto();
//! let h = Box::new(&*h); //! let cgroup: Cgroup = CgroupBuilder::new("hello")
//! let cgroup: Cgroup = CgroupBuilder::new("hello", h)
//! .memory() //! .memory()
//! .kernel_memory_limit(1024 * 1024) //! .kernel_memory_limit(1024 * 1024)
//! .memory_hard_limit(1024 * 1024) //! .memory_hard_limit(1024 * 1024)
@@ -47,8 +46,8 @@
//! .limit("2G".to_string(), 2 * 1024 * 1024 * 1024) //! .limit("2G".to_string(), 2 * 1024 * 1024 * 1024)
//! .done() //! .done()
//! .blkio() //! .blkio()
//! .weight(Some(123)) //! .weight(123)
//! .leaf_weight(Some(99)) //! .leaf_weight(99)
//! .weight_device(6, 1, Some(100), Some(55)) //! .weight_device(6, 1, Some(100), Some(55))
//! .weight_device(6, 1, Some(100), Some(55)) //! .weight_device(6, 1, Some(100), Some(55))
//! .throttle_iops() //! .throttle_iops()
@@ -58,12 +57,11 @@
//! .read(6, 1, 10) //! .read(6, 1, 10)
//! .write(11, 1, 100) //! .write(11, 1, 100)
//! .done() //! .done()
//! .build(); //! .build(h);
//! ``` //! ```
use crate::error::*;
use crate::{ use crate::{
pid, BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy, BlkIoDeviceResource, BlkIoDeviceThrottleResource, Cgroup, DeviceResource, Hierarchy,
HugePageResource, MaxValue, NetworkPriority, Resources, HugePageResource, MaxValue, NetworkPriority, Resources,
}; };
@@ -71,67 +69,64 @@ macro_rules! gen_setter {
($res:ident, $cont:ident, $func:ident, $name:ident, $ty:ty) => { ($res:ident, $cont:ident, $func:ident, $name:ident, $ty:ty) => {
/// See the similarly named function in the respective controller. /// See the similarly named function in the respective controller.
pub fn $name(mut self, $name: $ty) -> Self { pub fn $name(mut self, $name: $ty) -> Self {
self.cgroup.resources.$res.update_values = true; self.cgroup.resources.$res.$name = Some($name);
self.cgroup.resources.$res.$name = $name;
self self
} }
}; };
} }
/// A control group builder instance /// A control group builder instance
pub struct CgroupBuilder<'a> { pub struct CgroupBuilder {
name: String, name: String,
hierarchy: Box<&'a dyn Hierarchy>,
/// Internal, unsupported field: use the associated builders instead. /// Internal, unsupported field: use the associated builders instead.
resources: Resources, resources: Resources,
} }
impl<'a> CgroupBuilder<'a> { impl CgroupBuilder {
/// Start building a control group with the supplied hierarchy and name pair. /// Start building a control group with the supplied hierarchy and name pair.
/// ///
/// Note that this does not actually create the control group until `build()` is called. /// Note that this does not actually create the control group until `build()` is called.
pub fn new(name: &'a str, hierarchy: Box<&'a dyn Hierarchy>) -> CgroupBuilder<'a> { pub fn new(name: &str) -> CgroupBuilder {
CgroupBuilder { CgroupBuilder {
name: name.to_owned(), name: name.to_owned(),
hierarchy: hierarchy,
resources: Resources::default(), resources: Resources::default(),
} }
} }
/// Builds the memory resources of the control group. /// Builds the memory resources of the control group.
pub fn memory(self) -> MemoryResourceBuilder<'a> { pub fn memory(self) -> MemoryResourceBuilder {
MemoryResourceBuilder { cgroup: self } MemoryResourceBuilder { cgroup: self }
} }
/// Builds the pid resources of the control group. /// Builds the pid resources of the control group.
pub fn pid(self) -> PidResourceBuilder<'a> { pub fn pid(self) -> PidResourceBuilder {
PidResourceBuilder { cgroup: self } PidResourceBuilder { cgroup: self }
} }
/// Builds the cpu resources of the control group. /// Builds the cpu resources of the control group.
pub fn cpu(self) -> CpuResourceBuilder<'a> { pub fn cpu(self) -> CpuResourceBuilder {
CpuResourceBuilder { cgroup: self } CpuResourceBuilder { cgroup: self }
} }
/// Builds the devices resources of the control group, disallowing or /// Builds the devices resources of the control group, disallowing or
/// allowing access to certain devices in the system. /// allowing access to certain devices in the system.
pub fn devices(self) -> DeviceResourceBuilder<'a> { pub fn devices(self) -> DeviceResourceBuilder {
DeviceResourceBuilder { cgroup: self } DeviceResourceBuilder { cgroup: self }
} }
/// Builds the network resources of the control group, setting class id, or /// Builds the network resources of the control group, setting class id, or
/// various priorities on networking interfaces. /// various priorities on networking interfaces.
pub fn network(self) -> NetworkResourceBuilder<'a> { pub fn network(self) -> NetworkResourceBuilder {
NetworkResourceBuilder { cgroup: self } NetworkResourceBuilder { cgroup: self }
} }
/// Builds the hugepage/hugetlb resources available to the control group. /// Builds the hugepage/hugetlb resources available to the control group.
pub fn hugepages(self) -> HugepagesResourceBuilder<'a> { pub fn hugepages(self) -> HugepagesResourceBuilder {
HugepagesResourceBuilder { cgroup: self } HugepagesResourceBuilder { cgroup: self }
} }
/// Builds the block I/O resources available for the control group. /// Builds the block I/O resources available for the control group.
pub fn blkio(self) -> BlkIoResourcesBuilder<'a> { pub fn blkio(self) -> BlkIoResourcesBuilder {
BlkIoResourcesBuilder { BlkIoResourcesBuilder {
cgroup: self, cgroup: self,
throttling_iops: false, throttling_iops: false,
@@ -139,19 +134,19 @@ impl<'a> CgroupBuilder<'a> {
} }
/// Finalize the control group, consuming the builder and creating the control group. /// Finalize the control group, consuming the builder and creating the control group.
pub fn build(self) -> Cgroup<'a> { pub fn build(self, hier: Box<dyn Hierarchy>) -> Cgroup {
let cg = Cgroup::new(self.hierarchy, self.name); let cg = Cgroup::new(hier, self.name);
cg.apply(&self.resources); let _ret = cg.apply(&self.resources);
cg cg
} }
} }
/// A builder that configures the memory controller of a control group. /// A builder that configures the memory controller of a control group.
pub struct MemoryResourceBuilder<'a> { pub struct MemoryResourceBuilder {
cgroup: CgroupBuilder<'a>, cgroup: CgroupBuilder,
} }
impl<'a> MemoryResourceBuilder<'a> { impl MemoryResourceBuilder {
gen_setter!( gen_setter!(
memory, memory,
MemController, MemController,
@@ -184,17 +179,17 @@ impl<'a> MemoryResourceBuilder<'a> {
gen_setter!(memory, MemController, set_swappiness, swappiness, u64); gen_setter!(memory, MemController, set_swappiness, swappiness, u64);
/// Finish the construction of the memory resources of a control group. /// Finish the construction of the memory resources of a control group.
pub fn done(self) -> CgroupBuilder<'a> { pub fn done(self) -> CgroupBuilder {
self.cgroup self.cgroup
} }
} }
/// A builder that configures the pid controller of a control group. /// A builder that configures the pid controller of a control group.
pub struct PidResourceBuilder<'a> { pub struct PidResourceBuilder {
cgroup: CgroupBuilder<'a>, cgroup: CgroupBuilder,
} }
impl<'a> PidResourceBuilder<'a> { impl PidResourceBuilder {
gen_setter!( gen_setter!(
pid, pid,
PidController, PidController,
@@ -204,19 +199,18 @@ impl<'a> PidResourceBuilder<'a> {
); );
/// Finish the construction of the pid resources of a control group. /// Finish the construction of the pid resources of a control group.
pub fn done(self) -> CgroupBuilder<'a> { pub fn done(self) -> CgroupBuilder {
self.cgroup self.cgroup
} }
} }
/// A builder that configures the cpuset & cpu controllers of a control group. /// A builder that configures the cpuset & cpu controllers of a control group.
pub struct CpuResourceBuilder<'a> { pub struct CpuResourceBuilder {
cgroup: CgroupBuilder<'a>, cgroup: CgroupBuilder,
} }
impl<'a> CpuResourceBuilder<'a> { impl CpuResourceBuilder {
// FIXME this should all changed to options. gen_setter!(cpu, CpuSetController, set_cpus, cpus, String);
gen_setter!(cpu, CpuSetController, set_cpus, cpus, Option<String>);
gen_setter!(cpu, CpuSetController, set_mems, mems, String); gen_setter!(cpu, CpuSetController, set_mems, mems, String);
gen_setter!(cpu, CpuController, set_shares, shares, u64); gen_setter!(cpu, CpuController, set_shares, shares, u64);
gen_setter!(cpu, CpuController, set_cfs_quota, quota, i64); gen_setter!(cpu, CpuController, set_cfs_quota, quota, i64);
@@ -225,17 +219,17 @@ impl<'a> CpuResourceBuilder<'a> {
gen_setter!(cpu, CpuController, set_rt_period, realtime_period, u64); gen_setter!(cpu, CpuController, set_rt_period, realtime_period, u64);
/// Finish the construction of the cpu resources of a control group. /// Finish the construction of the cpu resources of a control group.
pub fn done(self) -> CgroupBuilder<'a> { pub fn done(self) -> CgroupBuilder {
self.cgroup self.cgroup
} }
} }
/// A builder that configures the devices controller of a control group. /// A builder that configures the devices controller of a control group.
pub struct DeviceResourceBuilder<'a> { pub struct DeviceResourceBuilder {
cgroup: CgroupBuilder<'a>, cgroup: CgroupBuilder,
} }
impl<'a> DeviceResourceBuilder<'a> { impl DeviceResourceBuilder {
/// Restrict (or allow) a device to the tasks inside the control group. /// Restrict (or allow) a device to the tasks inside the control group.
pub fn device( pub fn device(
mut self, mut self,
@@ -244,8 +238,7 @@ impl<'a> DeviceResourceBuilder<'a> {
devtype: crate::devices::DeviceType, devtype: crate::devices::DeviceType,
allow: bool, allow: bool,
access: Vec<crate::devices::DevicePermissions>, access: Vec<crate::devices::DevicePermissions>,
) -> DeviceResourceBuilder<'a> { ) -> DeviceResourceBuilder {
self.cgroup.resources.devices.update_values = true;
self.cgroup.resources.devices.devices.push(DeviceResource { self.cgroup.resources.devices.devices.push(DeviceResource {
major, major,
minor, minor,
@@ -257,23 +250,22 @@ impl<'a> DeviceResourceBuilder<'a> {
} }
/// Finish the construction of the devices resources of a control group. /// Finish the construction of the devices resources of a control group.
pub fn done(self) -> CgroupBuilder<'a> { pub fn done(self) -> CgroupBuilder {
self.cgroup self.cgroup
} }
} }
/// A builder that configures the net_cls & net_prio controllers of a control group. /// A builder that configures the net_cls & net_prio controllers of a control group.
pub struct NetworkResourceBuilder<'a> { pub struct NetworkResourceBuilder {
cgroup: CgroupBuilder<'a>, cgroup: CgroupBuilder,
} }
impl<'a> NetworkResourceBuilder<'a> { impl NetworkResourceBuilder {
gen_setter!(network, NetclsController, set_class, class_id, u64); 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 /// Set the priority of the tasks when operating on a networking device defined by `name` to be
/// `priority`. /// `priority`.
pub fn priority(mut self, name: String, priority: u64) -> NetworkResourceBuilder<'a> { pub fn priority(mut self, name: String, priority: u64) -> NetworkResourceBuilder {
self.cgroup.resources.network.update_values = true;
self.cgroup self.cgroup
.resources .resources
.network .network
@@ -283,20 +275,19 @@ impl<'a> NetworkResourceBuilder<'a> {
} }
/// Finish the construction of the network resources of a control group. /// Finish the construction of the network resources of a control group.
pub fn done(self) -> CgroupBuilder<'a> { pub fn done(self) -> CgroupBuilder {
self.cgroup self.cgroup
} }
} }
/// A builder that configures the hugepages controller of a control group. /// A builder that configures the hugepages controller of a control group.
pub struct HugepagesResourceBuilder<'a> { pub struct HugepagesResourceBuilder {
cgroup: CgroupBuilder<'a>, cgroup: CgroupBuilder,
} }
impl<'a> HugepagesResourceBuilder<'a> { impl HugepagesResourceBuilder {
/// Limit the usage of certain hugepages (determined by `size`) to be at most `limit` bytes. /// 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 {
self.cgroup.resources.hugepages.update_values = true;
self.cgroup self.cgroup
.resources .resources
.hugepages .hugepages
@@ -306,26 +297,20 @@ impl<'a> HugepagesResourceBuilder<'a> {
} }
/// Finish the construction of the network resources of a control group. /// Finish the construction of the network resources of a control group.
pub fn done(self) -> CgroupBuilder<'a> { pub fn done(self) -> CgroupBuilder {
self.cgroup self.cgroup
} }
} }
/// A builder that configures the blkio controller of a control group. /// A builder that configures the blkio controller of a control group.
pub struct BlkIoResourcesBuilder<'a> { pub struct BlkIoResourcesBuilder {
cgroup: CgroupBuilder<'a>, cgroup: CgroupBuilder,
throttling_iops: bool, throttling_iops: bool,
} }
impl<'a> BlkIoResourcesBuilder<'a> { impl BlkIoResourcesBuilder {
gen_setter!(blkio, BlkIoController, set_weight, weight, Option<u16>); gen_setter!(blkio, BlkIoController, set_weight, weight, u16);
gen_setter!( gen_setter!(blkio, BlkIoController, set_leaf_weight, leaf_weight, u16);
blkio,
BlkIoController,
set_leaf_weight,
leaf_weight,
Option<u16>
);
/// Set the weight of a certain device. /// Set the weight of a certain device.
pub fn weight_device( pub fn weight_device(
@@ -334,8 +319,7 @@ impl<'a> BlkIoResourcesBuilder<'a> {
minor: u64, minor: u64,
weight: Option<u16>, weight: Option<u16>,
leaf_weight: Option<u16>, leaf_weight: Option<u16>,
) -> BlkIoResourcesBuilder<'a> { ) -> BlkIoResourcesBuilder {
self.cgroup.resources.blkio.update_values = true;
self.cgroup self.cgroup
.resources .resources
.blkio .blkio
@@ -350,20 +334,19 @@ impl<'a> BlkIoResourcesBuilder<'a> {
} }
/// Start configuring the I/O operations per second metric. /// Start configuring the I/O operations per second metric.
pub fn throttle_iops(mut self) -> BlkIoResourcesBuilder<'a> { pub fn throttle_iops(mut self) -> BlkIoResourcesBuilder {
self.throttling_iops = true; self.throttling_iops = true;
self self
} }
/// Start configuring the bytes per second metric. /// Start configuring the bytes per second metric.
pub fn throttle_bps(mut self) -> BlkIoResourcesBuilder<'a> { pub fn throttle_bps(mut self) -> BlkIoResourcesBuilder {
self.throttling_iops = false; self.throttling_iops = false;
self self
} }
/// Limit the read rate of the current metric for a certain device. /// 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 {
self.cgroup.resources.blkio.update_values = true;
let throttle = BlkIoDeviceThrottleResource { major, minor, rate }; let throttle = BlkIoDeviceThrottleResource { major, minor, rate };
if self.throttling_iops { if self.throttling_iops {
self.cgroup self.cgroup
@@ -382,8 +365,7 @@ impl<'a> BlkIoResourcesBuilder<'a> {
} }
/// Limit the write rate of the current metric for a certain device. /// 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 {
self.cgroup.resources.blkio.update_values = true;
let throttle = BlkIoDeviceThrottleResource { major, minor, rate }; let throttle = BlkIoDeviceThrottleResource { major, minor, rate };
if self.throttling_iops { if self.throttling_iops {
self.cgroup self.cgroup
@@ -402,7 +384,7 @@ impl<'a> BlkIoResourcesBuilder<'a> {
} }
/// Finish the construction of the blkio resources of a control group. /// Finish the construction of the blkio resources of a control group.
pub fn done(self) -> CgroupBuilder<'a> { pub fn done(self) -> CgroupBuilder {
self.cgroup self.cgroup
} }
} }

View File

@@ -18,8 +18,8 @@ use crate::error::*;
use crate::{parse_max_value, read_i64_from}; use crate::{parse_max_value, read_i64_from};
use crate::{ use crate::{
ControllIdentifier, ControllerInternal, Controllers, CpuResources, MaxValue, Resources, ControllIdentifier, ControllerInternal, Controllers, CpuResources, CustomizedAttribute,
Subsystem, MaxValue, Resources, Subsystem,
}; };
/// A controller that allows controlling the `cpu` subsystem of a Cgroup. /// A controller that allows controlling the `cpu` subsystem of a Cgroup.
@@ -75,24 +75,15 @@ impl ControllerInternal for CpuController {
// get the resources that apply to this controller // get the resources that apply to this controller
let res: &CpuResources = &res.cpu; let res: &CpuResources = &res.cpu;
if res.update_values { update_and_test!(self, set_shares, res.shares, shares);
let _ = self.set_shares(res.shares); update_and_test!(self, set_cfs_period, res.period, cfs_period);
if self.shares()? != res.shares as u64 { update_and_test!(self, set_cfs_quota, res.quota, cfs_quota);
return Err(Error::new(ErrorKind::Other));
}
let _ = self.set_cfs_period(res.period); res.attrs.iter().for_each(|(k, v)| {
if self.cfs_period()? != res.period as u64 { let _ = self.set(k, v);
return Err(Error::new(ErrorKind::Other)); });
}
let _ = self.set_cfs_quota(res.quota); // TODO: rt properties (CONFIG_RT_GROUP_SCHED) are not yet supported
if self.cfs_quota()? != res.quota {
return Err(Error::new(ErrorKind::Other));
}
// TODO: rt properties (CONFIG_RT_GROUP_SCHED) are not yet supported
}
Ok(()) Ok(())
} }
@@ -111,7 +102,8 @@ impl<'a> From<&'a Subsystem> for &'a CpuController {
Subsystem::Cpu(c) => c, Subsystem::Cpu(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -130,12 +122,8 @@ fn read_u64_from(mut file: File) -> Result<u64> {
} }
impl CpuController { impl CpuController {
/// Contructs a new `CpuController` with `oroot` serving as the root of the control group. /// Contructs a new `CpuController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf, v2: bool) -> Self { pub fn new(root: PathBuf, v2: bool) -> Self {
let mut root = oroot;
if !v2 {
root.push(Self::controller_type().to_string());
}
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,
@@ -305,6 +293,8 @@ impl CpuController {
} }
} }
impl CustomizedAttribute for CpuController {}
fn parse_cfs_quota_and_period(mut file: File) -> Result<CFSQuotaAndPeriod> { fn parse_cfs_quota_and_period(mut file: File) -> Result<CFSQuotaAndPeriod> {
let mut content = String::new(); let mut content = String::new();
file.read_to_string(&mut content) file.read_to_string(&mut content)

View File

@@ -89,7 +89,8 @@ impl<'a> From<&'a Subsystem> for &'a CpuAcctController {
Subsystem::CpuAcct(c) => c, Subsystem::CpuAcct(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -117,10 +118,8 @@ fn read_string_from(mut file: File) -> Result<String> {
} }
impl CpuAcctController { impl CpuAcctController {
/// Contructs a new `CpuAcctController` with `oroot` serving as the root of the control group. /// Contructs a new `CpuAcctController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf) -> Self { pub fn new(root: PathBuf) -> Self {
let mut root = oroot;
root.push(Self::controller_type().to_string());
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -110,12 +110,8 @@ impl ControllerInternal for CpuSetController {
// get the resources that apply to this controller // get the resources that apply to this controller
let res: &CpuResources = &res.cpu; let res: &CpuResources = &res.cpu;
if res.update_values { update!(self, set_cpus, res.cpus.as_ref());
if res.cpus.is_some() { update!(self, set_mems, res.mems.as_ref());
let _ = self.set_cpus(res.cpus.as_ref().unwrap().as_str());
}
let _ = self.set_mems(&res.mems);
}
Ok(()) Ok(())
} }
@@ -125,10 +121,6 @@ impl ControllerInternal for CpuSetController {
return; return;
} }
let current = self.get_path(); let current = self.get_path();
let parent = match current.parent() {
Some(p) => p,
None => return,
};
if current != self.get_base() { if current != self.get_base() {
match copy_from_parent(current.to_str().unwrap(), "cpuset.cpus") { match copy_from_parent(current.to_str().unwrap(), "cpuset.cpus") {
@@ -204,7 +196,8 @@ impl<'a> From<&'a Subsystem> for &'a CpuSetController {
Subsystem::CpuSet(c) => c, Subsystem::CpuSet(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -268,12 +261,8 @@ fn parse_range(s: String) -> Result<Vec<(u64, u64)>> {
} }
impl CpuSetController { impl CpuSetController {
/// Contructs a new `CpuSetController` with `oroot` serving as the root of the control group. /// Contructs a new `CpuSetController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf, v2: bool) -> Self { pub fn new(root: PathBuf, v2: bool) -> Self {
let mut root = oroot;
if !v2 {
root.push(Self::controller_type().to_string());
}
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -155,13 +155,11 @@ impl ControllerInternal for DevicesController {
// get the resources that apply to this controller // get the resources that apply to this controller
let res: &DeviceResources = &res.devices; let res: &DeviceResources = &res.devices;
if res.update_values { for i in &res.devices {
for i in &res.devices { if i.allow {
if i.allow { let _ = self.allow_device(i.devtype, i.major, i.minor, &i.access);
let _ = self.allow_device(i.devtype, i.major, i.minor, &i.access); } else {
} else { let _ = self.deny_device(i.devtype, i.major, i.minor, &i.access);
let _ = self.deny_device(i.devtype, i.major, i.minor, &i.access);
}
} }
} }
@@ -182,7 +180,8 @@ impl<'a> From<&'a Subsystem> for &'a DevicesController {
Subsystem::Devices(c) => c, Subsystem::Devices(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -190,10 +189,8 @@ impl<'a> From<&'a Subsystem> for &'a DevicesController {
} }
impl DevicesController { impl DevicesController {
/// Constructs a new `DevicesController` with `oroot` serving as the root of the control group. /// Constructs a new `DevicesController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf) -> Self { pub fn new(root: PathBuf) -> Self {
let mut root = oroot;
root.push(Self::controller_type().to_string());
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -19,6 +19,9 @@ pub enum ErrorKind {
/// An error occured while trying to read from a control group file. /// An error occured while trying to read from a control group file.
ReadFailed, ReadFailed,
/// An error occured while trying to remove a control group.
RemoveFailed,
/// An error occured while trying to parse a value from a control group file. /// An error occured while trying to parse a value from a control group file.
/// ///
/// In the future, there will be some information attached to this field. /// In the future, there will be some information attached to this field.
@@ -45,7 +48,7 @@ pub enum ErrorKind {
#[derive(Debug)] #[derive(Debug)]
pub struct Error { pub struct Error {
kind: ErrorKind, kind: ErrorKind,
cause: Option<Box<StdError + Send + Sync>>, cause: Option<Box<dyn StdError + Send + Sync>>,
} }
impl fmt::Display for Error { impl fmt::Display for Error {
@@ -55,6 +58,7 @@ impl fmt::Display for Error {
ErrorKind::Common(s) => s.clone(), ErrorKind::Common(s) => s.clone(),
ErrorKind::WriteFailed => "unable to write to a control group file".to_string(), ErrorKind::WriteFailed => "unable to write to a control group file".to_string(),
ErrorKind::ReadFailed => "unable to read a control group file".to_string(), ErrorKind::ReadFailed => "unable to read a control group file".to_string(),
ErrorKind::RemoveFailed => "unable to remove a control group".to_string(),
ErrorKind::ParseError => "unable to parse control group file".to_string(), ErrorKind::ParseError => "unable to parse control group file".to_string(),
ErrorKind::InvalidOperation => "the requested operation is invalid".to_string(), ErrorKind::InvalidOperation => "the requested operation is invalid".to_string(),
ErrorKind::InvalidPath => "the given path is invalid".to_string(), ErrorKind::InvalidPath => "the given path is invalid".to_string(),
@@ -62,12 +66,16 @@ impl fmt::Display for Error {
ErrorKind::Other => "an unknown error".to_string(), ErrorKind::Other => "an unknown error".to_string(),
}; };
write!(f, "{}", msg) if let Some(cause) = &self.cause {
write!(f, "{} caused by: {:?}", msg, cause)
} else {
write!(f, "{}", msg)
}
} }
} }
impl StdError for Error { impl StdError for Error {
fn cause(&self) -> Option<&StdError> { fn cause(&self) -> Option<&dyn StdError> {
match self.cause { match self.cause {
Some(ref x) => Some(&**x), Some(ref x) => Some(&**x),
None => None, None => None,

View File

@@ -60,7 +60,7 @@ fn register_memory_event(
} }
// write to file and set mode to 0700(FIXME) // write to file and set mode to 0700(FIXME)
fs::write(&event_control_path, data).map_err(|e| Error::with_cause(WriteFailed, e)); fs::write(&event_control_path, data).map_err(|e| Error::with_cause(WriteFailed, e))?;
let mut eventfd_file = unsafe { File::from_raw_fd(eventfd) }; let mut eventfd_file = unsafe { File::from_raw_fd(eventfd) };
@@ -71,7 +71,7 @@ fn register_memory_event(
loop { loop {
let mut buf = [0; 8]; let mut buf = [0; 8];
match eventfd_file.read(&mut buf) { match eventfd_file.read(&mut buf) {
Err(err) => { Err(_err) => {
return; return;
} }
Ok(_) => {} Ok(_) => {}

View File

@@ -73,7 +73,8 @@ impl<'a> From<&'a Subsystem> for &'a FreezerController {
Subsystem::Freezer(c) => c, Subsystem::Freezer(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -81,12 +82,8 @@ impl<'a> From<&'a Subsystem> for &'a FreezerController {
} }
impl FreezerController { impl FreezerController {
/// Contructs a new `FreezerController` with `oroot` serving as the root of the control group. /// Contructs a new `FreezerController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf, v2: bool) -> Self { pub fn new(root: PathBuf, v2: bool) -> Self {
let mut root = oroot;
if !v2 {
root.push(Self::controller_type().to_string());
}
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -8,14 +8,10 @@
//! //!
//! Currently, we only support the cgroupv1 hierarchy, but in the future we will add support for //! Currently, we only support the cgroupv1 hierarchy, but in the future we will add support for
//! the Unified Hierarchy. //! the Unified Hierarchy.
use nix::sys::statfs;
use std::fs::{self, File}; use procinfo::pid::{mountinfo_self, Mountinfo};
use std::io::BufRead; use std::fs;
use std::io::BufReader; use std::path::PathBuf;
use std::path::{Path, PathBuf};
use log::*;
use crate::blkio::BlkIoController; use crate::blkio::BlkIoController;
use crate::cpu::CpuController; use crate::cpu::CpuController;
@@ -36,10 +32,12 @@ use crate::{Controllers, Hierarchy, Subsystem};
use crate::cgroup::Cgroup; use crate::cgroup::Cgroup;
/// The standard, original cgroup implementation. Often referred to as "cgroupv1". /// The standard, original cgroup implementation. Often referred to as "cgroupv1".
#[derive(Debug)]
pub struct V1 { pub struct V1 {
mount_point: String, mountinfo: Vec<Mountinfo>,
} }
#[derive(Debug)]
pub struct V2 { pub struct V2 {
root: String, root: String,
} }
@@ -51,80 +49,71 @@ impl Hierarchy for V1 {
fn subsystems(&self) -> Vec<Subsystem> { fn subsystems(&self) -> Vec<Subsystem> {
let mut subs = vec![]; let mut subs = vec![];
if self.check_support(Controllers::Pids) {
subs.push(Subsystem::Pid(PidController::new(self.root(), false))); // The cgroup writeback feature requires cooperation between memcgs and blkcgs
// To avoid exceptions, we should add_task for blkcg before memcg(push BlkIo before Mem)
// For more Information: https://www.alibabacloud.com/help/doc-detail/155509.htm
if let Some(root) = self.get_mount_point(Controllers::BlkIo) {
subs.push(Subsystem::BlkIo(BlkIoController::new(root, false)));
} }
if self.check_support(Controllers::Mem) { if let Some(root) = self.get_mount_point(Controllers::Mem) {
subs.push(Subsystem::Mem(MemController::new(self.root(), false))); subs.push(Subsystem::Mem(MemController::new(root, false)));
} }
if self.check_support(Controllers::CpuSet) { if let Some(root) = self.get_mount_point(Controllers::Pids) {
subs.push(Subsystem::CpuSet(CpuSetController::new(self.root(), false))); subs.push(Subsystem::Pid(PidController::new(root, false)));
} }
if self.check_support(Controllers::CpuAcct) { if let Some(root) = self.get_mount_point(Controllers::CpuSet) {
subs.push(Subsystem::CpuAcct(CpuAcctController::new(self.root()))); subs.push(Subsystem::CpuSet(CpuSetController::new(root, false)));
} }
if self.check_support(Controllers::Cpu) { if let Some(root) = self.get_mount_point(Controllers::CpuAcct) {
subs.push(Subsystem::Cpu(CpuController::new(self.root(), false))); subs.push(Subsystem::CpuAcct(CpuAcctController::new(root)));
} }
if self.check_support(Controllers::Devices) { if let Some(root) = self.get_mount_point(Controllers::Cpu) {
subs.push(Subsystem::Devices(DevicesController::new(self.root()))); subs.push(Subsystem::Cpu(CpuController::new(root, false)));
} }
if self.check_support(Controllers::Freezer) { if let Some(root) = self.get_mount_point(Controllers::Devices) {
subs.push(Subsystem::Freezer(FreezerController::new( subs.push(Subsystem::Devices(DevicesController::new(root)));
self.root(),
false,
)));
} }
if self.check_support(Controllers::NetCls) { if let Some(root) = self.get_mount_point(Controllers::Freezer) {
subs.push(Subsystem::NetCls(NetClsController::new(self.root()))); subs.push(Subsystem::Freezer(FreezerController::new(root, false)));
} }
if self.check_support(Controllers::BlkIo) { if let Some(root) = self.get_mount_point(Controllers::NetCls) {
subs.push(Subsystem::BlkIo(BlkIoController::new(self.root(), false))); subs.push(Subsystem::NetCls(NetClsController::new(root)));
} }
if self.check_support(Controllers::PerfEvent) { if let Some(root) = self.get_mount_point(Controllers::PerfEvent) {
subs.push(Subsystem::PerfEvent(PerfEventController::new(self.root()))); subs.push(Subsystem::PerfEvent(PerfEventController::new(root)));
} }
if self.check_support(Controllers::NetPrio) { if let Some(root) = self.get_mount_point(Controllers::NetPrio) {
subs.push(Subsystem::NetPrio(NetPrioController::new(self.root()))); subs.push(Subsystem::NetPrio(NetPrioController::new(root)));
} }
if self.check_support(Controllers::HugeTlb) { if let Some(root) = self.get_mount_point(Controllers::HugeTlb) {
subs.push(Subsystem::HugeTlb(HugeTlbController::new( subs.push(Subsystem::HugeTlb(HugeTlbController::new(root, false)));
self.root(),
false,
)));
} }
if self.check_support(Controllers::Rdma) { if let Some(root) = self.get_mount_point(Controllers::Rdma) {
subs.push(Subsystem::Rdma(RdmaController::new(self.root()))); subs.push(Subsystem::Rdma(RdmaController::new(root)));
} }
if self.check_support(Controllers::Systemd) { if let Some(root) = self.get_mount_point(Controllers::Systemd) {
subs.push(Subsystem::Systemd(SystemdController::new( subs.push(Subsystem::Systemd(SystemdController::new(root, false)));
self.root(),
false,
)));
} }
subs subs
} }
fn root_control_group(&self) -> Cgroup { fn root_control_group(&self) -> Cgroup {
let b: &Hierarchy = self as &Hierarchy; Cgroup::load(auto(), "".to_string())
Cgroup::load(Box::new(&*b), "".to_string())
}
fn check_support(&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) -> PathBuf { fn root(&self) -> PathBuf {
PathBuf::from(self.mount_point.clone()) self.mountinfo
.iter()
.find_map(|m| {
if m.fs_type.0 == "cgroup" {
return Some(m.mount_point.parent().unwrap());
}
None
})
.unwrap()
.to_path_buf()
} }
} }
@@ -182,12 +171,7 @@ impl Hierarchy for V2 {
} }
fn root_control_group(&self) -> Cgroup { fn root_control_group(&self) -> Cgroup {
let b: &Hierarchy = self as &Hierarchy; Cgroup::load(auto(), "".to_string())
Cgroup::load(Box::new(&*b), "".to_string())
}
fn check_support(&self, _sub: Controllers) -> bool {
return false;
} }
fn root(&self) -> PathBuf { fn root(&self) -> PathBuf {
@@ -199,11 +183,19 @@ impl V1 {
/// Finds where control groups are mounted to and returns a hierarchy in which control groups /// Finds where control groups are mounted to and returns a hierarchy in which control groups
/// can be created. /// can be created.
pub fn new() -> V1 { pub fn new() -> V1 {
let mount_point = find_v1_mount().unwrap();
V1 { V1 {
mount_point: mount_point, mountinfo: mountinfo_self().unwrap(),
} }
} }
pub fn get_mount_point(&self, controller: Controllers) -> Option<PathBuf> {
self.mountinfo.iter().find_map(|m| {
if m.fs_type.0 == "cgroup" && m.super_opts.contains(&controller.to_string()) {
return Some(m.mount_point.clone());
}
None
})
}
} }
impl V2 { impl V2 {
@@ -220,7 +212,9 @@ pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup";
#[cfg(all(target_os = "linux", not(target_env = "musl")))] #[cfg(all(target_os = "linux", not(target_env = "musl")))]
pub fn is_cgroup2_unified_mode() -> bool { pub fn is_cgroup2_unified_mode() -> bool {
let path = Path::new(UNIFIED_MOUNTPOINT); use nix::sys::statfs;
let path = std::path::Path::new(UNIFIED_MOUNTPOINT);
let fs_stat = statfs::statfs(path); let fs_stat = statfs::statfs(path);
if fs_stat.is_err() { if fs_stat.is_err() {
return false; return false;
@@ -259,40 +253,3 @@ pub fn auto() -> Box<dyn Hierarchy> {
Box::new(V1::new()) Box::new(V1::new())
} }
} }
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 more_fields = line[index + 3..].split_whitespace().collect::<Vec<_>>();
if more_fields.len() == 0 {
continue;
}
if more_fields[0] == "cgroup" {
if more_fields.len() < 3 {
continue;
}
let cgroups_mount = fields.nth(4).unwrap();
if let Some(parent) = std::path::Path::new(cgroups_mount).parent() {
if let Some(path) = parent.as_os_str().to_str() {
debug!("found cgroups {:?} from {:?}", path, cgroups_mount);
return Some(path.to_string());
}
}
continue;
}
}
None
}

View File

@@ -54,14 +54,13 @@ impl ControllerInternal for HugeTlbController {
// get the resources that apply to this controller // get the resources that apply to this controller
let res: &HugePageResources = &res.hugepages; let res: &HugePageResources = &res.hugepages;
if res.update_values { for i in &res.limits {
for i in &res.limits { let _ = self.set_limit_in_bytes(&i.size, i.limit);
let _ = self.set_limit_in_bytes(&i.size, i.limit); if self.limit_in_bytes(&i.size)? != i.limit {
if self.limit_in_bytes(&i.size)? != i.limit { return Err(Error::new(Other));
return Err(Error::new(Other));
}
} }
} }
Ok(()) Ok(())
} }
} }
@@ -79,7 +78,8 @@ impl<'a> From<&'a Subsystem> for &'a HugeTlbController {
Subsystem::HugeTlb(c) => c, Subsystem::HugeTlb(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -98,12 +98,8 @@ fn read_u64_from(mut file: File) -> Result<u64> {
} }
impl HugeTlbController { impl HugeTlbController {
/// Constructs a new `HugeTlbController` with `oroot` serving as the root of the control group. /// Constructs a new `HugeTlbController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf, v2: bool) -> Self { pub fn new(root: PathBuf, v2: bool) -> Self {
let mut root = oroot;
if !v2 {
root.push(Self::controller_type().to_string());
}
let sizes = get_hugepage_sizes().unwrap(); let sizes = get_hugepage_sizes().unwrap();
Self { Self {
base: root.clone(), base: root.clone(),
@@ -225,10 +221,15 @@ pub const GB: u128 = 1000 * MB;
pub const TB: u128 = 1000 * GB; pub const TB: u128 = 1000 * GB;
pub const PB: u128 = 1000 * TB; pub const PB: u128 = 1000 * TB;
#[allow(non_upper_case_globals)]
pub const KiB: u128 = 1024; pub const KiB: u128 = 1024;
#[allow(non_upper_case_globals)]
pub const MiB: u128 = 1024 * KiB; pub const MiB: u128 = 1024 * KiB;
#[allow(non_upper_case_globals)]
pub const GiB: u128 = 1024 * MiB; pub const GiB: u128 = 1024 * MiB;
#[allow(non_upper_case_globals)]
pub const TiB: u128 = 1024 * GiB; pub const TiB: u128 = 1024 * GiB;
#[allow(non_upper_case_globals)]
pub const PiB: u128 = 1024 * TiB; pub const PiB: u128 = 1024 * TiB;
pub fn get_binary_size_map() -> HashMap<String, u128> { pub fn get_binary_size_map() -> HashMap<String, u128> {

View File

@@ -7,10 +7,29 @@
use log::*; use log::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::{self, File};
use std::io::{BufRead, BufReader, Read, Write}; use std::io::{BufRead, BufReader, Read, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
macro_rules! update_and_test {
($self: ident, $set_func:ident, $value:expr, $get_func:ident) => {
if let Some(v) = $value {
$self.$set_func(v)?;
if $self.$get_func()? != v {
return Err(Error::new(Other));
}
}
};
}
macro_rules! update {
($self: ident, $set_func:ident, $value:expr) => {
if let Some(v) = $value {
let _ = $self.$set_func(v);
}
};
}
pub mod blkio; pub mod blkio;
pub mod cgroup; pub mod cgroup;
pub mod cgroup_builder; pub mod cgroup_builder;
@@ -48,10 +67,11 @@ use crate::pid::PidController;
use crate::rdma::RdmaController; use crate::rdma::RdmaController;
use crate::systemd::SystemdController; use crate::systemd::SystemdController;
#[doc(inline)]
pub use crate::cgroup::Cgroup; pub use crate::cgroup::Cgroup;
/// Contains all the subsystems that are available in this crate. /// Contains all the subsystems that are available in this crate.
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum Subsystem { pub enum Subsystem {
/// Controller for the `Pid` subsystem, see `PidController` for more information. /// Controller for the `Pid` subsystem, see `PidController` for more information.
Pid(PidController), Pid(PidController),
@@ -84,7 +104,7 @@ pub enum Subsystem {
} }
#[doc(hidden)] #[doc(hidden)]
#[derive(Eq, PartialEq, Debug)] #[derive(Eq, PartialEq, Debug, Clone)]
pub enum Controllers { pub enum Controllers {
Pids, Pids,
Mem, Mem,
@@ -118,7 +138,7 @@ impl Controllers {
Controllers::NetPrio => return "net_prio".to_string(), Controllers::NetPrio => return "net_prio".to_string(),
Controllers::HugeTlb => return "hugetlb".to_string(), Controllers::HugeTlb => return "hugetlb".to_string(),
Controllers::Rdma => return "rdma".to_string(), Controllers::Rdma => return "rdma".to_string(),
Controllers::Systemd => return "systemd".to_string(), Controllers::Systemd => return "name=systemd".to_string(),
} }
} }
} }
@@ -189,9 +209,28 @@ mod sealed {
std::path::Path::new(p).exists() std::path::Path::new(p).exists()
} }
} }
pub trait CustomizedAttribute: ControllerInternal {
fn set(&self, key: &str, value: &str) -> Result<()> {
self.open_path(key, true).and_then(|mut file| {
file.write_all(value.as_ref())
.map_err(|e| Error::with_cause(WriteFailed, e))
})
}
fn get(&self, key: &str) -> Result<String> {
self.open_path(key, false).and_then(|mut file: File| {
let mut string = String::new();
match file.read_to_string(&mut string) {
Ok(_) => Ok(string.trim().to_owned()),
Err(e) => Err(Error::with_cause(ReadFailed, e)),
}
})
}
}
} }
pub(crate) use crate::sealed::ControllerInternal; pub(crate) use crate::sealed::{ControllerInternal, CustomizedAttribute};
/// A Controller is a subsystem attached to the control group. /// A Controller is a subsystem attached to the control group.
/// ///
@@ -213,12 +252,21 @@ pub trait Controller {
/// Does this controller already exist? /// Does this controller already exist?
fn exists(&self) -> bool; fn exists(&self) -> bool;
/// Set notify_on_release
fn set_notify_on_release(&self, enable: bool) -> Result<()>;
/// Set release_agent
fn set_release_agent(&self, path: &str) -> Result<()>;
/// Delete the controller. /// Delete the controller.
fn delete(&self); fn delete(&self) -> Result<()>;
/// Attach a task to this controller. /// Attach a task to this controller.
fn add_task(&self, pid: &CgroupPid) -> Result<()>; fn add_task(&self, pid: &CgroupPid) -> Result<()>;
/// Attach a task to this controller.
fn add_task_by_tgid(&self, pid: &CgroupPid) -> Result<()>;
/// Get the list of tasks that this controller has. /// Get the list of tasks that this controller has.
fn tasks(&self) -> Vec<CgroupPid>; fn tasks(&self) -> Vec<CgroupPid>;
@@ -250,20 +298,38 @@ where
match ::std::fs::create_dir_all(self.get_path()) { match ::std::fs::create_dir_all(self.get_path()) {
Ok(_) => self.post_create(), Ok(_) => self.post_create(),
Err(e) => warn!("error create_dir {:?}", e), Err(e) => warn!("error create_dir: {:?} error: {:?}", self.get_path(), e),
} }
} }
/// Set notify_on_release
fn set_notify_on_release(&self, enable: bool) -> Result<()> {
self.open_path("notify_on_release", true)
.and_then(|mut file| {
write!(file, "{}", enable as i32)
.map_err(|e| Error::with_cause(ErrorKind::WriteFailed, e))
})
}
/// Set release_agent
fn set_release_agent(&self, path: &str) -> Result<()> {
self.open_path("release_agent", true).and_then(|mut file| {
file.write_all(path.as_bytes())
.map_err(|e| Error::with_cause(ErrorKind::WriteFailed, e))
})
}
/// Does this controller already exist? /// Does this controller already exist?
fn exists(&self) -> bool { fn exists(&self) -> bool {
self.get_path().exists() self.get_path().exists()
} }
/// Delete the controller. /// Delete the controller.
fn delete(&self) { fn delete(&self) -> Result<()> {
if self.get_path().exists() { if !self.get_path().exists() {
libc_rmdir(self.get_path().to_str().unwrap()); return Ok(());
} }
fs::remove_dir(self.get_path()).map_err(|e| Error::with_cause(ErrorKind::RemoveFailed, e))
} }
/// Attach a task to this controller. /// Attach a task to this controller.
@@ -278,6 +344,14 @@ where
}) })
} }
/// Attach a task to this controller by thread group id.
fn add_task_by_tgid(&self, pid: &CgroupPid) -> Result<()> {
self.open_path("cgroup.procs", true).and_then(|mut file| {
file.write_all(pid.pid.to_string().as_ref())
.map_err(|e| Error::with_cause(ErrorKind::WriteFailed, e))
})
}
/// Get the list of tasks that this controller has. /// Get the list of tasks that this controller has.
fn tasks(&self) -> Vec<CgroupPid> { fn tasks(&self) -> Vec<CgroupPid> {
let mut file = "tasks"; let mut file = "tasks";
@@ -311,7 +385,7 @@ pub trait ControllIdentifier {
/// Control group hierarchy (right now, only V1 is supported, but in the future Unified will be /// Control group hierarchy (right now, only V1 is supported, but in the future Unified will be
/// implemented as well). /// implemented as well).
pub trait Hierarchy { pub trait Hierarchy: std::fmt::Debug + Send {
/// Returns what subsystems are supported by the hierarchy. /// Returns what subsystems are supported by the hierarchy.
fn subsystems(&self) -> Vec<Subsystem>; fn subsystems(&self) -> Vec<Subsystem>;
@@ -322,75 +396,79 @@ pub trait Hierarchy {
fn root_control_group(&self) -> Cgroup; fn root_control_group(&self) -> Cgroup;
fn v2(&self) -> bool; fn v2(&self) -> bool;
/// Checks whether a certain subsystem is supported in the hierarchy.
///
/// This is an internal function and should not be used.
#[doc(hidden)]
fn check_support(&self, sub: Controllers) -> bool;
} }
/// Resource limits for the memory subsystem. /// Resource limits for the memory subsystem.
#[derive(Debug, Clone, Eq, PartialEq, Default)] #[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct MemoryResources { pub struct MemoryResources {
/// Whether values should be applied to the controller.
pub update_values: bool,
/// How much memory (in bytes) can the kernel consume. /// How much memory (in bytes) can the kernel consume.
pub kernel_memory_limit: i64, pub kernel_memory_limit: Option<i64>,
/// Upper limit of memory usage of the control group's tasks. /// Upper limit of memory usage of the control group's tasks.
pub memory_hard_limit: i64, pub memory_hard_limit: Option<i64>,
/// How much memory the tasks in the control group can use when the system is under memory /// How much memory the tasks in the control group can use when the system is under memory
/// pressure. /// pressure.
pub memory_soft_limit: i64, pub memory_soft_limit: Option<i64>,
/// How much of the kernel's memory (in bytes) can be used for TCP-related buffers. /// How much of the kernel's memory (in bytes) can be used for TCP-related buffers.
pub kernel_tcp_memory_limit: i64, pub kernel_tcp_memory_limit: Option<i64>,
/// How much memory and swap together can the tasks in the control group use. /// How much memory and swap together can the tasks in the control group use.
pub memory_swap_limit: i64, pub memory_swap_limit: Option<i64>,
/// Controls the tendency of the kernel to swap out parts of the address space of the tasks to /// Controls the tendency of the kernel to swap out parts of the address space of the tasks to
/// disk. Lower value implies less likely. /// disk. Lower value implies less likely.
/// ///
/// Note, however, that a value of zero does not mean the process is never swapped out. Use the /// Note, however, that a value of zero does not mean the process is never swapped out. Use the
/// traditional `mlock(2)` system call for that purpose. /// traditional `mlock(2)` system call for that purpose.
pub swappiness: u64, pub swappiness: Option<u64>,
/// Customized key-value attributes
///
/// # Usage:
/// ```
/// let resource = &mut cgroups::Resources::default();
/// resource.memory.attrs.insert("memory.numa_balancing", "true".to_string());
/// // apply here
pub attrs: std::collections::HashMap<&'static str, String>,
} }
/// Resources limits on the number of processes. /// Resources limits on the number of processes.
#[derive(Debug, Clone, Eq, PartialEq, Default)] #[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct PidResources { pub struct PidResources {
/// Whether values should be applied to the controller.
pub update_values: bool,
/// The maximum number of processes that can exist in the control group. /// The maximum number of processes that can exist in the control group.
/// ///
/// Note that attaching processes to the control group will still succeed _even_ if the limit /// Note that attaching processes to the control group will still succeed _even_ if the limit
/// would be violated, however forks/clones inside the control group will have with `EAGAIN` if /// would be violated, however forks/clones inside the control group will have with `EAGAIN` if
/// they would violate the limit set here. /// they would violate the limit set here.
pub maximum_number_of_processes: MaxValue, pub maximum_number_of_processes: Option<MaxValue>,
} }
/// Resources limits about how the tasks can use the CPU. /// Resources limits about how the tasks can use the CPU.
#[derive(Debug, Clone, Eq, PartialEq, Default)] #[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct CpuResources { pub struct CpuResources {
/// Whether values should be applied to the controller.
pub update_values: bool,
// cpuset // cpuset
/// A comma-separated list of CPU IDs where the task in the control group can run. Dashes /// A comma-separated list of CPU IDs where the task in the control group can run. Dashes
/// between numbers indicate ranges. /// between numbers indicate ranges.
pub cpus: Option<String>, pub cpus: Option<String>,
/// Same syntax as the `cpus` field of this structure, but applies to memory nodes instead of /// Same syntax as the `cpus` field of this structure, but applies to memory nodes instead of
/// processors. /// processors.
pub mems: String, pub mems: Option<String>,
// cpu // cpu
/// Weight of how much of the total CPU time should this control group get. Note that this is /// Weight of how much of the total CPU time should this control group get. Note that this is
/// hierarchical, so this is weighted against the siblings of this control group. /// hierarchical, so this is weighted against the siblings of this control group.
pub shares: u64, pub shares: Option<u64>,
/// In one `period`, how much can the tasks run in nanoseconds. /// In one `period`, how much can the tasks run in nanoseconds.
pub quota: i64, pub quota: Option<i64>,
/// Period of time in nanoseconds. /// Period of time in nanoseconds.
pub period: u64, pub period: Option<u64>,
/// This is currently a no-operation. /// This is currently a no-operation.
pub realtime_runtime: i64, pub realtime_runtime: Option<i64>,
/// This is currently a no-operation. /// This is currently a no-operation.
pub realtime_period: u64, pub realtime_period: Option<u64>,
/// Customized key-value attributes
/// # Usage:
/// ```
/// let resource = &mut cgroups::Resources::default();
/// resource.cpu.attrs.insert("cpu.cfs_init_buffer_us", "10".to_string());
/// // apply here
/// ```
pub attrs: std::collections::HashMap<&'static str, String>,
} }
/// A device resource that can be allowed or denied access to. /// A device resource that can be allowed or denied access to.
@@ -411,8 +489,6 @@ pub struct DeviceResource {
/// Limit the usage of devices for the control group's tasks. /// Limit the usage of devices for the control group's tasks.
#[derive(Debug, Clone, Eq, PartialEq, Default)] #[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct DeviceResources { pub struct DeviceResources {
/// Whether values should be applied to the controller.
pub update_values: bool,
/// For each device in the list, the limits in the structure are applied. /// For each device in the list, the limits in the structure are applied.
pub devices: Vec<DeviceResource>, pub devices: Vec<DeviceResource>,
} }
@@ -430,12 +506,10 @@ pub struct NetworkPriority {
/// control group. /// control group.
#[derive(Debug, Clone, Eq, PartialEq, Default)] #[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct NetworkResources { pub struct NetworkResources {
/// Whether values should be applied to the controller.
pub update_values: bool,
/// The networking class identifier to attach to the packets. /// The networking class identifier to attach to the packets.
/// ///
/// This can then later be used in iptables and such to have special rules. /// This can then later be used in iptables and such to have special rules.
pub class_id: u64, pub class_id: Option<u64>,
/// Priority of the egress traffic for each interface. /// Priority of the egress traffic for each interface.
pub priorities: Vec<NetworkPriority>, pub priorities: Vec<NetworkPriority>,
} }
@@ -453,8 +527,6 @@ pub struct HugePageResource {
/// Provides the ability to set consumption limit on each type of hugepages. /// Provides the ability to set consumption limit on each type of hugepages.
#[derive(Debug, Clone, Eq, PartialEq, Default)] #[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct HugePageResources { pub struct HugePageResources {
/// Whether values should be applied to the controller.
pub update_values: bool,
/// Set a limit of consumption for each hugepages type. /// Set a limit of consumption for each hugepages type.
pub limits: Vec<HugePageResource>, pub limits: Vec<HugePageResource>,
} }
@@ -486,8 +558,6 @@ pub struct BlkIoDeviceThrottleResource {
/// General block I/O resource limits. /// General block I/O resource limits.
#[derive(Debug, Clone, Eq, PartialEq, Default)] #[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct BlkIoResources { pub struct BlkIoResources {
/// Whether values should be applied to the controller.
pub update_values: bool,
/// The weight of the control group against descendant nodes. /// The weight of the control group against descendant nodes.
pub weight: Option<u16>, pub weight: Option<u16>,
/// The weight of the control group against sibling nodes. /// The weight of the control group against sibling nodes.
@@ -619,7 +689,7 @@ impl Subsystem {
} }
} }
fn to_controller(&self) -> &dyn Controller { pub fn to_controller(&self) -> &dyn Controller {
match self { match self {
Subsystem::Pid(cont) => cont, Subsystem::Pid(cont) => cont,
Subsystem::Mem(cont) => cont, Subsystem::Mem(cont) => cont,
@@ -638,7 +708,7 @@ impl Subsystem {
} }
} }
fn controller_name(&self) -> String { pub fn controller_name(&self) -> String {
self.to_controller().control_type().to_string() self.to_controller().control_type().to_string()
} }
} }
@@ -762,15 +832,8 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result<HashMap<String, HashMap
Ok(h) Ok(h)
} }
/// fs::remove_dir_all or fs::remove_dir can't work with cgroup directory sometimes.
/// 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) };
}
/// read and parse an i64 data /// read and parse an i64 data
pub fn read_i64_from(mut file: File) -> Result<i64> { fn read_i64_from(mut file: File) -> Result<i64> {
let mut string = String::new(); let mut string = String::new();
match file.read_to_string(&mut string) { match file.read_to_string(&mut string) {
Ok(_) => string Ok(_) => string

View File

@@ -17,12 +17,13 @@ use std::sync::mpsc::Receiver;
use crate::error::ErrorKind::*; use crate::error::ErrorKind::*;
use crate::error::*; use crate::error::*;
use crate::events; use crate::events;
use crate::read_i64_from;
use crate::flat_keyed_to_hashmap; use crate::flat_keyed_to_hashmap;
use crate::{ use crate::{
ControllIdentifier, ControllerInternal, Controllers, MaxValue, MemoryResources, Resources, ControllIdentifier, ControllerInternal, Controllers, CustomizedAttribute, MaxValue,
Subsystem, MemoryResources, Resources, Subsystem,
}; };
/// A controller that allows controlling the `memory` subsystem of a Cgroup. /// A controller that allows controlling the `memory` subsystem of a Cgroup.
@@ -453,26 +454,20 @@ impl ControllerInternal for MemController {
// get the resources that apply to this controller // get the resources that apply to this controller
let memres: &MemoryResources = &res.memory; let memres: &MemoryResources = &res.memory;
if memres.update_values { update!(self, set_limit, memres.memory_hard_limit);
let _ = self.set_limit(memres.memory_hard_limit); update!(self, set_soft_limit, memres.memory_soft_limit);
let _ = self.set_soft_limit(memres.memory_soft_limit); update!(self, set_kmem_limit, memres.kernel_memory_limit);
let _ = self.set_kmem_limit(memres.kernel_memory_limit); update!(self, set_memswap_limit, memres.memory_swap_limit);
let _ = self.set_memswap_limit(memres.memory_swap_limit); update!(self, set_tcp_limit, memres.kernel_tcp_memory_limit);
let _ = self.set_tcp_limit(memres.kernel_tcp_memory_limit); update!(self, set_swappiness, memres.swappiness);
let _ = self.set_swappiness(memres.swappiness);
}
Ok(()) Ok(())
} }
} }
impl MemController { impl MemController {
/// Contructs a new `MemController` with `oroot` serving as the root of the control group. /// Contructs a new `MemController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf, v2: bool) -> Self { pub fn new(root: PathBuf, v2: bool) -> Self {
let mut root = oroot;
if !v2 {
root.push(Self::controller_type().to_string());
}
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,
@@ -505,10 +500,11 @@ impl MemController {
// for v2 // for v2
pub fn get_mem(&self) -> Result<SetMemory> { pub fn get_mem(&self) -> Result<SetMemory> {
let mut m: SetMemory = Default::default(); let mut m: SetMemory = Default::default();
self.get_max_value("memory.high").map(|x| m.high = Some(x)); self.get_max_value("memory.high")
self.get_max_value("memory.low").map(|x| m.low = Some(x)); .map(|x| m.high = Some(x))?;
self.get_max_value("memory.max").map(|x| m.max = Some(x)); self.get_max_value("memory.low").map(|x| m.low = Some(x))?;
self.get_max_value("memory.min").map(|x| m.min = Some(x)); self.get_max_value("memory.max").map(|x| m.max = Some(x))?;
self.get_max_value("memory.min").map(|x| m.min = Some(x))?;
Ok(m) Ok(m)
} }
@@ -707,6 +703,11 @@ impl MemController {
/// Reset the kernel memory fail counter /// Reset the kernel memory fail counter
pub fn reset_kmem_fail_count(&self) -> Result<()> { pub fn reset_kmem_fail_count(&self) -> Result<()> {
// Ignore kmem because there is no kmem in cgroup v2
if self.v2 {
return Ok(());
}
self.open_path("memory.kmem.failcnt", true) self.open_path("memory.kmem.failcnt", true)
.and_then(|mut file| { .and_then(|mut file| {
file.write_all("0".to_string().as_ref()) file.write_all("0".to_string().as_ref())
@@ -716,6 +717,11 @@ impl MemController {
/// Reset the TCP related fail counter /// Reset the TCP related fail counter
pub fn reset_tcp_fail_count(&self) -> Result<()> { pub fn reset_tcp_fail_count(&self) -> Result<()> {
// Ignore kmem because there is no kmem in cgroup v2
if self.v2 {
return Ok(());
}
self.open_path("memory.kmem.tcp.failcnt", true) self.open_path("memory.kmem.tcp.failcnt", true)
.and_then(|mut file| { .and_then(|mut file| {
file.write_all("0".to_string().as_ref()) file.write_all("0".to_string().as_ref())
@@ -732,6 +738,15 @@ impl MemController {
}) })
} }
/// Reset the max memory usage recorded
pub fn reset_max_usage(&self) -> Result<()> {
self.open_path("memory.max_usage_in_bytes", true)
.and_then(|mut file| {
file.write_all("0".to_string().as_ref())
.map_err(|e| Error::with_cause(WriteFailed, e))
})
}
/// Set the memory usage limit of the control group, in bytes. /// Set the memory usage limit of the control group, in bytes.
pub fn set_limit(&self, limit: i64) -> Result<()> { pub fn set_limit(&self, limit: i64) -> Result<()> {
let mut file = "memory.limit_in_bytes"; let mut file = "memory.limit_in_bytes";
@@ -746,6 +761,11 @@ impl MemController {
/// Set the kernel memory limit of the control group, in bytes. /// Set the kernel memory limit of the control group, in bytes.
pub fn set_kmem_limit(&self, limit: i64) -> Result<()> { pub fn set_kmem_limit(&self, limit: i64) -> Result<()> {
// Ignore kmem because there is no kmem in cgroup v2
if self.v2 {
return Ok(());
}
self.open_path("memory.kmem.limit_in_bytes", true) self.open_path("memory.kmem.limit_in_bytes", true)
.and_then(|mut file| { .and_then(|mut file| {
file.write_all(limit.to_string().as_ref()) file.write_all(limit.to_string().as_ref())
@@ -767,6 +787,11 @@ impl MemController {
/// Set how much kernel memory can be used for TCP-related buffers by the control group. /// Set how much kernel memory can be used for TCP-related buffers by the control group.
pub fn set_tcp_limit(&self, limit: i64) -> Result<()> { pub fn set_tcp_limit(&self, limit: i64) -> Result<()> {
// Ignore kmem because there is no kmem in cgroup v2
if self.v2 {
return Ok(());
}
self.open_path("memory.kmem.tcp.limit_in_bytes", true) self.open_path("memory.kmem.tcp.limit_in_bytes", true)
.and_then(|mut file| { .and_then(|mut file| {
file.write_all(limit.to_string().as_ref()) file.write_all(limit.to_string().as_ref())
@@ -794,11 +819,15 @@ impl MemController {
/// ///
/// Note that a value of zero does not imply that the process will not be swapped out. /// Note that a value of zero does not imply that the process will not be swapped out.
pub fn set_swappiness(&self, swp: u64) -> Result<()> { pub fn set_swappiness(&self, swp: u64) -> Result<()> {
self.open_path("memory.swappiness", true) let mut file = "memory.swappiness";
.and_then(|mut file| { if self.v2 {
file.write_all(swp.to_string().as_ref()) file = "memory.swap.max"
.map_err(|e| Error::with_cause(WriteFailed, e)) }
})
self.open_path(file, true).and_then(|mut file| {
file.write_all(swp.to_string().as_ref())
.map_err(|e| Error::with_cause(WriteFailed, e))
})
} }
pub fn disable_oom_killer(&self) -> Result<()> { pub fn disable_oom_killer(&self) -> Result<()> {
@@ -824,6 +853,8 @@ impl ControllIdentifier for MemController {
} }
} }
impl CustomizedAttribute for MemController {}
impl<'a> From<&'a Subsystem> for &'a MemController { impl<'a> From<&'a Subsystem> for &'a MemController {
fn from(sub: &'a Subsystem) -> &'a MemController { fn from(sub: &'a Subsystem) -> &'a MemController {
unsafe { unsafe {
@@ -831,7 +862,8 @@ impl<'a> From<&'a Subsystem> for &'a MemController {
Subsystem::Mem(c) => c, Subsystem::Mem(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -849,17 +881,6 @@ fn read_u64_from(mut file: File) -> Result<u64> {
} }
} }
fn read_i64_from(mut file: File) -> Result<i64> {
let mut string = String::new();
match file.read_to_string(&mut string) {
Ok(_) => string
.trim()
.parse()
.map_err(|e| Error::with_cause(ParseError, e)),
Err(e) => Err(Error::with_cause(ReadFailed, e)),
}
}
fn read_string_from(mut file: File) -> Result<String> { fn read_string_from(mut file: File) -> Result<String> {
let mut string = String::new(); let mut string = String::new();
match file.read_to_string(&mut string) { match file.read_to_string(&mut string) {
@@ -873,8 +894,6 @@ mod tests {
use crate::memory::{ use crate::memory::{
parse_memory_stat, parse_numa_stat, parse_oom_control, MemoryStat, NumaStat, OomControl, parse_memory_stat, parse_numa_stat, parse_oom_control, MemoryStat, NumaStat, OomControl,
}; };
use std::collections::HashMap;
static GOOD_VALUE: &str = "\ static GOOD_VALUE: &str = "\
total=51189 N0=51189 N1=123 total=51189 N0=51189 N1=123
file=50175 N0=50175 N1=123 file=50175 N0=50175 N1=123

View File

@@ -47,12 +47,8 @@ impl ControllerInternal for NetClsController {
// get the resources that apply to this controller // get the resources that apply to this controller
let res: &NetworkResources = &res.network; let res: &NetworkResources = &res.network;
if res.update_values { update_and_test!(self, set_class, res.class_id, get_class);
let _ = self.set_class(res.class_id);
if self.get_class()? != res.class_id {
return Err(Error::new(Other));
}
}
return Ok(()); return Ok(());
} }
} }
@@ -70,7 +66,8 @@ impl<'a> From<&'a Subsystem> for &'a NetClsController {
Subsystem::NetCls(c) => c, Subsystem::NetCls(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -89,10 +86,8 @@ fn read_u64_from(mut file: File) -> Result<u64> {
} }
impl NetClsController { impl NetClsController {
/// Constructs a new `NetClsController` with `oroot` serving as the root of the control group. /// Constructs a new `NetClsController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf) -> Self { pub fn new(root: PathBuf) -> Self {
let mut root = oroot;
root.push(Self::controller_type().to_string());
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -48,10 +48,8 @@ impl ControllerInternal for NetPrioController {
// get the resources that apply to this controller // get the resources that apply to this controller
let res: &NetworkResources = &res.network; let res: &NetworkResources = &res.network;
if res.update_values { for i in &res.priorities {
for i in &res.priorities { let _ = self.set_if_prio(&i.name, i.priority);
let _ = self.set_if_prio(&i.name, i.priority);
}
} }
Ok(()) Ok(())
@@ -71,7 +69,8 @@ impl<'a> From<&'a Subsystem> for &'a NetPrioController {
Subsystem::NetPrio(c) => c, Subsystem::NetPrio(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -90,10 +89,8 @@ fn read_u64_from(mut file: File) -> Result<u64> {
} }
impl NetPrioController { impl NetPrioController {
/// Constructs a new `NetPrioController` with `oroot` serving as the root of the control group. /// Constructs a new `NetPrioController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf) -> Self { pub fn new(root: PathBuf) -> Self {
let mut root = oroot;
root.push(Self::controller_type().to_string());
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -55,7 +55,8 @@ impl<'a> From<&'a Subsystem> for &'a PerfEventController {
Subsystem::PerfEvent(c) => c, Subsystem::PerfEvent(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -63,10 +64,8 @@ impl<'a> From<&'a Subsystem> for &'a PerfEventController {
} }
impl PerfEventController { impl PerfEventController {
/// Constructs a new `PerfEventController` with `oroot` serving as the root of the control group. /// Constructs a new `PerfEventController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf) -> Self { pub fn new(root: PathBuf) -> Self {
let mut root = oroot;
root.push(Self::controller_type().to_string());
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -50,17 +50,13 @@ impl ControllerInternal for PidController {
// get the resources that apply to this controller // get the resources that apply to this controller
let pidres: &PidResources = &res.pid; let pidres: &PidResources = &res.pid;
if pidres.update_values { // apply pid_max
// apply pid_max update_and_test!(
let _ = self.set_pid_max(pidres.maximum_number_of_processes); self,
set_pid_max,
// now, verify pidres.maximum_number_of_processes,
if self.get_pid_max()? == pidres.maximum_number_of_processes { get_pid_max
return Ok(()); );
} else {
return Err(Error::new(Other));
}
}
Ok(()) Ok(())
} }
@@ -85,7 +81,8 @@ impl<'a> From<&'a Subsystem> for &'a PidController {
Subsystem::Pid(c) => c, Subsystem::Pid(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -104,13 +101,9 @@ fn read_u64_from(mut file: File) -> Result<u64> {
} }
impl PidController { impl PidController {
/// Constructors a new `PidController` instance, with `oroot` serving as the controller's root /// Constructors a new `PidController` instance, with `root` serving as the controller's root
/// directory. /// directory.
pub fn new(oroot: PathBuf, v2: bool) -> Self { pub fn new(root: PathBuf, v2: bool) -> Self {
let mut root = oroot;
if !v2 {
root.push(Self::controller_type().to_string());
}
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -58,7 +58,8 @@ impl<'a> From<&'a Subsystem> for &'a RdmaController {
Subsystem::Rdma(c) => c, Subsystem::Rdma(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -74,10 +75,8 @@ fn read_string_from(mut file: File) -> Result<String> {
} }
impl RdmaController { impl RdmaController {
/// Constructs a new `RdmaController` with `oroot` serving as the root of the control group. /// Constructs a new `RdmaController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf) -> Self { pub fn new(root: PathBuf) -> Self {
let mut root = oroot;
root.push(Self::controller_type().to_string());
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -7,7 +7,6 @@
//! //!
use std::path::PathBuf; use std::path::PathBuf;
use crate::error::ErrorKind::*;
use crate::error::*; use crate::error::*;
use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem}; use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
@@ -53,7 +52,8 @@ impl<'a> From<&'a Subsystem> for &'a SystemdController {
Subsystem::Systemd(c) => c, Subsystem::Systemd(c) => c,
_ => { _ => {
assert_eq!(1, 0); assert_eq!(1, 0);
::std::mem::uninitialized() let v = std::mem::MaybeUninit::uninit();
v.assume_init()
} }
} }
} }
@@ -61,12 +61,8 @@ impl<'a> From<&'a Subsystem> for &'a SystemdController {
} }
impl SystemdController { impl SystemdController {
/// Constructs a new `SystemdController` with `oroot` serving as the root of the control group. /// Constructs a new `SystemdController` with `root` serving as the root of the control group.
pub fn new(oroot: PathBuf, v2: bool) -> Self { pub fn new(root: PathBuf, v2: bool) -> Self {
let mut root = oroot;
if !v2 {
root.push(Self::controller_type().to_string());
}
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,

View File

@@ -18,12 +18,11 @@ use cgroups::*;
#[test] #[test]
pub fn test_cpu_res_build() { pub fn test_cpu_res_build() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_cpu_res_build")
let cg: Cgroup = CgroupBuilder::new("test_cpu_res_build", h)
.cpu() .cpu()
.shares(85) .shares(85)
.done() .done()
.build(); .build(h);
{ {
let cpu: &CpuController = cg.controller_of().unwrap(); let cpu: &CpuController = cg.controller_of().unwrap();
@@ -31,20 +30,19 @@ pub fn test_cpu_res_build() {
assert_eq!(cpu.shares().unwrap(), 85); assert_eq!(cpu.shares().unwrap(), 85);
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
pub fn test_memory_res_build() { pub fn test_memory_res_build() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_memory_res_build")
let cg: Cgroup = CgroupBuilder::new("test_memory_res_build", h)
.memory() .memory()
.kernel_memory_limit(128 * 1024 * 1024) .kernel_memory_limit(128 * 1024 * 1024)
.swappiness(70) .swappiness(70)
.memory_hard_limit(1024 * 1024 * 1024) .memory_hard_limit(1024 * 1024 * 1024)
.done() .done()
.build(); .build(h);
{ {
let c: &MemController = cg.controller_of().unwrap(); let c: &MemController = cg.controller_of().unwrap();
@@ -55,18 +53,17 @@ pub fn test_memory_res_build() {
assert_eq!(c.memory_stat().limit_in_bytes, 1024 * 1024 * 1024); assert_eq!(c.memory_stat().limit_in_bytes, 1024 * 1024 * 1024);
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
pub fn test_pid_res_build() { pub fn test_pid_res_build() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_pid_res_build")
let cg: Cgroup = CgroupBuilder::new("test_pid_res_build", h)
.pid() .pid()
.maximum_number_of_processes(MaxValue::Value(123)) .maximum_number_of_processes(MaxValue::Value(123))
.done() .done()
.build(); .build(h);
{ {
let c: &PidController = cg.controller_of().unwrap(); let c: &PidController = cg.controller_of().unwrap();
@@ -74,19 +71,18 @@ pub fn test_pid_res_build() {
assert_eq!(c.get_pid_max().unwrap(), MaxValue::Value(123)); assert_eq!(c.get_pid_max().unwrap(), MaxValue::Value(123));
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
#[ignore] // ignore this test for now, not sure why my kernel doesn't like it #[ignore] // ignore this test for now, not sure why my kernel doesn't like it
pub fn test_devices_res_build() { pub fn test_devices_res_build() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_devices_res_build")
let cg: Cgroup = CgroupBuilder::new("test_devices_res_build", h)
.devices() .devices()
.device(1, 6, DeviceType::Char, true, vec![DevicePermissions::Read]) .device(1, 6, DeviceType::Char, true, vec![DevicePermissions::Read])
.done() .done()
.build(); .build(h);
{ {
let c: &DevicesController = cg.controller_of().unwrap(); let c: &DevicesController = cg.controller_of().unwrap();
@@ -102,7 +98,7 @@ pub fn test_devices_res_build() {
}] }]
); );
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
@@ -112,19 +108,18 @@ pub fn test_network_res_build() {
// FIXME add cases for v2 // FIXME add cases for v2
return; return;
} }
let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_network_res_build")
let cg: Cgroup = CgroupBuilder::new("test_network_res_build", h)
.network() .network()
.class_id(1337) .class_id(1337)
.done() .done()
.build(); .build(h);
{ {
let c: &NetClsController = cg.controller_of().unwrap(); let c: &NetClsController = cg.controller_of().unwrap();
assert!(c.get_class().is_ok()); assert!(c.get_class().is_ok());
assert_eq!(c.get_class().unwrap(), 1337); assert_eq!(c.get_class().unwrap(), 1337);
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
@@ -134,12 +129,11 @@ pub fn test_hugepages_res_build() {
// FIXME add cases for v2 // FIXME add cases for v2
return; return;
} }
let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_hugepages_res_build")
let cg: Cgroup = CgroupBuilder::new("test_hugepages_res_build", h)
.hugepages() .hugepages()
.limit("2MB".to_string(), 4 * 2 * 1024 * 1024) .limit("2MB".to_string(), 4 * 2 * 1024 * 1024)
.done() .done()
.build(); .build(h);
{ {
let c: &HugeTlbController = cg.controller_of().unwrap(); let c: &HugeTlbController = cg.controller_of().unwrap();
@@ -149,23 +143,22 @@ pub fn test_hugepages_res_build() {
4 * 2 * 1024 * 1024 4 * 2 * 1024 * 1024
); );
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
#[ignore] // high version kernel not support `blkio.weight` #[ignore] // high version kernel not support `blkio.weight`
pub fn test_blkio_res_build() { pub fn test_blkio_res_build() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h); let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build")
let cg: Cgroup = CgroupBuilder::new("test_blkio_res_build", h)
.blkio() .blkio()
.weight(Some(100)) .weight(100)
.done() .done()
.build(); .build(h);
{ {
let c: &BlkIoController = cg.controller_of().unwrap(); let c: &BlkIoController = cg.controller_of().unwrap();
assert_eq!(c.blkio().weight, 100); assert_eq!(c.blkio().weight, 100);
} }
cg.delete(); cg.delete().unwrap();
} }

View File

@@ -5,15 +5,13 @@
// //
//! Simple unit tests about the control groups system. //! Simple unit tests about the control groups system.
use cgroups::memory::{MemController, SetMemory}; use cgroups::memory::MemController;
use cgroups::Controller; use cgroups::Controller;
use cgroups::{Cgroup, CgroupPid, Hierarchy, Subsystem}; use cgroups::{Cgroup, CgroupPid, Subsystem};
use std::collections::HashMap;
#[test] #[test]
fn test_tasks_iterator() { fn test_tasks_iterator() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let pid = libc::pid_t::from(nix::unistd::getpid()) as u64; let pid = libc::pid_t::from(nix::unistd::getpid()) as u64;
let cg = Cgroup::new(h, String::from("test_tasks_iterator")); let cg = Cgroup::new(h, String::from("test_tasks_iterator"));
{ {
@@ -35,7 +33,7 @@ fn test_tasks_iterator() {
// Verify that it was indeed removed. // Verify that it was indeed removed.
assert_eq!(tasks.next(), None); assert_eq!(tasks.next(), None);
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
@@ -45,13 +43,9 @@ fn test_cgroup_with_relative_paths() {
} }
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let cgroup_root = h.root(); let cgroup_root = h.root();
let h = Box::new(&*h);
let mut relative_paths = HashMap::new();
let mem_relative_path = "/mmm/abc/def";
relative_paths.insert("memory".to_string(), mem_relative_path.to_string());
let cgroup_name = "test_cgroup_with_relative_paths"; let cgroup_name = "test_cgroup_with_relative_paths";
let cg = Cgroup::new_with_relative_paths(h, String::from(cgroup_name), relative_paths); let cg = Cgroup::load(h, String::from(cgroup_name));
{ {
let subsystems = cg.subsystems(); let subsystems = cg.subsystems();
subsystems.into_iter().for_each(|sub| match sub { subsystems.into_iter().for_each(|sub| match sub {
@@ -74,18 +68,13 @@ fn test_cgroup_with_relative_paths() {
// cgroup_path = cgroup_root + relative_path + cgroup_name // cgroup_path = cgroup_root + relative_path + cgroup_name
assert_eq!( assert_eq!(
cgroup_path, cgroup_path,
format!( format!("{}/memory/{}", cgroup_root.to_str().unwrap(), cgroup_name)
"{}/memory{}/{}",
cgroup_root.to_str().unwrap(),
mem_relative_path,
cgroup_name
)
); );
} }
_ => {} _ => {}
}); });
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
@@ -94,15 +83,14 @@ fn test_cgroup_v2() {
return; return;
} }
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h); let cg = Cgroup::new(h, String::from("test_v2"));
let cg = Cgroup::new_with_relative_paths(h, String::from("test_v2"), HashMap::new());
let mem_controller: &MemController = cg.controller_of().unwrap(); 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); mem_controller.set_limit(mem).unwrap();
let _ = mem_controller.set_memswap_limit(swp); mem_controller.set_memswap_limit(swp).unwrap();
let _ = mem_controller.set_soft_limit(rev); mem_controller.set_soft_limit(rev).unwrap();
let memory_stat = mem_controller.memory_stat(); let memory_stat = mem_controller.memory_stat();
println!("memory_stat {:?}", memory_stat); println!("memory_stat {:?}", memory_stat);
@@ -113,5 +101,5 @@ fn test_cgroup_v2() {
println!("memswap {:?}", memswap); println!("memswap {:?}", memswap);
assert_eq!(swp, memswap.limit_in_bytes); assert_eq!(swp, memswap.limit_in_bytes);
cg.delete(); cg.delete().unwrap();
} }

View File

@@ -5,15 +5,11 @@
//! Simple unit tests about the CPU control groups system. //! Simple unit tests about the CPU control groups system.
use cgroups::cpu::CpuController; use cgroups::cpu::CpuController;
use cgroups::error::ErrorKind; use cgroups::Cgroup;
use cgroups::{Cgroup, CgroupPid, CpuResources, Hierarchy, Resources};
use std::fs;
#[test] #[test]
fn test_cfs_quota_and_periods() { fn test_cfs_quota_and_periods() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("test_cfs_quota_and_periods")); let cg = Cgroup::new(h, String::from("test_cfs_quota_and_periods"));
let cpu_controller: &CpuController = cg.controller_of().unwrap(); let cpu_controller: &CpuController = cg.controller_of().unwrap();
@@ -27,7 +23,7 @@ fn test_cfs_quota_and_periods() {
assert_eq!(100000, current_peroid); assert_eq!(100000, current_peroid);
// case 1 set quota // case 1 set quota
let r = cpu_controller.set_cfs_quota(2000); let _ = cpu_controller.set_cfs_quota(2000);
let current_quota = cpu_controller.cfs_quota().unwrap(); let current_quota = cpu_controller.cfs_quota().unwrap();
let current_peroid = cpu_controller.cfs_period().unwrap(); let current_peroid = cpu_controller.cfs_period().unwrap();
@@ -35,14 +31,16 @@ fn test_cfs_quota_and_periods() {
assert_eq!(100000, current_peroid); assert_eq!(100000, current_peroid);
// case 2 set period // case 2 set period
cpu_controller.set_cfs_period(1000000); cpu_controller.set_cfs_period(1000000).unwrap();
let current_quota = cpu_controller.cfs_quota().unwrap(); let current_quota = cpu_controller.cfs_quota().unwrap();
let current_peroid = cpu_controller.cfs_period().unwrap(); let current_peroid = cpu_controller.cfs_period().unwrap();
assert_eq!(2000, current_quota); assert_eq!(2000, current_quota);
assert_eq!(1000000, current_peroid); assert_eq!(1000000, current_peroid);
// case 3 set both quota and period // case 3 set both quota and period
cpu_controller.set_cfs_quota_and_period(Some(5000), Some(100000)); cpu_controller
.set_cfs_quota_and_period(Some(5000), Some(100000))
.unwrap();
let current_quota = cpu_controller.cfs_quota().unwrap(); let current_quota = cpu_controller.cfs_quota().unwrap();
let current_peroid = cpu_controller.cfs_period().unwrap(); let current_peroid = cpu_controller.cfs_period().unwrap();
@@ -50,12 +48,14 @@ fn test_cfs_quota_and_periods() {
assert_eq!(100000, current_peroid); assert_eq!(100000, current_peroid);
// case 4 set both quota and period, set quota to -1 // case 4 set both quota and period, set quota to -1
cpu_controller.set_cfs_quota_and_period(Some(-1), None); cpu_controller
.set_cfs_quota_and_period(Some(-1), None)
.unwrap();
let current_quota = cpu_controller.cfs_quota().unwrap(); let current_quota = cpu_controller.cfs_quota().unwrap();
let current_peroid = cpu_controller.cfs_period().unwrap(); let current_peroid = cpu_controller.cfs_period().unwrap();
assert_eq!(-1, current_quota); assert_eq!(-1, current_quota);
assert_eq!(100000, current_peroid); assert_eq!(100000, current_peroid);
cg.delete(); cg.delete().unwrap();
} }

View File

@@ -6,14 +6,13 @@
use cgroups::cpuset::CpuSetController; use cgroups::cpuset::CpuSetController;
use cgroups::error::ErrorKind; use cgroups::error::ErrorKind;
use cgroups::{Cgroup, CgroupPid, CpuResources, Hierarchy, Resources}; use cgroups::{Cgroup, CgroupPid};
use std::fs; use std::fs;
#[test] #[test]
fn test_cpuset_memory_pressure_root_cg() { fn test_cpuset_memory_pressure_root_cg() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("test_cpuset_memory_pressure_root_cg")); let cg = Cgroup::new(h, String::from("test_cpuset_memory_pressure_root_cg"));
{ {
let cpuset: &CpuSetController = cg.controller_of().unwrap(); let cpuset: &CpuSetController = cg.controller_of().unwrap();
@@ -22,13 +21,12 @@ fn test_cpuset_memory_pressure_root_cg() {
let res = cpuset.set_enable_memory_pressure(true); let res = cpuset.set_enable_memory_pressure(true);
assert_eq!(res.unwrap_err().kind(), &ErrorKind::InvalidOperation); assert_eq!(res.unwrap_err().kind(), &ErrorKind::InvalidOperation);
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
fn test_cpuset_set_cpus() { fn test_cpuset_set_cpus() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus")); let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus"));
{ {
let cpuset: &CpuSetController = cg.controller_of().unwrap(); let cpuset: &CpuSetController = cg.controller_of().unwrap();
@@ -61,13 +59,12 @@ fn test_cpuset_set_cpus() {
assert_eq!(format!("{}-{}", set.cpus[0].0, set.cpus[0].1), cpus); assert_eq!(format!("{}-{}", set.cpus[0].0, set.cpus[0].1), cpus);
} }
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
fn test_cpuset_set_cpus_add_task() { fn test_cpuset_set_cpus_add_task() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus_add_task/sub-dir")); let cg = Cgroup::new(h, String::from("test_cpuset_set_cpus_add_task/sub-dir"));
let cpuset: &CpuSetController = cg.controller_of().unwrap(); let cpuset: &CpuSetController = cg.controller_of().unwrap();
@@ -92,5 +89,5 @@ fn test_cpuset_set_cpus_add_task() {
println!("tasks after deleted: {:?}", tasks); println!("tasks after deleted: {:?}", tasks);
assert_eq!(0, tasks.len()); assert_eq!(0, tasks.len());
cg.delete(); cg.delete().unwrap();
} }

View File

@@ -7,7 +7,7 @@
//! Integration tests about the devices subsystem //! Integration tests about the devices subsystem
use cgroups::devices::{DevicePermissions, DeviceType, DevicesController}; use cgroups::devices::{DevicePermissions, DeviceType, DevicesController};
use cgroups::{Cgroup, DeviceResource, Hierarchy}; use cgroups::{Cgroup, DeviceResource};
#[test] #[test]
fn test_devices_parsing() { fn test_devices_parsing() {
@@ -17,22 +17,23 @@ fn test_devices_parsing() {
} }
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("test_devices_parsing")); let cg = Cgroup::new(h, String::from("test_devices_parsing"));
{ {
let devices: &DevicesController = cg.controller_of().unwrap(); let devices: &DevicesController = cg.controller_of().unwrap();
// Deny access to all devices first // Deny access to all devices first
devices.deny_device( devices
DeviceType::All, .deny_device(
-1, DeviceType::All,
-1, -1,
&vec![ -1,
DevicePermissions::Read, &vec![
DevicePermissions::Write, DevicePermissions::Read,
DevicePermissions::MkNod, DevicePermissions::Write,
], DevicePermissions::MkNod,
); ],
)
.unwrap();
// Acquire the list of allowed devices after we denied all // Acquire the list of allowed devices after we denied all
let allowed_devices = devices.allowed_devices(); let allowed_devices = devices.allowed_devices();
// Verify that there are no devices that we can access. // Verify that there are no devices that we can access.
@@ -40,7 +41,9 @@ fn test_devices_parsing() {
assert_eq!(allowed_devices.unwrap(), Vec::new()); assert_eq!(allowed_devices.unwrap(), Vec::new());
// Now add mknod access to /dev/null device // Now add mknod access to /dev/null device
devices.allow_device(DeviceType::Char, 1, 3, &vec![DevicePermissions::MkNod]); devices
.allow_device(DeviceType::Char, 1, 3, &vec![DevicePermissions::MkNod])
.unwrap();
let allowed_devices = devices.allowed_devices(); let allowed_devices = devices.allowed_devices();
assert!(allowed_devices.is_ok()); assert!(allowed_devices.is_ok());
let allowed_devices = allowed_devices.unwrap(); let allowed_devices = allowed_devices.unwrap();
@@ -57,12 +60,14 @@ fn test_devices_parsing() {
); );
// Now deny, this device explicitly. // Now deny, this device explicitly.
devices.deny_device(DeviceType::Char, 1, 3, &DevicePermissions::all()); devices
.deny_device(DeviceType::Char, 1, 3, &DevicePermissions::all())
.unwrap();
// Finally, check that. // Finally, check that.
let allowed_devices = devices.allowed_devices(); let allowed_devices = devices.allowed_devices();
// Verify that there are no devices that we can access. // Verify that there are no devices that we can access.
assert!(allowed_devices.is_ok()); assert!(allowed_devices.is_ok());
assert_eq!(allowed_devices.unwrap(), Vec::new()); assert_eq!(allowed_devices.unwrap(), Vec::new());
} }
cg.delete(); cg.delete().unwrap();
} }

View File

@@ -4,12 +4,9 @@
// //
//! Integration tests about the hugetlb subsystem //! Integration tests about the hugetlb subsystem
use cgroups::hugetlb::{self, HugeTlbController};
use cgroups::Controller;
use cgroups::{Cgroup, Hierarchy};
use cgroups::error::ErrorKind::*;
use cgroups::error::*; use cgroups::error::*;
use cgroups::hugetlb::{self, HugeTlbController};
use cgroups::Cgroup;
use std::fs; use std::fs;
#[test] #[test]
@@ -20,11 +17,10 @@ fn test_hugetlb_sizes() {
} }
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("test_hugetlb_sizes")); let cg = Cgroup::new(h, String::from("test_hugetlb_sizes"));
{ {
let hugetlb_controller: &HugeTlbController = cg.controller_of().unwrap(); let hugetlb_controller: &HugeTlbController = cg.controller_of().unwrap();
let sizes = hugetlb_controller.get_sizes(); let _ = hugetlb_controller.get_sizes();
// test sizes count // test sizes count
let sizes = hugetlb_controller.get_sizes(); let sizes = hugetlb_controller.get_sizes();
@@ -40,7 +36,7 @@ fn test_hugetlb_sizes() {
assert_no_error(hugetlb_controller.max_usage_in_bytes(&size)); assert_no_error(hugetlb_controller.max_usage_in_bytes(&size));
} }
} }
cg.delete(); cg.delete().unwrap();
} }
fn assert_no_error(r: Result<u64>) { fn assert_no_error(r: Result<u64>) {

View File

@@ -11,7 +11,6 @@ use cgroups::{Cgroup, MaxValue};
#[test] #[test]
fn test_disable_oom_killer() { fn test_disable_oom_killer() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("test_disable_oom_killer")); let cg = Cgroup::new(h, String::from("test_disable_oom_killer"));
{ {
let mem_controller: &MemController = cg.controller_of().unwrap(); let mem_controller: &MemController = cg.controller_of().unwrap();
@@ -31,7 +30,7 @@ fn test_disable_oom_killer() {
assert_eq!(m.oom_control.oom_kill_disable, true); assert_eq!(m.oom_control.oom_kill_disable, true);
} }
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
@@ -41,7 +40,6 @@ fn set_mem_v2() {
return; return;
} }
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("set_mem_v2")); let cg = Cgroup::new(h, String::from("set_mem_v2"));
{ {
let mem_controller: &MemController = cg.controller_of().unwrap(); let mem_controller: &MemController = cg.controller_of().unwrap();
@@ -89,5 +87,5 @@ fn set_mem_v2() {
assert_eq!(m.high, Some(MaxValue::Max)); assert_eq!(m.high, Some(MaxValue::Max));
} }
cg.delete(); cg.delete().unwrap();
} }

View File

@@ -7,47 +7,42 @@
//! Integration tests about the pids subsystem //! Integration tests about the pids subsystem
use cgroups::pid::PidController; use cgroups::pid::PidController;
use cgroups::Controller; use cgroups::Controller;
use cgroups::{Cgroup, CgroupPid, Hierarchy, MaxValue, PidResources, Resources}; use cgroups::{Cgroup, MaxValue};
use nix::sys::wait::{waitpid, WaitStatus}; use nix::sys::wait::{waitpid, WaitStatus};
use nix::unistd::{fork, ForkResult, Pid}; use nix::unistd::{fork, ForkResult};
use libc::pid_t; use libc::pid_t;
use std::thread;
#[test] #[test]
fn create_and_delete_cgroup() { fn create_and_delete_cgroup() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("create_and_delete_cgroup")); let cg = Cgroup::new(h, String::from("create_and_delete_cgroup"));
{ {
let pidcontroller: &PidController = cg.controller_of().unwrap(); let pidcontroller: &PidController = cg.controller_of().unwrap();
pidcontroller.set_pid_max(MaxValue::Value(1337)); pidcontroller.set_pid_max(MaxValue::Value(1337)).unwrap();
let max = pidcontroller.get_pid_max(); let max = pidcontroller.get_pid_max();
assert!(max.is_ok()); assert!(max.is_ok());
assert_eq!(max.unwrap(), MaxValue::Value(1337)); assert_eq!(max.unwrap(), MaxValue::Value(1337));
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
fn test_pids_current_is_zero() { fn test_pids_current_is_zero() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("test_pids_current_is_zero")); let cg = Cgroup::new(h, String::from("test_pids_current_is_zero"));
{ {
let pidcontroller: &PidController = cg.controller_of().unwrap(); let pidcontroller: &PidController = cg.controller_of().unwrap();
let current = pidcontroller.get_pid_current(); let current = pidcontroller.get_pid_current();
assert_eq!(current.unwrap(), 0); assert_eq!(current.unwrap(), 0);
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
fn test_pids_events_is_zero() { fn test_pids_events_is_zero() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("test_pids_events_is_zero")); let cg = Cgroup::new(h, String::from("test_pids_events_is_zero"));
{ {
let pidcontroller: &PidController = cg.controller_of().unwrap(); let pidcontroller: &PidController = cg.controller_of().unwrap();
@@ -55,13 +50,12 @@ fn test_pids_events_is_zero() {
assert!(events.is_ok()); assert!(events.is_ok());
assert_eq!(events.unwrap(), 0); assert_eq!(events.unwrap(), 0);
} }
cg.delete(); cg.delete().unwrap();
} }
#[test] #[test]
fn test_pid_events_is_not_zero() { fn test_pid_events_is_not_zero() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("test_pid_events_is_not_zero")); let cg = Cgroup::new(h, String::from("test_pid_events_is_not_zero"));
{ {
let pids: &PidController = cg.controller_of().unwrap(); let pids: &PidController = cg.controller_of().unwrap();
@@ -105,5 +99,5 @@ fn test_pid_events_is_not_zero() {
Err(_) => panic!("failed to fork"), Err(_) => panic!("failed to fork"),
} }
} }
cg.delete(); cg.delete().unwrap();
} }

View File

@@ -6,22 +6,20 @@
//! Integration test about setting resources using `apply()` //! Integration test about setting resources using `apply()`
use cgroups::pid::PidController; use cgroups::pid::PidController;
use cgroups::{Cgroup, Hierarchy, MaxValue, PidResources, Resources}; use cgroups::{Cgroup, MaxValue, PidResources, Resources};
#[test] #[test]
fn pid_resources() { fn pid_resources() {
let h = cgroups::hierarchies::auto(); let h = cgroups::hierarchies::auto();
let h = Box::new(&*h);
let cg = Cgroup::new(h, String::from("pid_resources")); let cg = Cgroup::new(h, String::from("pid_resources"));
{ {
let res = Resources { let res = Resources {
pid: PidResources { pid: PidResources {
update_values: true, maximum_number_of_processes: Some(MaxValue::Value(512)),
maximum_number_of_processes: MaxValue::Value(512),
}, },
..Default::default() ..Default::default()
}; };
cg.apply(&res); cg.apply(&res).unwrap();
// verify // verify
let pidcontroller: &PidController = cg.controller_of().unwrap(); let pidcontroller: &PidController = cg.controller_of().unwrap();
@@ -29,5 +27,5 @@ fn pid_resources() {
assert_eq!(pid_max.is_ok(), true); assert_eq!(pid_max.is_ok(), true);
assert_eq!(pid_max.unwrap(), MaxValue::Value(512)); assert_eq!(pid_max.unwrap(), MaxValue::Value(512));
} }
cg.delete(); cg.delete().unwrap();
} }