mirror of
https://github.com/kata-containers/cgroups-rs.git
synced 2026-08-05 02:13:23 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbdfa88596 | ||
|
|
853ed46993 | ||
|
|
15b65c5e5e | ||
|
|
87f8ac7f0d | ||
|
|
225388ff7c | ||
|
|
f0a695cc00 | ||
|
|
50d3c398a0 | ||
|
|
033fa4b857 | ||
|
|
ac4e6eda66 | ||
|
|
35ecd6fd77 | ||
|
|
eb6577e3e0 | ||
|
|
8f6a7e0a31 | ||
|
|
9baa065226 | ||
|
|
e160df0751 | ||
|
|
e1e05d3a1c | ||
|
|
a89f4a062e | ||
|
|
61a0957a65 | ||
|
|
059204589c | ||
|
|
c254fffbe0 | ||
|
|
438d774866 | ||
|
|
42ee1bafbd | ||
|
|
b6bb5ae947 | ||
|
|
d2882b1d85 | ||
|
|
abcb5ed031 | ||
|
|
1f188be405 | ||
|
|
fbd7164c29 | ||
|
|
f34225411e | ||
|
|
cd998f3f9b | ||
|
|
1ac76b69ba | ||
|
|
121f78d8e8 | ||
|
|
0f76570677 | ||
|
|
10650e2b16 | ||
|
|
567cdb43b3 | ||
|
|
0c18b0855e | ||
|
|
ca610bb57e | ||
|
|
af6fc63bed | ||
|
|
6f9e89572e | ||
|
|
42eb32765b | ||
|
|
efb98108fc | ||
|
|
c310b30c52 | ||
|
|
152af17f8f | ||
|
|
d18b3bac2f | ||
|
|
414fa281cc | ||
|
|
f0eac7859a | ||
|
|
db40fe8cd3 | ||
|
|
8717524f2c | ||
|
|
cd7e737149 |
21
.github/workflows/PR-wip-checks.yaml
vendored
Normal file
21
.github/workflows/PR-wip-checks.yaml
vendored
Normal 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"]'
|
||||||
53
.github/workflows/commit-message-check.yaml
vendored
Normal file
53
.github/workflows/commit-message-check.yaml
vendored
Normal 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 }}
|
||||||
30
.travis.yml
30
.travis.yml
@@ -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
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cgroups"
|
name = "cgroups-rs"
|
||||||
description = "Native Rust crate for managing control groups on Linux"
|
description = "Native Rust crate for managing control groups on Linux"
|
||||||
repository = "https://github.com/levex/cgroups-rs"
|
repository = "https://github.com/kata-containers/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.2"
|
||||||
authors = ["Levente Kurusa <lkurusa@acm.org>", "Sam Wilson <tecywiz121@hotmail.com>"]
|
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>", "Levente Kurusa <lkurusa@acm.org>", "Sam Wilson <tecywiz121@hotmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -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"
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -1,32 +1,36 @@
|
|||||||
# cgroups-rs 
|
# cgroups-rs 
|
||||||
Native Rust library for managing control groups under Linux
|
Native Rust library for managing control groups under Linux
|
||||||
|
|
||||||
Right now the crate only support the original, V1 hierarchy, however support
|
Both v1 and v2 of cgroups are supported.
|
||||||
is planned for the Unified hierarchy.
|
|
||||||
|
|
||||||
# Examples
|
# Examples
|
||||||
|
|
||||||
## 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_rs::*;
|
||||||
|
use cgroups_rs::cgroup_builder::*;
|
||||||
|
|
||||||
|
// Acquire a handle for the cgroup hierarchy.
|
||||||
|
let hier = cgroups_rs::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_rs::cpu::CpuController = cg.controller_of().unwrap();
|
||||||
cpus.add_task(1234u64);
|
cpus.add_task(&CgroupPid::from(1234u64));
|
||||||
|
|
||||||
// [...]
|
// [...]
|
||||||
|
|
||||||
|
|||||||
85
src/blkio.rs
85
src/blkio.rs
@@ -8,13 +8,13 @@
|
|||||||
//!
|
//!
|
||||||
//! See the Kernel's documentation for more information about this subsystem, found at:
|
//! See the Kernel's documentation for more information about this subsystem, found at:
|
||||||
//! [Documentation/cgroup-v1/blkio-controller.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt)
|
//! [Documentation/cgroup-v1/blkio-controller.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt)
|
||||||
use std::fs::File;
|
use std::io::Write;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::error::ErrorKind::*;
|
use crate::error::ErrorKind::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
|
use crate::{read_string_from, read_u64_from};
|
||||||
use crate::{
|
use crate::{
|
||||||
BlkIoResources, ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem,
|
BlkIoResources, ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem,
|
||||||
};
|
};
|
||||||
@@ -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,39 +393,17 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_string_from(mut file: File) -> Result<String> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => Ok(string.trim().to_string()),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => string
|
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
||||||
|
|||||||
154
src/cgroup.rs
154
src/cgroup.rs
@@ -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)
|
||||||
|
|||||||
@@ -16,12 +16,11 @@
|
|||||||
//! by a call to `build()`.
|
//! by a call to `build()`.
|
||||||
//!
|
//!
|
||||||
//! ```rust,no_run
|
//! ```rust,no_run
|
||||||
//! # use cgroups::*;
|
//! # use cgroups_rs::*;
|
||||||
//! # use cgroups::devices::*;
|
//! # use cgroups_rs::devices::*;
|
||||||
//! # use cgroups::cgroup_builder::*;
|
//! # use cgroups_rs::cgroup_builder::*;
|
||||||
//! let h = cgroups::hierarchies::auto();
|
//! let h = cgroups_rs::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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
53
src/cpu.rs
53
src/cpu.rs
@@ -15,11 +15,11 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
use crate::error::ErrorKind::*;
|
use crate::error::ErrorKind::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::{parse_max_value, read_i64_from};
|
use crate::{parse_max_value, read_i64_from, read_u64_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,31 +102,17 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => string
|
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 +282,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)
|
||||||
|
|||||||
@@ -7,13 +7,13 @@
|
|||||||
//!
|
//!
|
||||||
//! See the Kernel's documentation for more information about this subsystem, found at:
|
//! See the Kernel's documentation for more information about this subsystem, found at:
|
||||||
//! [Documentation/cgroup-v1/cpuacct.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt)
|
//! [Documentation/cgroup-v1/cpuacct.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt)
|
||||||
use std::fs::File;
|
use std::io::Write;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::error::ErrorKind::*;
|
use crate::error::ErrorKind::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
|
use crate::{read_string_from, read_u64_from};
|
||||||
use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
|
use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
|
||||||
|
|
||||||
/// A controller that allows controlling the `cpuacct` subsystem of a Cgroup.
|
/// A controller that allows controlling the `cpuacct` subsystem of a Cgroup.
|
||||||
@@ -89,38 +89,17 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
|
||||||
let mut string = String::new();
|
|
||||||
let res = file.read_to_string(&mut string);
|
|
||||||
match res {
|
|
||||||
Ok(_) => match string.trim().parse() {
|
|
||||||
Ok(e) => Ok(e),
|
|
||||||
Err(e) => Err(Error::with_cause(ParseError, e)),
|
|
||||||
},
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_string_from(mut file: File) -> Result<String> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => Ok(string.trim().to_string()),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
||||||
|
|||||||
@@ -10,13 +10,13 @@
|
|||||||
//! [Documentation/cgroup-v1/cpusets.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt)
|
//! [Documentation/cgroup-v1/cpusets.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt)
|
||||||
|
|
||||||
use log::*;
|
use log::*;
|
||||||
use std::fs::File;
|
use std::io::Write;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::error::ErrorKind::*;
|
use crate::error::ErrorKind::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
|
use crate::{read_string_from, read_u64_from};
|
||||||
use crate::{
|
use crate::{
|
||||||
ControllIdentifier, ControllerInternal, Controllers, CpuResources, Resources, Subsystem,
|
ControllIdentifier, ControllerInternal, Controllers, CpuResources, Resources, Subsystem,
|
||||||
};
|
};
|
||||||
@@ -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,32 +196,14 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_string_from(mut file: File) -> Result<String> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => Ok(string.trim().to_string()),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => string
|
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a string like "1,2,4-5,8" into a list of (start, end) tuples.
|
/// Parse a string like "1,2,4-5,8" into a list of (start, end) tuples.
|
||||||
fn parse_range(s: String) -> Result<Vec<(u64, u64)>> {
|
fn parse_range(s: String) -> Result<Vec<(u64, u64)>> {
|
||||||
let mut fin = Vec::new();
|
let mut fin = Vec::new();
|
||||||
@@ -268,12 +242,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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
14
src/error.rs
14
src/error.rs
@@ -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,
|
||||||
|
|||||||
@@ -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(_) => {}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,13 +8,12 @@
|
|||||||
//!
|
//!
|
||||||
//! See the Kernel's documentation for more information about this subsystem, found at:
|
//! See the Kernel's documentation for more information about this subsystem, found at:
|
||||||
//! [Documentation/cgroup-v1/hugetlb.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/hugetlb.txt)
|
//! [Documentation/cgroup-v1/hugetlb.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/hugetlb.txt)
|
||||||
use std::fs::File;
|
use std::io::Write;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::error::ErrorKind::*;
|
use crate::error::ErrorKind::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::flat_keyed_to_vec;
|
use crate::{flat_keyed_to_vec, read_u64_from};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ControllIdentifier, ControllerInternal, Controllers, HugePageResources, Resources, Subsystem,
|
ControllIdentifier, ControllerInternal, Controllers, HugePageResources, Resources, Subsystem,
|
||||||
@@ -54,14 +53,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,31 +77,17 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => string
|
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 +209,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> {
|
||||||
|
|||||||
199
src/lib.rs
199
src/lib.rs
@@ -7,9 +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};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
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;
|
||||||
@@ -48,10 +68,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 +105,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 +139,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 +210,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 +253,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 +299,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 +345,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 +386,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 + Sync {
|
||||||
/// 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 +397,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_rs::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_rs::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 +490,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 +507,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 +528,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 +559,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 +690,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 +709,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,21 +833,35 @@ 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.
|
fn read_from<T>(mut file: File) -> Result<T>
|
||||||
/// with error: `Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" }`
|
where
|
||||||
pub fn libc_rmdir(p: &str) {
|
T: FromStr,
|
||||||
// with int return value
|
<T as FromStr>::Err: 'static + Send + Sync + std::error::Error,
|
||||||
let _ = unsafe { libc::rmdir(p.as_ptr() as *const i8) };
|
{
|
||||||
}
|
|
||||||
|
|
||||||
/// read and parse an i64 data
|
|
||||||
pub 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
|
||||||
.trim()
|
.trim()
|
||||||
.parse()
|
.parse::<T>()
|
||||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
.map_err(|e| Error::with_cause(ParseError, e)),
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_string_from(mut file: File) -> Result<String> {
|
||||||
|
let mut string = String::new();
|
||||||
|
match file.read_to_string(&mut string) {
|
||||||
|
Ok(_) => Ok(string.trim().to_string()),
|
||||||
|
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read and parse an u64 data
|
||||||
|
fn read_u64_from(file: File) -> Result<u64> {
|
||||||
|
read_from::<u64>(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// read and parse an i64 data
|
||||||
|
fn read_i64_from(file: File) -> Result<i64> {
|
||||||
|
read_from::<i64>(file)
|
||||||
|
}
|
||||||
|
|||||||
123
src/memory.rs
123
src/memory.rs
@@ -9,20 +9,20 @@
|
|||||||
//! See the Kernel's documentation for more information about this subsystem, found at:
|
//! See the Kernel's documentation for more information about this subsystem, found at:
|
||||||
//! [Documentation/cgroup-v1/memory.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt)
|
//! [Documentation/cgroup-v1/memory.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt)
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::io::Write;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::mpsc::Receiver;
|
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, read_string_from, read_u64_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 +453,24 @@ 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);
|
|
||||||
}
|
memres.attrs.iter().for_each(|(k, v)| {
|
||||||
|
let _ = self.set(k, v);
|
||||||
|
});
|
||||||
|
|
||||||
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 +503,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 +706,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 +720,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 +741,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 +764,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 +790,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 +822,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 +856,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,50 +865,19 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => string
|
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => Ok(string.trim().to_string()),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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
|
||||||
|
|||||||
@@ -7,13 +7,13 @@
|
|||||||
//!
|
//!
|
||||||
//! See the Kernel's documentation for more information about this subsystem, found at:
|
//! See the Kernel's documentation for more information about this subsystem, found at:
|
||||||
//! [Documentation/cgroup-v1/net_cls.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/net_cls.txt)
|
//! [Documentation/cgroup-v1/net_cls.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/net_cls.txt)
|
||||||
use std::fs::File;
|
use std::io::Write;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::error::ErrorKind::*;
|
use crate::error::ErrorKind::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
|
use crate::read_u64_from;
|
||||||
use crate::{
|
use crate::{
|
||||||
ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, Subsystem,
|
ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, Subsystem,
|
||||||
};
|
};
|
||||||
@@ -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,29 +66,17 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => string
|
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
||||||
|
|||||||
@@ -8,13 +8,13 @@
|
|||||||
//! See the Kernel's documentation for more information about this subsystem, found at:
|
//! See the Kernel's documentation for more information about this subsystem, found at:
|
||||||
//! [Documentation/cgroup-v1/net_prio.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/net_prio.txt)
|
//! [Documentation/cgroup-v1/net_prio.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/net_prio.txt)
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::io::{BufRead, BufReader, Write};
|
||||||
use std::io::{BufRead, BufReader, Read, Write};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::error::ErrorKind::*;
|
use crate::error::ErrorKind::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
|
use crate::read_u64_from;
|
||||||
use crate::{
|
use crate::{
|
||||||
ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, Subsystem,
|
ControllIdentifier, ControllerInternal, Controllers, NetworkResources, Resources, Subsystem,
|
||||||
};
|
};
|
||||||
@@ -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,29 +69,17 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => string
|
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
42
src/pid.rs
42
src/pid.rs
@@ -8,13 +8,13 @@
|
|||||||
//!
|
//!
|
||||||
//! See the Kernel's documentation for more information about this subsystem, found at:
|
//! See the Kernel's documentation for more information about this subsystem, found at:
|
||||||
//! [Documentation/cgroups-v1/pids.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt)
|
//! [Documentation/cgroups-v1/pids.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt)
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::error::ErrorKind::*;
|
use crate::error::ErrorKind::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
|
use crate::read_u64_from;
|
||||||
use crate::{
|
use crate::{
|
||||||
parse_max_value, ControllIdentifier, ControllerInternal, Controllers, MaxValue, PidResources,
|
parse_max_value, ControllIdentifier, ControllerInternal, Controllers, MaxValue, PidResources,
|
||||||
Resources, Subsystem,
|
Resources, Subsystem,
|
||||||
@@ -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,32 +81,18 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_u64_from(mut file: File) -> Result<u64> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => string
|
|
||||||
.trim()
|
|
||||||
.parse()
|
|
||||||
.map_err(|e| Error::with_cause(ParseError, e)),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
||||||
|
|||||||
21
src/rdma.rs
21
src/rdma.rs
@@ -7,13 +7,13 @@
|
|||||||
//!
|
//!
|
||||||
//! See the Kernel's documentation for more information about this subsystem, found at:
|
//! See the Kernel's documentation for more information about this subsystem, found at:
|
||||||
//! [Documentation/cgroup-v1/rdma.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/rdma.txt)
|
//! [Documentation/cgroup-v1/rdma.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/rdma.txt)
|
||||||
use std::fs::File;
|
use std::io::Write;
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::error::ErrorKind::*;
|
use crate::error::ErrorKind::*;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
|
||||||
|
use crate::read_string_from;
|
||||||
use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
|
use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
|
||||||
|
|
||||||
/// A controller that allows controlling the `rdma` subsystem of a Cgroup.
|
/// A controller that allows controlling the `rdma` subsystem of a Cgroup.
|
||||||
@@ -58,26 +58,17 @@ 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_string_from(mut file: File) -> Result<String> {
|
|
||||||
let mut string = String::new();
|
|
||||||
match file.read_to_string(&mut string) {
|
|
||||||
Ok(_) => Ok(string.trim().to_string()),
|
|
||||||
Err(e) => Err(Error::with_cause(ReadFailed, e)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -5,25 +5,24 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
//! Some simple tests covering the builder pattern for control groups.
|
//! Some simple tests covering the builder pattern for control groups.
|
||||||
use cgroups::blkio::*;
|
use cgroups_rs::blkio::*;
|
||||||
use cgroups::cgroup_builder::*;
|
use cgroups_rs::cgroup_builder::*;
|
||||||
use cgroups::cpu::*;
|
use cgroups_rs::cpu::*;
|
||||||
use cgroups::devices::*;
|
use cgroups_rs::devices::*;
|
||||||
use cgroups::hugetlb::*;
|
use cgroups_rs::hugetlb::*;
|
||||||
use cgroups::memory::*;
|
use cgroups_rs::memory::*;
|
||||||
use cgroups::net_cls::*;
|
use cgroups_rs::net_cls::*;
|
||||||
use cgroups::pid::*;
|
use cgroups_rs::pid::*;
|
||||||
use cgroups::*;
|
use cgroups_rs::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_cpu_res_build() {
|
pub fn test_cpu_res_build() {
|
||||||
let h = cgroups::hierarchies::auto();
|
let h = cgroups_rs::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_rs::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_rs::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_rs::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,44 +98,42 @@ pub fn test_devices_res_build() {
|
|||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
cg.delete();
|
cg.delete().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_network_res_build() {
|
pub fn test_network_res_build() {
|
||||||
let h = cgroups::hierarchies::auto();
|
let h = cgroups_rs::hierarchies::auto();
|
||||||
if h.v2() {
|
if h.v2() {
|
||||||
// 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]
|
||||||
pub fn test_hugepages_res_build() {
|
pub fn test_hugepages_res_build() {
|
||||||
let h = cgroups::hierarchies::auto();
|
let h = cgroups_rs::hierarchies::auto();
|
||||||
if h.v2() {
|
if h.v2() {
|
||||||
// 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_rs::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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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_rs::memory::MemController;
|
||||||
use cgroups::Controller;
|
use cgroups_rs::Controller;
|
||||||
use cgroups::{Cgroup, CgroupPid, Hierarchy, Subsystem};
|
use cgroups_rs::{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_rs::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,23 +33,19 @@ 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]
|
||||||
fn test_cgroup_with_relative_paths() {
|
fn test_cgroup_with_relative_paths() {
|
||||||
if cgroups::hierarchies::is_cgroup2_unified_mode() {
|
if cgroups_rs::hierarchies::is_cgroup2_unified_mode() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let h = cgroups::hierarchies::auto();
|
let h = cgroups_rs::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,35 +68,29 @@ 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]
|
||||||
fn test_cgroup_v2() {
|
fn test_cgroup_v2() {
|
||||||
if !cgroups::hierarchies::is_cgroup2_unified_mode() {
|
if !cgroups_rs::hierarchies::is_cgroup2_unified_mode() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let h = cgroups::hierarchies::auto();
|
let h = cgroups_rs::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();
|
||||||
}
|
}
|
||||||
|
|||||||
24
tests/cpu.rs
24
tests/cpu.rs
@@ -4,16 +4,12 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
//! Simple unit tests about the CPU control groups system.
|
//! Simple unit tests about the CPU control groups system.
|
||||||
use cgroups::cpu::CpuController;
|
use cgroups_rs::cpu::CpuController;
|
||||||
use cgroups::error::ErrorKind;
|
use cgroups_rs::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_rs::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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,15 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 or MIT
|
// SPDX-License-Identifier: Apache-2.0 or MIT
|
||||||
//
|
//
|
||||||
|
|
||||||
use cgroups::cpuset::CpuSetController;
|
use cgroups_rs::cpuset::CpuSetController;
|
||||||
use cgroups::error::ErrorKind;
|
use cgroups_rs::error::ErrorKind;
|
||||||
use cgroups::{Cgroup, CgroupPid, CpuResources, Hierarchy, Resources};
|
use cgroups_rs::{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_rs::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_rs::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_rs::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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,33 +6,34 @@
|
|||||||
|
|
||||||
//! Integration tests about the devices subsystem
|
//! Integration tests about the devices subsystem
|
||||||
|
|
||||||
use cgroups::devices::{DevicePermissions, DeviceType, DevicesController};
|
use cgroups_rs::devices::{DevicePermissions, DeviceType, DevicesController};
|
||||||
use cgroups::{Cgroup, DeviceResource, Hierarchy};
|
use cgroups_rs::{Cgroup, DeviceResource};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_devices_parsing() {
|
fn test_devices_parsing() {
|
||||||
// now only v2
|
// now only v2
|
||||||
if cgroups::hierarchies::is_cgroup2_unified_mode() {
|
if cgroups_rs::hierarchies::is_cgroup2_unified_mode() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let h = cgroups::hierarchies::auto();
|
let h = cgroups_rs::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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,27 +4,23 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
//! Integration tests about the hugetlb subsystem
|
//! Integration tests about the hugetlb subsystem
|
||||||
use cgroups::hugetlb::{self, HugeTlbController};
|
use cgroups_rs::error::*;
|
||||||
use cgroups::Controller;
|
use cgroups_rs::hugetlb::{self, HugeTlbController};
|
||||||
use cgroups::{Cgroup, Hierarchy};
|
use cgroups_rs::Cgroup;
|
||||||
|
|
||||||
use cgroups::error::ErrorKind::*;
|
|
||||||
use cgroups::error::*;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hugetlb_sizes() {
|
fn test_hugetlb_sizes() {
|
||||||
// now only v2
|
// now only v2
|
||||||
if cgroups::hierarchies::is_cgroup2_unified_mode() {
|
if cgroups_rs::hierarchies::is_cgroup2_unified_mode() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let h = cgroups::hierarchies::auto();
|
let h = cgroups_rs::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>) {
|
||||||
|
|||||||
@@ -4,14 +4,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
//! Integration tests about the hugetlb subsystem
|
//! Integration tests about the hugetlb subsystem
|
||||||
use cgroups::memory::{MemController, SetMemory};
|
use cgroups_rs::memory::{MemController, SetMemory};
|
||||||
use cgroups::Controller;
|
use cgroups_rs::Controller;
|
||||||
use cgroups::{Cgroup, MaxValue};
|
use cgroups_rs::{Cgroup, MaxValue};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_disable_oom_killer() {
|
fn test_disable_oom_killer() {
|
||||||
let h = cgroups::hierarchies::auto();
|
let h = cgroups_rs::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,17 +30,16 @@ 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]
|
||||||
fn set_mem_v2() {
|
fn set_mem_v2() {
|
||||||
let h = cgroups::hierarchies::auto();
|
let h = cgroups_rs::hierarchies::auto();
|
||||||
if !h.v2() {
|
if !h.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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,49 +5,44 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
//! Integration tests about the pids subsystem
|
//! Integration tests about the pids subsystem
|
||||||
use cgroups::pid::PidController;
|
use cgroups_rs::pid::PidController;
|
||||||
use cgroups::Controller;
|
use cgroups_rs::Controller;
|
||||||
use cgroups::{Cgroup, CgroupPid, Hierarchy, MaxValue, PidResources, Resources};
|
use cgroups_rs::{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_rs::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_rs::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_rs::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_rs::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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,23 +5,21 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
//! Integration test about setting resources using `apply()`
|
//! Integration test about setting resources using `apply()`
|
||||||
use cgroups::pid::PidController;
|
use cgroups_rs::pid::PidController;
|
||||||
use cgroups::{Cgroup, Hierarchy, MaxValue, PidResources, Resources};
|
use cgroups_rs::{Cgroup, MaxValue, PidResources, Resources};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pid_resources() {
|
fn pid_resources() {
|
||||||
let h = cgroups::hierarchies::auto();
|
let h = cgroups_rs::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();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user