Compare commits

...

24 Commits

Author SHA1 Message Date
Fupan Li
bcb7c6cd54 Merge pull request #51 from Tim-Zhang/release-0.2.6
release: v0.2.6
2021-06-30 20:53:39 +08:00
Tim Zhang
2554aa65d0 release: v0.2.6
Bump version from 0.2.5 to 0.2.6

Signed-off-by: Tim Zhang <tim@hyper.sh>
2021-06-30 20:36:34 +08:00
Tim Zhang
34f935be89 Merge pull request #49 from lifupan/master
freezer: fix the issue of missing trim the str
2021-06-30 20:35:22 +08:00
Fupan Li
5485d8dd46 Merge pull request #50 from Tim-Zhang/fix-clippy-for-rust-1.53
Fix clippy for rust 1.53
2021-06-30 19:58:48 +08:00
Tim Zhang
ec4cda1dd9 Fix clippy for rust 1.53
There are new lints are added in clippy for rust 1.53

Signed-off-by: Tim Zhang <tim@hyper.sh>
2021-06-30 19:07:56 +08:00
fupan.lfp
4b5a190ecc freezer: fix the issue of missing trim the str
When reading from the freezer file, it should trim it
first, and the string may container an '\n'.

Fixes: #48

Signed-off-by: fupan.lfp <fupan.lfp@antgroup.com>
2021-06-30 18:39:33 +08:00
Fupan Li
45b626e0c0 Merge pull request #46 from Tim-Zhang/fix-clippy-for-rust-1.52
Fix clippy for rust 1.52
2021-05-21 16:24:16 +08:00
Tim Zhang
0e2430fde1 clippy: turn on lint upper_case_acronyms
cargo-clippy has moved the upper_case_acronyms lint to
pedantic(removed from the default list), but we need
the lint to keep names consistent and follow the rust
naming conventions.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2021-05-21 00:48:50 +08:00
Tim Zhang
5aa7e6c90e Fix clippy for rust 1.52
There are new lints are added in clippy for rust 1.52

Signed-off-by: Tim Zhang <tim@hyper.sh>
2021-05-21 00:45:27 +08:00
Fupan Li
5bb27a2692 Merge pull request #45 from Tim-Zhang/release-0.2.5
release: v0.2.5
2021-03-24 14:52:27 +08:00
Tim Zhang
0b2a0405e2 release: v0.2.5
Bump version to 0.2.5

Signed-off-by: Tim Zhang <tim@hyper.sh>
2021-03-24 14:37:19 +08:00
Bin Liu
c4850ef2ef Merge pull request #44 from Tim-Zhang/impl-clone
Impl Clone for hierarchies:V1, hierarchies:V2
2021-03-23 22:31:27 +08:00
Tim Zhang
aa207edca8 Impl Clone for hierarchies:V1, hierarchies:V2
Clone is useful.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2021-03-23 21:50:18 +08:00
Bin Liu
af7a75ce9e Merge pull request #40 from Jakob-Naucke/v0.2.4
release: v0.2.4
2021-03-03 15:39:15 +08:00
Bin Liu
fb56c817ca Merge pull request #32 from Tim-Zhang/fix-clippy
Fix clippy warnings
2021-03-03 15:38:37 +08:00
Tim Zhang
fdabe52401 github action: Add clippy check
Because the existing warnings are all fixed.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2021-03-03 13:46:19 +08:00
Tim Zhang
9ec1010a15 Fix clippy warnings
Fix clippy warnings.

Signed-off-by: Tim Zhang <tim@hyper.sh>
2021-03-03 13:44:29 +08:00
Fupan Li
610071730d Merge pull request #41 from bergwolf/fix-panic
memory: fix parse_oom_control panic on older kernels
2021-03-03 00:17:54 +08:00
Peng Tao
0a3e4a828f memory: fix parse_oom_control panic on older kernels
Where the oom control fields might not be present.

Fixes: #36
Signed-off-by: Peng Tao <bergwolf@hyper.sh>
2021-02-26 01:40:19 +08:00
Jakob Naucke
60820bfffb release: v0.2.4
Bump version from 0.2.3 to 0.2.4

Signed-off-by: Jakob Naucke <jakob.naucke@ibm.com>
2021-02-25 11:22:47 +01:00
Fupan Li
2209189244 Merge pull request #39 from bergwolf/fix-panic
memory: fix panic when no hierarchical numa stat is available
2021-02-25 14:57:39 +08:00
Peng Tao
8720aed656 memory: fix panic when no hierarchical numa stat is available
For older kernels, it is possible that there is no hierarchical numa
stats.

Fixes: #36
Signed-off-by: Peng Tao <bergwolf@hyper.sh>
2021-02-25 11:00:48 +08:00
Fupan Li
16d73e1d59 Merge pull request #38 from Jakob-Naucke/update-nix
Update nix to 0.20.0
2021-02-25 09:47:01 +08:00
Jakob Naucke
b9ca0a51f1 Update nix to 0.20.0
to pull in https://github.com/nix-rust/nix/pull/1372 and get statfs
MAGIC constants on s390x. Additionally, fork() calls in tests now have
to be marked unsafe.

Fixes: #37

Signed-off-by: Jakob Naucke <jakob.naucke@ibm.com>
2021-02-22 14:28:16 +01:00
28 changed files with 511 additions and 393 deletions

1
.clippy.toml Normal file
View File

@@ -0,0 +1 @@
upper-case-acronyms-aggressive = true

View File

@@ -17,6 +17,13 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- run: rustup component add rustfmt - run: rustup component add rustfmt
- run: make fmt - run: make fmt
clippy:
name: Clippy Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: rustup component add clippy
- run: make clippy
test: test:
name: Run Unit Test name: Run Unit Test
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -24,3 +31,4 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- run: make test - run: make test

View File

@@ -5,7 +5,7 @@ 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.2.3" version = "0.2.6"
authors = ["The Kata Containers community <kata-dev@lists.katacontainers.io>", "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"
homepage = "https://github.com/kata-containers/cgroups-rs" homepage = "https://github.com/kata-containers/cgroups-rs"
@@ -14,7 +14,7 @@ readme = "README.md"
[dependencies] [dependencies]
log = "0.4" log = "0.4"
regex = "1.1" regex = "1.1"
nix = "0.18.0" nix = "0.20.0"
libc = "0.2" libc = "0.2"
[dev-dependencies] [dev-dependencies]

View File

@@ -84,14 +84,14 @@ pub struct IoStat {
fn parse_io_service(s: String) -> Result<Vec<IoService>> { fn parse_io_service(s: String) -> Result<Vec<IoService>> {
s.lines() s.lines()
.filter(|x| x.split_whitespace().collect::<Vec<_>>().len() == 3) .filter(|x| x.split_whitespace().count() == 3)
.map(|x| { .map(|x| {
let mut spl = x.split_whitespace(); let mut spl = x.split_whitespace();
(spl.nth(0).unwrap(), spl.nth(0).unwrap(), spl.nth(0).unwrap()) (spl.next().unwrap(), spl.next().unwrap(), spl.next().unwrap())
}) })
.map(|(a, b, c)| { .map(|(a, b, c)| {
let mut spl = a.split(":"); let mut spl = a.split(':');
(spl.nth(0).unwrap(), spl.nth(0).unwrap(), b, c) (spl.next().unwrap(), spl.next().unwrap(), b, c)
}) })
.collect::<Vec<_>>() .collect::<Vec<_>>()
.chunks(5) .chunks(5)
@@ -131,15 +131,14 @@ fn get_value(s: &str) -> String {
arr[1].to_string() arr[1].to_string()
} }
fn parse_io_stat(s: String) -> Result<Vec<IoStat>> { fn parse_io_stat(s: String) -> Vec<IoStat> {
// line: // line:
// 8:0 rbytes=180224 wbytes=0 rios=3 wios=0 dbytes=0 dios=0 // 8:0 rbytes=180224 wbytes=0 rios=3 wios=0 dbytes=0 dios=0
let v = s s.lines()
.lines() .filter(|x| x.split_whitespace().count() == 7)
.filter(|x| x.split_whitespace().collect::<Vec<_>>().len() == 7)
.map(|x| { .map(|x| {
let arr = x.split_whitespace().collect::<Vec<&str>>(); let arr = x.split_whitespace().collect::<Vec<&str>>();
let device = arr[0].split(":").collect::<Vec<&str>>(); let device = arr[0].split(':').collect::<Vec<&str>>();
let (major, minor) = (device[0], device[1]); let (major, minor) = (device[0], device[1]);
IoStat { IoStat {
@@ -153,14 +152,12 @@ fn parse_io_stat(s: String) -> Result<Vec<IoStat>> {
dios: get_value(arr[6]).parse::<u64>().unwrap(), dios: get_value(arr[6]).parse::<u64>().unwrap(),
} }
}) })
.collect::<Vec<IoStat>>(); .collect::<Vec<IoStat>>()
Ok(v)
} }
fn parse_io_service_total(s: String) -> Result<u64> { fn parse_io_service_total(s: String) -> Result<u64> {
s.lines() s.lines()
.filter(|x| x.split_whitespace().collect::<Vec<_>>().len() == 2) .filter(|x| x.split_whitespace().count() == 2)
.fold(Err(Error::new(ParseError)), |_, x| { .fold(Err(Error::new(ParseError)), |_, x| {
match x.split_whitespace().collect::<Vec<_>>().as_slice() { match x.split_whitespace().collect::<Vec<_>>().as_slice() {
["Total", val] => val.parse::<u64>().map_err(|_| Error::new(ParseError)), ["Total", val] => val.parse::<u64>().map_err(|_| Error::new(ParseError)),
@@ -197,9 +194,9 @@ fn parse_blkio_data(s: String) -> Result<Vec<BlkIoData>> {
}); });
if err.is_err() { if err.is_err() {
return Err(Error::new(ParseError)); Err(Error::new(ParseError))
} else { } else {
return Ok(res); Ok(res)
} }
} }
@@ -407,19 +404,19 @@ impl BlkIoController {
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,
v2: v2, v2,
} }
} }
fn blkio_v2(&self) -> BlkIo { fn blkio_v2(&self) -> BlkIo {
let mut blkio: BlkIo = Default::default(); BlkIo {
blkio.io_stat = self io_stat: self
.open_path("io.stat", false) .open_path("io.stat", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_stat) .map(parse_io_stat)
.unwrap_or(Vec::new()); .unwrap_or_default(),
..Default::default()
blkio }
} }
/// Gathers statistics about and reports the state of the block devices used by the control /// Gathers statistics about and reports the state of the block devices used by the control
@@ -433,222 +430,222 @@ impl BlkIoController {
.open_path("blkio.io_merged", false) .open_path("blkio.io_merged", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_merged_total: self io_merged_total: self
.open_path("blkio.io_merged", false) .open_path("blkio.io_merged", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_merged_recursive: self io_merged_recursive: self
.open_path("blkio.io_merged_recursive", false) .open_path("blkio.io_merged_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_merged_recursive_total: self io_merged_recursive_total: self
.open_path("blkio.io_merged_recursive", false) .open_path("blkio.io_merged_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_queued: self io_queued: self
.open_path("blkio.io_queued", false) .open_path("blkio.io_queued", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_queued_total: self io_queued_total: self
.open_path("blkio.io_queued", false) .open_path("blkio.io_queued", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_queued_recursive: self io_queued_recursive: self
.open_path("blkio.io_queued_recursive", false) .open_path("blkio.io_queued_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_queued_recursive_total: self io_queued_recursive_total: self
.open_path("blkio.io_queued_recursive", false) .open_path("blkio.io_queued_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_service_bytes: self io_service_bytes: self
.open_path("blkio.io_service_bytes", false) .open_path("blkio.io_service_bytes", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_service_bytes_total: self io_service_bytes_total: self
.open_path("blkio.io_service_bytes", false) .open_path("blkio.io_service_bytes", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_service_bytes_recursive: self io_service_bytes_recursive: self
.open_path("blkio.io_service_bytes_recursive", false) .open_path("blkio.io_service_bytes_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_service_bytes_recursive_total: self io_service_bytes_recursive_total: self
.open_path("blkio.io_service_bytes_recursive", false) .open_path("blkio.io_service_bytes_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_serviced: self io_serviced: self
.open_path("blkio.io_serviced", false) .open_path("blkio.io_serviced", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_serviced_total: self io_serviced_total: self
.open_path("blkio.io_serviced", false) .open_path("blkio.io_serviced", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_serviced_recursive: self io_serviced_recursive: self
.open_path("blkio.io_serviced_recursive", false) .open_path("blkio.io_serviced_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_serviced_recursive_total: self io_serviced_recursive_total: self
.open_path("blkio.io_serviced_recursive", false) .open_path("blkio.io_serviced_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_service_time: self io_service_time: self
.open_path("blkio.io_service_time", false) .open_path("blkio.io_service_time", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_service_time_total: self io_service_time_total: self
.open_path("blkio.io_service_time", false) .open_path("blkio.io_service_time", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_service_time_recursive: self io_service_time_recursive: self
.open_path("blkio.io_service_time_recursive", false) .open_path("blkio.io_service_time_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_service_time_recursive_total: self io_service_time_recursive_total: self
.open_path("blkio.io_service_time_recursive", false) .open_path("blkio.io_service_time_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_wait_time: self io_wait_time: self
.open_path("blkio.io_wait_time", false) .open_path("blkio.io_wait_time", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_wait_time_total: self io_wait_time_total: self
.open_path("blkio.io_wait_time", false) .open_path("blkio.io_wait_time", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_wait_time_recursive: self io_wait_time_recursive: self
.open_path("blkio.io_wait_time_recursive", false) .open_path("blkio.io_wait_time_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_wait_time_recursive_total: self io_wait_time_recursive_total: self
.open_path("blkio.io_wait_time_recursive", false) .open_path("blkio.io_wait_time_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
leaf_weight: self leaf_weight: self
.open_path("blkio.leaf_weight", false) .open_path("blkio.leaf_weight", false)
.and_then(|file| read_u64_from(file)) .and_then(read_u64_from)
.unwrap_or(0u64), .unwrap_or(0u64),
leaf_weight_device: self leaf_weight_device: self
.open_path("blkio.leaf_weight_device", false) .open_path("blkio.leaf_weight_device", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_blkio_data) .and_then(parse_blkio_data)
.unwrap_or(Vec::new()), .unwrap_or_default(),
sectors: self sectors: self
.open_path("blkio.sectors", false) .open_path("blkio.sectors", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_blkio_data) .and_then(parse_blkio_data)
.unwrap_or(Vec::new()), .unwrap_or_default(),
sectors_recursive: self sectors_recursive: self
.open_path("blkio.sectors_recursive", false) .open_path("blkio.sectors_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_blkio_data) .and_then(parse_blkio_data)
.unwrap_or(Vec::new()), .unwrap_or_default(),
throttle: BlkIoThrottle { throttle: BlkIoThrottle {
io_service_bytes: self io_service_bytes: self
.open_path("blkio.throttle.io_service_bytes", false) .open_path("blkio.throttle.io_service_bytes", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_service_bytes_total: self io_service_bytes_total: self
.open_path("blkio.throttle.io_service_bytes", false) .open_path("blkio.throttle.io_service_bytes", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_service_bytes_recursive: self io_service_bytes_recursive: self
.open_path("blkio.throttle.io_service_bytes_recursive", false) .open_path("blkio.throttle.io_service_bytes_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_service_bytes_recursive_total: self io_service_bytes_recursive_total: self
.open_path("blkio.throttle.io_service_bytes_recursive", false) .open_path("blkio.throttle.io_service_bytes_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_serviced: self io_serviced: self
.open_path("blkio.throttle.io_serviced", false) .open_path("blkio.throttle.io_serviced", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_serviced_total: self io_serviced_total: self
.open_path("blkio.throttle.io_serviced", false) .open_path("blkio.throttle.io_serviced", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
io_serviced_recursive: self io_serviced_recursive: self
.open_path("blkio.throttle.io_serviced_recursive", false) .open_path("blkio.throttle.io_serviced_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service) .and_then(parse_io_service)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_serviced_recursive_total: self io_serviced_recursive_total: self
.open_path("blkio.throttle.io_serviced_recursive", false) .open_path("blkio.throttle.io_serviced_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_io_service_total) .and_then(parse_io_service_total)
.unwrap_or(0), .unwrap_or_default(),
read_bps_device: self read_bps_device: self
.open_path("blkio.throttle.read_bps_device", false) .open_path("blkio.throttle.read_bps_device", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_blkio_data) .and_then(parse_blkio_data)
.unwrap_or(Vec::new()), .unwrap_or_default(),
read_iops_device: self read_iops_device: self
.open_path("blkio.throttle.read_iops_device", false) .open_path("blkio.throttle.read_iops_device", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_blkio_data) .and_then(parse_blkio_data)
.unwrap_or(Vec::new()), .unwrap_or_default(),
write_bps_device: self write_bps_device: self
.open_path("blkio.throttle.write_bps_device", false) .open_path("blkio.throttle.write_bps_device", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_blkio_data) .and_then(parse_blkio_data)
.unwrap_or(Vec::new()), .unwrap_or_default(),
write_iops_device: self write_iops_device: self
.open_path("blkio.throttle.write_iops_device", false) .open_path("blkio.throttle.write_iops_device", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_blkio_data) .and_then(parse_blkio_data)
.unwrap_or(Vec::new()), .unwrap_or_default(),
}, },
time: self time: self
.open_path("blkio.time", false) .open_path("blkio.time", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_blkio_data) .and_then(parse_blkio_data)
.unwrap_or(Vec::new()), .unwrap_or_default(),
time_recursive: self time_recursive: self
.open_path("blkio.time_recursive", false) .open_path("blkio.time_recursive", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_blkio_data) .and_then(parse_blkio_data)
.unwrap_or(Vec::new()), .unwrap_or_default(),
weight: self weight: self
.open_path("blkio.weight", false) .open_path("blkio.weight", false)
.and_then(|file| read_u64_from(file)) .and_then(read_u64_from)
.unwrap_or(0u64), .unwrap_or(0u64),
weight_device: self weight_device: self
.open_path("blkio.weight_device", false) .open_path("blkio.weight_device", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_blkio_data) .and_then(parse_blkio_data)
.unwrap_or(Vec::new()), .unwrap_or_default(),
io_stat: Vec::new(), io_stat: Vec::new(),
} }
} }

View File

@@ -62,7 +62,7 @@ impl Cgroup {
/// Create this control group. /// Create this control group.
fn create(&self) { fn create(&self) {
if self.hier.v2() { if self.hier.v2() {
let _ret = create_v2_cgroup(self.hier.root().clone(), &self.path); let _ret = create_v2_cgroup(self.hier.root(), &self.path);
} else { } else {
for subsystem in &self.subsystems { for subsystem in &self.subsystems {
subsystem.to_controller().create(); subsystem.to_controller().create();
@@ -112,13 +112,11 @@ impl Cgroup {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
let cg = Cgroup { Cgroup {
path: path.to_str().unwrap().to_string(), path: path.to_str().unwrap().to_string(),
subsystems: subsystems, subsystems,
hier, hier,
}; }
cg
} }
/// Create a handle for a control group in the hierarchy `hier`, with name `path` and `relative_paths` /// Create a handle for a control group in the hierarchy `hier`, with name `path` and `relative_paths`
@@ -146,7 +144,7 @@ impl Cgroup {
let cn = x.controller_name(); let cn = x.controller_name();
if relative_paths.contains_key(&cn) { if relative_paths.contains_key(&cn) {
let rp = relative_paths.get(&cn).unwrap(); let rp = relative_paths.get(&cn).unwrap();
let valid_path = rp.trim_start_matches("/").to_string(); let valid_path = rp.trim_start_matches('/').to_string();
let mut p = PathBuf::from(valid_path); let mut p = PathBuf::from(valid_path);
p.push(path); p.push(path);
x.enter(p.as_ref()) x.enter(p.as_ref())
@@ -157,13 +155,11 @@ impl Cgroup {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
} }
let cg = Cgroup { Cgroup {
subsystems: subsystems, subsystems,
hier, hier,
path: path.to_str().unwrap().to_string(), path: path.to_str().unwrap().to_string(),
}; }
cg
} }
/// The list of subsystems that this control group supports. /// The list of subsystems that this control group supports.
@@ -179,8 +175,8 @@ impl Cgroup {
/// will change. /// will change.
pub fn delete(&self) -> Result<()> { pub fn delete(&self) -> Result<()> {
if self.v2() { if self.v2() {
if self.path != "" { if !self.path.is_empty() {
let mut p = self.hier.root().clone(); let mut p = self.hier.root();
p.push(self.path.clone()); p.push(self.path.clone());
return fs::remove_dir(p).map_err(|e| Error::with_cause(RemoveFailed, e)); return fs::remove_dir(p).map_err(|e| Error::with_cause(RemoveFailed, e));
} }
@@ -222,7 +218,7 @@ impl Cgroup {
/// let cpu: &CpuController = control_group.controller_of() /// let cpu: &CpuController = control_group.controller_of()
/// .expect("No cpu controller attached!"); /// .expect("No cpu controller attached!");
/// ``` /// ```
pub fn controller_of<'a, T>(self: &'a Self) -> Option<&'a T> pub fn controller_of<'a, T>(&'a self) -> Option<&'a T>
where where
&'a T: From<&'a Subsystem>, &'a T: From<&'a Subsystem>,
T: Controller + ControllIdentifier, T: Controller + ControllIdentifier,
@@ -249,7 +245,7 @@ impl Cgroup {
pub fn add_task(&self, pid: CgroupPid) -> Result<()> { pub fn add_task(&self, pid: CgroupPid) -> Result<()> {
if self.v2() { if self.v2() {
let subsystems = self.subsystems(); let subsystems = self.subsystems();
if subsystems.len() > 0 { if !subsystems.is_empty() {
let c = subsystems[0].to_controller(); let c = subsystems[0].to_controller();
c.add_task(&pid) c.add_task(&pid)
} else { } else {
@@ -291,7 +287,7 @@ impl Cgroup {
// Collect the tasks from all subsystems // Collect the tasks from all subsystems
let mut v = if self.v2() { let mut v = if self.v2() {
let subsystems = self.subsystems(); let subsystems = self.subsystems();
if subsystems.len() > 0 { if !subsystems.is_empty() {
let c = subsystems[0].to_controller(); let c = subsystems[0].to_controller();
c.tasks() c.tasks()
} else { } else {
@@ -313,11 +309,10 @@ impl Cgroup {
} }
} }
pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; pub const UNIFIED_MOUNTPOINT: &str = "/sys/fs/cgroup";
fn enable_controllers(controllers: &Vec<String>, path: &PathBuf) { fn enable_controllers(controllers: &[String], path: &Path) {
let mut f = path.clone(); let f = path.join("cgroup.subtree_control");
f.push("cgroup.subtree_control");
for c in controllers { for c in controllers {
let body = format!("+{}", c); let body = format!("+{}", c);
let _rest = fs::write(f.as_path(), body.as_bytes()); let _rest = fs::write(f.as_path(), body.as_bytes());
@@ -327,8 +322,8 @@ fn enable_controllers(controllers: &Vec<String>, path: &PathBuf) {
fn supported_controllers() -> 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_default()
.split(" ") .split(' ')
.map(|x| x.to_string()) .map(|x| x.to_string())
.collect::<Vec<String>>() .collect::<Vec<String>>()
} }
@@ -342,16 +337,15 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> {
enable_controllers(&controllers, &fp); enable_controllers(&controllers, &fp);
// path: "a/b/c" // path: "a/b/c"
let elements = path.split("/").collect::<Vec<&str>>(); let elements = path.split('/').collect::<Vec<&str>>();
let last_index = elements.len() - 1; let last_index = elements.len() - 1;
for (i, ele) in elements.iter().enumerate() { for (i, ele) in elements.iter().enumerate() {
// ROOT/a // ROOT/a
fp.push(ele); fp.push(ele);
// create dir, need not check if is a file or directory // create dir, need not check if is a file or directory
if !fp.exists() { if !fp.exists() {
match ::std::fs::create_dir(fp.clone()) { if let Err(e) = std::fs::create_dir(fp.clone()) {
Err(e) => return Err(Error::with_cause(ErrorKind::FsError, e)), return Err(Error::with_cause(ErrorKind::FsError, e));
Ok(_) => {}
} }
} }

View File

@@ -240,10 +240,10 @@ impl DeviceResourceBuilder {
access: Vec<crate::devices::DevicePermissions>, access: Vec<crate::devices::DevicePermissions>,
) -> DeviceResourceBuilder { ) -> DeviceResourceBuilder {
self.cgroup.resources.devices.devices.push(DeviceResource { self.cgroup.resources.devices.devices.push(DeviceResource {
allow,
devtype,
major, major,
minor, minor,
devtype,
allow,
access, access,
}); });
self self

View File

@@ -45,7 +45,7 @@ pub struct Cpu {
/// The current state of the control group and its processes. /// The current state of the control group and its processes.
#[derive(Debug)] #[derive(Debug)]
struct CFSQuotaAndPeriod { struct CfsQuotaAndPeriod {
quota: MaxValue, quota: MaxValue,
period: u64, period: u64,
} }
@@ -116,7 +116,7 @@ impl CpuController {
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,
v2: v2, v2,
} }
} }
@@ -133,7 +133,7 @@ impl CpuController {
Err(e) => Err(Error::with_cause(ReadFailed, e)), Err(e) => Err(Error::with_cause(ReadFailed, e)),
} }
}) })
.unwrap_or("".to_string()), .unwrap_or_default(),
} }
} }
@@ -284,7 +284,7 @@ impl CpuController {
impl CustomizedAttribute for 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)
.map_err(|e| Error::with_cause(ReadFailed, e))?; .map_err(|e| Error::with_cause(ReadFailed, e))?;
@@ -299,8 +299,5 @@ fn parse_cfs_quota_and_period(mut file: File) -> Result<CFSQuotaAndPeriod> {
.parse::<u64>() .parse::<u64>()
.map_err(|e| Error::with_cause(ParseError, e))?; .map_err(|e| Error::with_cause(ParseError, e))?;
Ok(CFSQuotaAndPeriod { Ok(CfsQuotaAndPeriod { quota, period })
quota: quota,
period: period,
})
} }

View File

@@ -111,35 +111,35 @@ impl CpuAcctController {
CpuAcct { CpuAcct {
stat: self stat: self
.open_path("cpuacct.stat", false) .open_path("cpuacct.stat", false)
.and_then(|file| read_string_from(file)) .and_then(read_string_from)
.unwrap_or("".to_string()), .unwrap_or_default(),
usage: self usage: self
.open_path("cpuacct.usage", false) .open_path("cpuacct.usage", false)
.and_then(|file| read_u64_from(file)) .and_then(read_u64_from)
.unwrap_or(0), .unwrap_or(0),
usage_all: self usage_all: self
.open_path("cpuacct.usage_all", false) .open_path("cpuacct.usage_all", false)
.and_then(|file| read_string_from(file)) .and_then(read_string_from)
.unwrap_or("".to_string()), .unwrap_or_default(),
usage_percpu: self usage_percpu: self
.open_path("cpuacct.usage_percpu", false) .open_path("cpuacct.usage_percpu", false)
.and_then(|file| read_string_from(file)) .and_then(read_string_from)
.unwrap_or("".to_string()), .unwrap_or_default(),
usage_percpu_sys: self usage_percpu_sys: self
.open_path("cpuacct.usage_percpu_sys", false) .open_path("cpuacct.usage_percpu_sys", false)
.and_then(|file| read_string_from(file)) .and_then(read_string_from)
.unwrap_or("".to_string()), .unwrap_or_default(),
usage_percpu_user: self usage_percpu_user: self
.open_path("cpuacct.usage_percpu_user", false) .open_path("cpuacct.usage_percpu_user", false)
.and_then(|file| read_string_from(file)) .and_then(read_string_from)
.unwrap_or("".to_string()), .unwrap_or_default(),
usage_sys: self usage_sys: self
.open_path("cpuacct.usage_sys", false) .open_path("cpuacct.usage_sys", false)
.and_then(|file| read_u64_from(file)) .and_then(read_u64_from)
.unwrap_or(0), .unwrap_or(0),
usage_user: self usage_user: self
.open_path("cpuacct.usage_user", false) .open_path("cpuacct.usage_user", false)
.and_then(|file| read_u64_from(file)) .and_then(read_u64_from)
.unwrap_or(0), .unwrap_or(0),
} }
} }

View File

@@ -146,7 +146,7 @@ fn find_no_empty_parent(from: &str, file: &str) -> Result<(String, Vec<PathBuf>)
Err(e) => return Err(Error::with_cause(ReadFailed, e)), Err(e) => return Err(Error::with_cause(ReadFailed, e)),
}; };
if current_value != "" { if !current_value.is_empty() {
return Ok((current_value, v)); return Ok((current_value, v));
} }
v.push(current_path.clone()); v.push(current_path.clone());
@@ -167,7 +167,7 @@ fn copy_from_parent(current: &str, file: &str) -> Result<()> {
// find not empty cpus/memes from current directory. // find not empty cpus/memes from current directory.
let (value, parents) = find_no_empty_parent(current, file)?; let (value, parents) = find_no_empty_parent(current, file)?;
if value == "" || parents.len() == 0 { if value.is_empty() || parents.is_empty() {
return Ok(()); return Ok(());
} }
@@ -208,17 +208,17 @@ impl<'a> From<&'a Subsystem> for &'a CpuSetController {
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();
if s == "".to_string() { if s.is_empty() {
return Ok(fin); return Ok(fin);
} }
// first split by commas // first split by commas
let comma_split = s.split(","); let comma_split = s.split(',');
for sp in comma_split { for sp in comma_split {
if sp.contains("-") { if sp.contains('-') {
// this is a true range // this is a true range
let dash_split = sp.split("-").collect::<Vec<_>>(); let dash_split = sp.split('-').collect::<Vec<_>>();
if dash_split.len() != 2 { if dash_split.len() != 2 {
return Err(Error::new(ParseError)); return Err(Error::new(ParseError));
} }
@@ -247,7 +247,7 @@ impl CpuSetController {
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,
v2: v2, v2,
} }
} }
@@ -257,7 +257,7 @@ impl CpuSetController {
CpuSet { CpuSet {
cpu_exclusive: { cpu_exclusive: {
self.open_path("cpuset.cpu_exclusive", false) self.open_path("cpuset.cpu_exclusive", false)
.and_then(|file| read_u64_from(file)) .and_then(read_u64_from)
.map(|x| x == 1) .map(|x| x == 1)
.unwrap_or(false) .unwrap_or(false)
}, },
@@ -265,19 +265,19 @@ impl CpuSetController {
self.open_path("cpuset.cpus", false) self.open_path("cpuset.cpus", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_range) .and_then(parse_range)
.unwrap_or(Vec::new()) .unwrap_or_default()
}, },
effective_cpus: { effective_cpus: {
self.open_path("cpuset.effective_cpus", false) self.open_path("cpuset.effective_cpus", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_range) .and_then(parse_range)
.unwrap_or(Vec::new()) .unwrap_or_default()
}, },
effective_mems: { effective_mems: {
self.open_path("cpuset.effective_mems", false) self.open_path("cpuset.effective_mems", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_range) .and_then(parse_range)
.unwrap_or(Vec::new()) .unwrap_or_default()
}, },
mem_exclusive: { mem_exclusive: {
self.open_path("cpuset.mem_exclusive", false) self.open_path("cpuset.mem_exclusive", false)
@@ -324,7 +324,7 @@ impl CpuSetController {
self.open_path("cpuset.mems", false) self.open_path("cpuset.mems", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_range) .and_then(parse_range)
.unwrap_or(Vec::new()) .unwrap_or_default()
}, },
sched_load_balance: { sched_load_balance: {
self.open_path("cpuset.sched_load_balance", false) self.open_path("cpuset.sched_load_balance", false)

View File

@@ -49,6 +49,7 @@ impl Default for DeviceType {
impl DeviceType { impl DeviceType {
/// Convert a DeviceType into the character that the kernel recognizes. /// Convert a DeviceType into the character that the kernel recognizes.
#[allow(clippy::should_implement_trait, clippy::wrong_self_convention)]
pub fn to_char(&self) -> char { pub fn to_char(&self) -> char {
match self { match self {
DeviceType::All => 'a', DeviceType::All => 'a',
@@ -82,6 +83,7 @@ pub enum DevicePermissions {
impl DevicePermissions { impl DevicePermissions {
/// Convert a DevicePermissions into the character that the kernel recognizes. /// Convert a DevicePermissions into the character that the kernel recognizes.
#[allow(clippy::should_implement_trait, clippy::wrong_self_convention)]
pub fn to_char(&self) -> char { pub fn to_char(&self) -> char {
match self { match self {
DevicePermissions::Read => 'r', DevicePermissions::Read => 'r',
@@ -102,7 +104,7 @@ impl DevicePermissions {
/// Checks whether the string is a valid descriptor of DevicePermissions. /// Checks whether the string is a valid descriptor of DevicePermissions.
pub fn is_valid(s: &str) -> bool { pub fn is_valid(s: &str) -> bool {
if s == "" { if s.is_empty() {
return false; return false;
} }
for i in s.chars() { for i in s.chars() {
@@ -110,7 +112,7 @@ impl DevicePermissions {
return false; return false;
} }
} }
return true; true
} }
/// Returns a Vec will all the permissions that a device can have. /// Returns a Vec will all the permissions that a device can have.
@@ -123,9 +125,10 @@ impl DevicePermissions {
} }
/// Convert a string into DevicePermissions. /// Convert a string into DevicePermissions.
#[allow(clippy::should_implement_trait)]
pub fn from_str(s: &str) -> Result<Vec<DevicePermissions>> { pub fn from_str(s: &str) -> Result<Vec<DevicePermissions>> {
let mut v = Vec::new(); let mut v = Vec::new();
if s == "" { if s.is_empty() {
return Ok(v); return Ok(v);
} }
for e in s.chars() { for e in s.chars() {
@@ -206,7 +209,7 @@ impl DevicesController {
devtype: DeviceType, devtype: DeviceType,
major: i64, major: i64,
minor: i64, minor: i64,
perm: &Vec<DevicePermissions>, perm: &[DevicePermissions],
) -> Result<()> { ) -> Result<()> {
let perms = perm let perms = perm
.iter() .iter()
@@ -238,7 +241,7 @@ impl DevicesController {
devtype: DeviceType, devtype: DeviceType,
major: i64, major: i64,
minor: i64, minor: i64,
perm: &Vec<DevicePermissions>, perm: &[DevicePermissions],
) -> Result<()> { ) -> Result<()> {
let perms = perm let perms = perm
.iter() .iter()
@@ -274,13 +277,13 @@ impl DevicesController {
error!("allowed_devices: acc: {:?}, ls: {:?}", acc, ls); error!("allowed_devices: acc: {:?}, ls: {:?}", acc, ls);
Err(Error::new(ParseError)) Err(Error::new(ParseError))
} else { } else {
let devtype = DeviceType::from_char(ls[0].chars().nth(0)); let devtype = DeviceType::from_char(ls[0].chars().next());
let mut major = ls[1].parse::<i64>(); let mut major = ls[1].parse::<i64>();
let mut minor = ls[2].parse::<i64>(); let mut minor = ls[2].parse::<i64>();
if major.is_err() && ls[1] == "*".to_string() { if major.is_err() && ls[1] == "*" {
major = Ok(-1); major = Ok(-1);
} }
if minor.is_err() && ls[2] == "*".to_string() { if minor.is_err() && ls[2] == "*" {
minor = Ok(-1); minor = Ok(-1);
} }
if devtype.is_none() || major.is_err() || minor.is_err() || !DevicePermissions::is_valid(&ls[3]) { if devtype.is_none() || major.is_err() || minor.is_err() || !DevicePermissions::is_valid(&ls[3]) {
@@ -295,7 +298,7 @@ impl DevicesController {
devtype: devtype.unwrap(), devtype: devtype.unwrap(),
major: major.unwrap(), major: major.unwrap(),
minor: minor.unwrap(), minor: minor.unwrap(),
access: access, access,
}); });
Ok(acc) Ok(acc)
} }

View File

@@ -76,6 +76,7 @@ impl fmt::Display for Error {
impl StdError for Error { impl StdError for Error {
fn cause(&self) -> Option<&dyn StdError> { fn cause(&self) -> Option<&dyn StdError> {
#[allow(clippy::manual_map)]
match self.cause { match self.cause {
Some(ref x) => Some(&**x), Some(ref x) => Some(&**x),
None => None, None => None,

View File

@@ -8,7 +8,7 @@ use nix::sys::eventfd;
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::Read; use std::io::Read;
use std::os::unix::io::{AsRawFd, FromRawFd}; use std::os::unix::io::{AsRawFd, FromRawFd};
use std::path::{Path, PathBuf}; use std::path::Path;
use std::sync::mpsc::{self, Receiver}; use std::sync::mpsc::{self, Receiver};
use std::thread; use std::thread;
@@ -17,18 +17,18 @@ use crate::error::*;
// notify_on_oom returns channel on which you can expect event about OOM, // notify_on_oom returns channel on which you can expect event about OOM,
// if process died without OOM this channel will be closed. // if process died without OOM this channel will be closed.
pub fn notify_on_oom_v2(key: &str, dir: &PathBuf) -> Result<Receiver<String>> { pub fn notify_on_oom_v2(key: &str, dir: &Path) -> Result<Receiver<String>> {
register_memory_event(key, dir, "memory.oom_control", "") register_memory_event(key, dir, "memory.oom_control", "")
} }
// notify_on_oom returns channel on which you can expect event about OOM, // notify_on_oom returns channel on which you can expect event about OOM,
// if process died without OOM this channel will be closed. // if process died without OOM this channel will be closed.
pub fn notify_on_oom_v1(key: &str, dir: &PathBuf) -> Result<Receiver<String>> { pub fn notify_on_oom_v1(key: &str, dir: &Path) -> Result<Receiver<String>> {
register_memory_event(key, dir, "memory.oom_control", "") register_memory_event(key, dir, "memory.oom_control", "")
} }
// level is one of "low", "medium", or "critical" // level is one of "low", "medium", or "critical"
pub fn notify_memory_pressure(key: &str, dir: &PathBuf, level: &str) -> Result<Receiver<String>> { pub fn notify_memory_pressure(key: &str, dir: &Path, level: &str) -> Result<Receiver<String>> {
if level != "low" && level != "medium" && level != "critical" { if level != "low" && level != "medium" && level != "critical" {
return Err(Error::from_string(format!( return Err(Error::from_string(format!(
"invalid pressure level {}", "invalid pressure level {}",
@@ -41,7 +41,7 @@ pub fn notify_memory_pressure(key: &str, dir: &PathBuf, level: &str) -> Result<R
fn register_memory_event( fn register_memory_event(
key: &str, key: &str,
cg_dir: &PathBuf, cg_dir: &Path,
event_name: &str, event_name: &str,
arg: &str, arg: &str,
) -> Result<Receiver<String>> { ) -> Result<Receiver<String>> {
@@ -53,7 +53,7 @@ fn register_memory_event(
let event_control_path = cg_dir.join("cgroup.event_control"); let event_control_path = cg_dir.join("cgroup.event_control");
let data; let data;
if arg == "" { if arg.is_empty() {
data = format!("{} {}", eventfd, event_file.as_raw_fd()); data = format!("{} {}", eventfd, event_file.as_raw_fd());
} else { } else {
data = format!("{} {} {}", eventfd, event_file.as_raw_fd(), arg); data = format!("{} {} {}", eventfd, event_file.as_raw_fd(), arg);
@@ -70,11 +70,8 @@ fn register_memory_event(
thread::spawn(move || { thread::spawn(move || {
loop { loop {
let mut buf = [0; 8]; let mut buf = [0; 8];
match eventfd_file.read(&mut buf) { if eventfd_file.read(&mut buf).is_err() {
Err(_err) => { return;
return;
}
Ok(_) => {}
} }
// When a cgroup is destroyed, an event is sent to eventfd. // When a cgroup is destroyed, an event is sent to eventfd.

View File

@@ -87,7 +87,7 @@ impl FreezerController {
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,
v2: v2, v2,
} }
} }
@@ -130,7 +130,7 @@ impl FreezerController {
let mut s = String::new(); let mut s = String::new();
let res = file.read_to_string(&mut s); let res = file.read_to_string(&mut s);
match res { match res {
Ok(_) => match s.as_ref() { Ok(_) => match s.trim() {
"FROZEN" => Ok(FreezerState::Frozen), "FROZEN" => Ok(FreezerState::Frozen),
"THAWED" => Ok(FreezerState::Thawed), "THAWED" => Ok(FreezerState::Thawed),
"1" => Ok(FreezerState::Frozen), "1" => Ok(FreezerState::Frozen),

View File

@@ -35,7 +35,7 @@ use crate::cgroup::Cgroup;
/// Process mounts information. /// Process mounts information.
/// ///
/// See `proc(5)` for format details. /// See `proc(5)` for format details.
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Mountinfo { pub struct Mountinfo {
/// Mount pathname relative to the process's root. /// Mount pathname relative to the process's root.
pub mount_point: PathBuf, pub mount_point: PathBuf,
@@ -102,12 +102,12 @@ pub fn mountinfo_self() -> Vec<Mountinfo> {
} }
/// The standard, original cgroup implementation. Often referred to as "cgroupv1". /// The standard, original cgroup implementation. Often referred to as "cgroupv1".
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct V1 { pub struct V1 {
mountinfo: Vec<Mountinfo>, mountinfo: Vec<Mountinfo>,
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct V2 { pub struct V2 {
root: String, root: String,
} }
@@ -268,6 +268,12 @@ impl V1 {
} }
} }
impl Default for V1 {
fn default() -> Self {
Self::new()
}
}
impl V2 { impl V2 {
/// 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.
@@ -278,7 +284,13 @@ impl V2 {
} }
} }
pub const UNIFIED_MOUNTPOINT: &'static str = "/sys/fs/cgroup"; impl Default for V2 {
fn default() -> Self {
Self::new()
}
}
pub const UNIFIED_MOUNTPOINT: &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 {
@@ -294,7 +306,7 @@ pub fn is_cgroup2_unified_mode() -> bool {
fs_stat.unwrap().filesystem_type() == statfs::CGROUP2_SUPER_MAGIC fs_stat.unwrap().filesystem_type() == statfs::CGROUP2_SUPER_MAGIC
} }
pub const INIT_CGROUP_PATHS: &'static str = "/proc/1/cgroup"; pub const INIT_CGROUP_PATHS: &str = "/proc/1/cgroup";
#[cfg(all(target_os = "linux", target_env = "musl"))] #[cfg(all(target_os = "linux", target_env = "musl"))]
pub fn is_cgroup2_unified_mode() -> bool { pub fn is_cgroup2_unified_mode() -> bool {

View File

@@ -92,8 +92,8 @@ impl HugeTlbController {
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,
sizes: sizes, sizes,
v2: v2, v2,
} }
} }
@@ -115,7 +115,7 @@ impl HugeTlbController {
self.open_path(&format!("hugetlb.{}.events", hugetlb_size), false) self.open_path(&format!("hugetlb.{}.events", hugetlb_size), false)
.and_then(flat_keyed_to_vec) .and_then(flat_keyed_to_vec)
.and_then(|x| { .and_then(|x| {
if x.len() == 0 { if x.is_empty() {
return Err(Error::from_string(format!( return Err(Error::from_string(format!(
"get empty from hugetlb.{}.events", "get empty from hugetlb.{}.events",
hugetlb_size hugetlb_size
@@ -175,7 +175,7 @@ impl HugeTlbController {
} }
} }
pub const HUGEPAGESIZE_DIR: &'static str = "/sys/kernel/mm/hugepages"; pub const HUGEPAGESIZE_DIR: &str = "/sys/kernel/mm/hugepages";
use regex::Regex; use regex::Regex;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs; use std::fs;
@@ -264,8 +264,8 @@ fn parse_size(s: &str, m: &HashMap<String, u128>) -> Result<u128> {
let caps = re.unwrap().captures(s).unwrap(); let caps = re.unwrap().captures(s).unwrap();
let num = caps.name("num"); let num = caps.name("num");
let size: u128 = if num.is_some() { let size: u128 = if let Some(num) = num {
let n = num.unwrap().as_str().trim().parse::<u128>(); let n = num.as_str().trim().parse::<u128>();
if n.is_err() { if n.is_err() {
return Err(Error::new(InvalidBytesSize)); return Err(Error::new(InvalidBytesSize));
} }
@@ -275,10 +275,10 @@ fn parse_size(s: &str, m: &HashMap<String, u128>) -> Result<u128> {
}; };
let q = caps.name("mul"); let q = caps.name("mul");
let mul: u128 = if q.is_some() { let mul: u128 = if let Some(q) = q {
let t = m.get(q.unwrap().as_str()); let t = m.get(q.as_str());
if t.is_some() { if let Some(t) = t {
*t.unwrap() *t
} else { } else {
return Err(Error::new(InvalidBytesSize)); return Err(Error::new(InvalidBytesSize));
} }
@@ -289,7 +289,7 @@ fn parse_size(s: &str, m: &HashMap<String, u128>) -> Result<u128> {
Ok(size * mul) Ok(size * mul)
} }
fn custom_size(mut size: f64, base: f64, m: &Vec<String>) -> String { fn custom_size(mut size: f64, base: f64, m: &[String]) -> String {
let mut i = 0; let mut i = 0;
while size >= base && i < m.len() - 1 { while size >= base && i < m.len() - 1 {
size /= base; size /= base;

View File

@@ -4,9 +4,11 @@
// SPDX-License-Identifier: Apache-2.0 or MIT // SPDX-License-Identifier: Apache-2.0 or MIT
// //
#![allow(clippy::unnecessary_unwrap)]
use log::*; use log::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt;
use std::fs::{self, 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};
@@ -123,23 +125,23 @@ pub enum Controllers {
Systemd, Systemd,
} }
impl Controllers { impl fmt::Display for Controllers {
pub fn to_string(&self) -> String { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Controllers::Pids => return "pids".to_string(), Controllers::Pids => write!(f, "pids"),
Controllers::Mem => return "memory".to_string(), Controllers::Mem => write!(f, "memory"),
Controllers::CpuSet => return "cpuset".to_string(), Controllers::CpuSet => write!(f, "cpuset"),
Controllers::CpuAcct => return "cpuacct".to_string(), Controllers::CpuAcct => write!(f, "cpuacct"),
Controllers::Cpu => return "cpu".to_string(), Controllers::Cpu => write!(f, "cpu"),
Controllers::Devices => return "devices".to_string(), Controllers::Devices => write!(f, "devices"),
Controllers::Freezer => return "freezer".to_string(), Controllers::Freezer => write!(f, "freezer"),
Controllers::NetCls => return "net_cls".to_string(), Controllers::NetCls => write!(f, "net_cls"),
Controllers::BlkIo => return "blkio".to_string(), Controllers::BlkIo => write!(f, "blkio"),
Controllers::PerfEvent => return "perf_event".to_string(), Controllers::PerfEvent => write!(f, "perf_event"),
Controllers::NetPrio => return "net_prio".to_string(), Controllers::NetPrio => write!(f, "net_prio"),
Controllers::HugeTlb => return "hugetlb".to_string(), Controllers::HugeTlb => write!(f, "hugetlb"),
Controllers::Rdma => return "rdma".to_string(), Controllers::Rdma => write!(f, "rdma"),
Controllers::Systemd => return "name=systemd".to_string(), Controllers::Systemd => write!(f, "name=systemd"),
} }
} }
} }
@@ -179,13 +181,13 @@ mod sealed {
if w { if w {
match File::create(&path) { match File::create(&path) {
Err(e) => return Err(Error::with_cause(ErrorKind::WriteFailed, e)), Err(e) => Err(Error::with_cause(ErrorKind::WriteFailed, e)),
Ok(file) => return Ok(file), Ok(file) => Ok(file),
} }
} else { } else {
match File::open(&path) { match File::open(&path) {
Err(e) => return Err(Error::with_cause(ErrorKind::ReadFailed, e)), Err(e) => Err(Error::with_cause(ErrorKind::ReadFailed, e)),
Ok(file) => return Ok(file), Ok(file) => Ok(file),
} }
} }
} }
@@ -203,7 +205,7 @@ mod sealed {
#[doc(hidden)] #[doc(hidden)]
fn path_exists(&self, p: &str) -> bool { fn path_exists(&self, p: &str) -> bool {
if let Err(_) = self.verify_path() { if self.verify_path().is_err() {
return false; return false;
} }
@@ -295,7 +297,7 @@ where
/// Create this controller /// Create this controller
fn create(&self) { fn create(&self) {
self.verify_path() self.verify_path()
.expect(format!("path should be valid: {:?}", self.path()).as_str()); .unwrap_or_else(|_| panic!("path should be valid: {:?}", self.path()));
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(),
@@ -360,18 +362,16 @@ where
file = "cgroup.procs"; file = "cgroup.procs";
} }
self.open_path(file, false) self.open_path(file, false)
.and_then(|file| { .map(|file| {
let bf = BufReader::new(file); let bf = BufReader::new(file);
let mut v = Vec::new(); let mut v = Vec::new();
for line in bf.lines() { for line in bf.lines().flatten() {
if let Ok(line) = line { let n = line.trim().parse().unwrap_or(0u64);
let n = line.trim().parse().unwrap_or(0u64); v.push(n);
v.push(n);
}
} }
Ok(v.into_iter().map(CgroupPid::from).collect()) v.into_iter().map(CgroupPid::from).collect()
}) })
.unwrap_or(vec![]) .unwrap_or_default()
} }
fn v2(&self) -> bool { fn v2(&self) -> bool {
@@ -381,23 +381,21 @@ where
// remove_dir aims to remove cgroup path. It does so recursively, // remove_dir aims to remove cgroup path. It does so recursively,
// by removing any subdirectories (sub-cgroups) first. // by removing any subdirectories (sub-cgroups) first.
fn remove_dir(dir: &PathBuf) -> Result<()> { fn remove_dir(dir: &Path) -> Result<()> {
// try the fast path first. // try the fast path first.
if fs::remove_dir(dir).is_ok() { if fs::remove_dir(dir).is_ok() {
return Ok(()); return Ok(());
} }
if dir.exists() { if dir.exists() && dir.is_dir() {
if dir.is_dir() { for entry in fs::read_dir(dir).map_err(|e| Error::with_cause(ReadFailed, e))? {
for entry in fs::read_dir(dir).map_err(|e| Error::with_cause(ReadFailed, e))? { let entry = entry.map_err(|e| Error::with_cause(ReadFailed, e))?;
let entry = entry.map_err(|e| Error::with_cause(ReadFailed, e))?; let path = entry.path();
let path = entry.path(); if path.is_dir() {
if path.is_dir() { remove_dir(&path)?;
remove_dir(&path)?;
}
} }
fs::remove_dir(dir).map_err(|e| Error::with_cause(RemoveFailed, e))?;
} }
fs::remove_dir(dir).map_err(|e| Error::with_cause(RemoveFailed, e))?;
} }
Ok(()) Ok(())
@@ -641,75 +639,61 @@ impl<'a> From<&'a std::process::Child> for CgroupPid {
impl Subsystem { impl Subsystem {
fn enter(self, path: &Path) -> Self { fn enter(self, path: &Path) -> Self {
match self { match self {
Subsystem::Pid(cont) => Subsystem::Pid({ Subsystem::Pid(mut cont) => Subsystem::Pid({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::Mem(cont) => Subsystem::Mem({ Subsystem::Mem(mut cont) => Subsystem::Mem({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::CpuSet(cont) => Subsystem::CpuSet({ Subsystem::CpuSet(mut cont) => Subsystem::CpuSet({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::CpuAcct(cont) => Subsystem::CpuAcct({ Subsystem::CpuAcct(mut cont) => Subsystem::CpuAcct({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::Cpu(cont) => Subsystem::Cpu({ Subsystem::Cpu(mut cont) => Subsystem::Cpu({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::Devices(cont) => Subsystem::Devices({ Subsystem::Devices(mut cont) => Subsystem::Devices({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::Freezer(cont) => Subsystem::Freezer({ Subsystem::Freezer(mut cont) => Subsystem::Freezer({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::NetCls(cont) => Subsystem::NetCls({ Subsystem::NetCls(mut cont) => Subsystem::NetCls({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::BlkIo(cont) => Subsystem::BlkIo({ Subsystem::BlkIo(mut cont) => Subsystem::BlkIo({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::PerfEvent(cont) => Subsystem::PerfEvent({ Subsystem::PerfEvent(mut cont) => Subsystem::PerfEvent({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::NetPrio(cont) => Subsystem::NetPrio({ Subsystem::NetPrio(mut cont) => Subsystem::NetPrio({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::HugeTlb(cont) => Subsystem::HugeTlb({ Subsystem::HugeTlb(mut cont) => Subsystem::HugeTlb({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::Rdma(cont) => Subsystem::Rdma({ Subsystem::Rdma(mut cont) => Subsystem::Rdma({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
Subsystem::Systemd(cont) => Subsystem::Systemd({ Subsystem::Systemd(mut cont) => Subsystem::Systemd({
let mut c = cont.clone(); cont.get_path_mut().push(path);
c.get_path_mut().push(path); cont
c
}), }),
} }
} }
@@ -754,22 +738,25 @@ impl Default for MaxValue {
} }
impl MaxValue { impl MaxValue {
#[allow(clippy::should_implement_trait, clippy::wrong_self_convention)]
fn to_i64(&self) -> i64 { fn to_i64(&self) -> i64 {
match self { match self {
MaxValue::Max => -1, MaxValue::Max => -1,
MaxValue::Value(num) => *num, MaxValue::Value(num) => *num,
} }
} }
}
fn to_string(&self) -> String { impl fmt::Display for MaxValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
MaxValue::Max => "max".to_string(), MaxValue::Max => write!(f, "max"),
MaxValue::Value(num) => num.to_string(), MaxValue::Value(num) => write!(f, "{}", num.to_string()),
} }
} }
} }
pub fn parse_max_value(s: &String) -> Result<MaxValue> { pub fn parse_max_value(s: &str) -> Result<MaxValue> {
if s.trim() == "max" { if s.trim() == "max" {
return Ok(MaxValue::Max); return Ok(MaxValue::Max);
} }
@@ -791,11 +778,8 @@ pub fn flat_keyed_to_vec(mut file: File) -> Result<Vec<(String, i64)>> {
for line in content.lines() { for line in content.lines() {
let parts: Vec<&str> = line.split(' ').collect(); let parts: Vec<&str> = line.split(' ').collect();
if parts.len() == 2 { if parts.len() == 2 {
match parts[1].parse::<i64>() { if let Ok(i) = parts[1].parse::<i64>() {
Ok(i) => { v.push((parts[0].to_string(), i));
v.push((parts[0].to_string(), i));
}
Err(_) => {}
} }
} }
} }
@@ -814,11 +798,8 @@ pub fn flat_keyed_to_hashmap(mut file: File) -> Result<HashMap<String, i64>> {
for line in content.lines() { for line in content.lines() {
let parts: Vec<&str> = line.split(' ').collect(); let parts: Vec<&str> = line.split(' ').collect();
if parts.len() == 2 { if parts.len() == 2 {
match parts[1].parse::<i64>() { if let Ok(i) = parts[1].parse::<i64>() {
Ok(i) => { h.insert(parts[0].to_string(), i);
h.insert(parts[0].to_string(), i);
}
Err(_) => {}
} }
} }
} }
@@ -836,18 +817,15 @@ pub fn nested_keyed_to_hashmap(mut file: File) -> Result<HashMap<String, HashMap
let mut h = HashMap::new(); let mut h = HashMap::new();
for line in content.lines() { for line in content.lines() {
let parts: Vec<&str> = line.split(' ').collect(); let parts: Vec<&str> = line.split(' ').collect();
if parts.len() == 0 { if parts.is_empty() {
continue; continue;
} }
let mut th = HashMap::new(); let mut th = HashMap::new();
for item in parts[1..].into_iter() { for item in parts[1..].iter() {
let fields: Vec<&str> = item.split('=').collect(); let fields: Vec<&str> = item.split('=').collect();
if fields.len() == 2 { if fields.len() == 2 {
match fields[1].parse::<i64>() { if let Ok(i) = fields[1].parse::<i64>() {
Ok(i) => { th.insert(fields[0].to_string(), i);
th.insert(fields[0].to_string(), i);
}
Err(_) => {}
} }
} }
} }

View File

@@ -56,13 +56,32 @@ pub struct OomControl {
pub oom_kill: u64, pub oom_kill: u64,
} }
#[allow(clippy::unnecessary_wraps)]
fn parse_oom_control(s: String) -> Result<OomControl> { fn parse_oom_control(s: String) -> Result<OomControl> {
let spl = s.split_whitespace().collect::<Vec<_>>(); let spl = s.split_whitespace().collect::<Vec<_>>();
let oom_kill_disable = if spl.len() > 1 {
spl[1].parse::<u64>().unwrap() == 1
} else {
false
};
let under_oom = if spl.len() > 3 {
spl[3].parse::<u64>().unwrap() == 1
} else {
false
};
let oom_kill = if spl.len() > 5 {
spl[5].parse::<u64>().unwrap()
} else {
0
};
Ok(OomControl { Ok(OomControl {
oom_kill_disable: spl[1].parse::<u64>().unwrap() == 1, oom_kill_disable,
under_oom: spl[3].parse::<u64>().unwrap() == 1, under_oom,
oom_kill: spl[5].parse::<u64>().unwrap(), oom_kill,
}) })
} }
@@ -104,18 +123,19 @@ pub struct NumaStat {
pub hierarchical_unevictable_pages_per_node: Vec<u64>, pub hierarchical_unevictable_pages_per_node: Vec<u64>,
} }
#[allow(clippy::unnecessary_wraps)]
fn parse_numa_stat(s: String) -> Result<NumaStat> { fn parse_numa_stat(s: String) -> Result<NumaStat> {
// Parse the number of nodes // Parse the number of nodes
let _nodes = (s.split_whitespace().collect::<Vec<_>>().len() - 8) / 8; let _nodes = (s.split_whitespace().count() - 8) / 8;
let mut ls = s.lines(); let mut ls = s.lines();
let total_line = ls.next().unwrap(); let total_line = ls.next().unwrap();
let file_line = ls.next().unwrap(); let file_line = ls.next().unwrap();
let anon_line = ls.next().unwrap(); let anon_line = ls.next().unwrap();
let unevict_line = ls.next().unwrap(); let unevict_line = ls.next().unwrap();
let hier_total_line = ls.next().unwrap(); let hier_total_line = ls.next().unwrap_or_default();
let hier_file_line = ls.next().unwrap(); let hier_file_line = ls.next().unwrap_or_default();
let hier_anon_line = ls.next().unwrap(); let hier_anon_line = ls.next().unwrap_or_default();
let hier_unevict_line = ls.next().unwrap(); let hier_unevict_line = ls.next().unwrap_or_default();
Ok(NumaStat { Ok(NumaStat {
total_pages: total_line total_pages: total_line
@@ -124,10 +144,10 @@ fn parse_numa_stat(s: String) -> Result<NumaStat> {
.parse::<u64>() .parse::<u64>()
.unwrap_or(0), .unwrap_or(0),
total_pages_per_node: { total_pages_per_node: {
let spl = &total_line.split(" ").collect::<Vec<_>>()[1..]; let spl = &total_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter() spl.iter()
.map(|x| { .map(|x| {
x.split("=").collect::<Vec<_>>()[1] x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>() .parse::<u64>()
.unwrap_or(0) .unwrap_or(0)
}) })
@@ -139,10 +159,10 @@ fn parse_numa_stat(s: String) -> Result<NumaStat> {
.parse::<u64>() .parse::<u64>()
.unwrap_or(0), .unwrap_or(0),
file_pages_per_node: { file_pages_per_node: {
let spl = &file_line.split(" ").collect::<Vec<_>>()[1..]; let spl = &file_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter() spl.iter()
.map(|x| { .map(|x| {
x.split("=").collect::<Vec<_>>()[1] x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>() .parse::<u64>()
.unwrap_or(0) .unwrap_or(0)
}) })
@@ -154,10 +174,10 @@ fn parse_numa_stat(s: String) -> Result<NumaStat> {
.parse::<u64>() .parse::<u64>()
.unwrap_or(0), .unwrap_or(0),
anon_pages_per_node: { anon_pages_per_node: {
let spl = &anon_line.split(" ").collect::<Vec<_>>()[1..]; let spl = &anon_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter() spl.iter()
.map(|x| { .map(|x| {
x.split("=").collect::<Vec<_>>()[1] x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>() .parse::<u64>()
.unwrap_or(0) .unwrap_or(0)
}) })
@@ -169,74 +189,114 @@ fn parse_numa_stat(s: String) -> Result<NumaStat> {
.parse::<u64>() .parse::<u64>()
.unwrap_or(0), .unwrap_or(0),
unevictable_pages_per_node: { unevictable_pages_per_node: {
let spl = &unevict_line.split(" ").collect::<Vec<_>>()[1..]; let spl = &unevict_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter() spl.iter()
.map(|x| { .map(|x| {
x.split("=").collect::<Vec<_>>()[1] x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>() .parse::<u64>()
.unwrap_or(0) .unwrap_or(0)
}) })
.collect() .collect()
}, },
hierarchical_total_pages: hier_total_line hierarchical_total_pages: {
.split(|x| x == ' ' || x == '=') if !hier_total_line.is_empty() {
.collect::<Vec<_>>()[1] hier_total_line
.parse::<u64>() .split(|x| x == ' ' || x == '=')
.unwrap_or(0), .collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
} else {
0
}
},
hierarchical_total_pages_per_node: { hierarchical_total_pages_per_node: {
let spl = &hier_total_line.split(" ").collect::<Vec<_>>()[1..]; if !hier_total_line.is_empty() {
spl.iter() let spl = &hier_total_line.split(' ').collect::<Vec<_>>()[1..];
.map(|x| { spl.iter()
x.split("=").collect::<Vec<_>>()[1] .map(|x| {
.parse::<u64>() x.split('=').collect::<Vec<_>>()[1]
.unwrap_or(0) .parse::<u64>()
}) .unwrap_or(0)
.collect() })
.collect()
} else {
Vec::new()
}
},
hierarchical_file_pages: {
if !hier_file_line.is_empty() {
hier_file_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
} else {
0
}
}, },
hierarchical_file_pages: hier_file_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
hierarchical_file_pages_per_node: { hierarchical_file_pages_per_node: {
let spl = &hier_file_line.split(" ").collect::<Vec<_>>()[1..]; if !hier_file_line.is_empty() {
spl.iter() let spl = &hier_file_line.split(' ').collect::<Vec<_>>()[1..];
.map(|x| { spl.iter()
x.split("=").collect::<Vec<_>>()[1] .map(|x| {
.parse::<u64>() x.split('=').collect::<Vec<_>>()[1]
.unwrap_or(0) .parse::<u64>()
}) .unwrap_or(0)
.collect() })
.collect()
} else {
Vec::new()
}
},
hierarchical_anon_pages: {
if !hier_anon_line.is_empty() {
hier_anon_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
} else {
0
}
}, },
hierarchical_anon_pages: hier_anon_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
hierarchical_anon_pages_per_node: { hierarchical_anon_pages_per_node: {
let spl = &hier_anon_line.split(" ").collect::<Vec<_>>()[1..]; if !hier_anon_line.is_empty() {
spl.iter() let spl = &hier_anon_line.split(' ').collect::<Vec<_>>()[1..];
.map(|x| { spl.iter()
x.split("=").collect::<Vec<_>>()[1] .map(|x| {
.parse::<u64>() x.split('=').collect::<Vec<_>>()[1]
.unwrap_or(0) .parse::<u64>()
}) .unwrap_or(0)
.collect() })
.collect()
} else {
Vec::new()
}
},
hierarchical_unevictable_pages: {
if !hier_unevict_line.is_empty() {
hier_unevict_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
} else {
0
}
}, },
hierarchical_unevictable_pages: hier_unevict_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
hierarchical_unevictable_pages_per_node: { hierarchical_unevictable_pages_per_node: {
let spl = &hier_unevict_line.split(" ").collect::<Vec<_>>()[1..]; if !hier_unevict_line.is_empty() {
spl.iter() let spl = &hier_unevict_line.split(' ').collect::<Vec<_>>()[1..];
.map(|x| { spl.iter()
x.split("=").collect::<Vec<_>>()[1] .map(|x| {
.parse::<u64>() x.split('=').collect::<Vec<_>>()[1]
.unwrap_or(0) .parse::<u64>()
}) .unwrap_or(0)
.collect() })
.collect()
} else {
Vec::new()
}
}, },
}) })
} }
@@ -282,6 +342,7 @@ pub struct MemoryStat {
pub raw: HashMap<String, u64>, pub raw: HashMap<String, u64>,
} }
#[allow(clippy::unnecessary_wraps)]
fn parse_memory_stat(s: String) -> Result<MemoryStat> { fn parse_memory_stat(s: String) -> Result<MemoryStat> {
let mut raw = HashMap::new(); let mut raw = HashMap::new();
@@ -335,7 +396,7 @@ fn parse_memory_stat(s: String) -> Result<MemoryStat> {
total_inactive_file: *raw.get("total_inactive_file").unwrap_or(&0), total_inactive_file: *raw.get("total_inactive_file").unwrap_or(&0),
total_active_file: *raw.get("total_active_file").unwrap_or(&0), total_active_file: *raw.get("total_active_file").unwrap_or(&0),
total_unevictable: *raw.get("total_unevictable").unwrap_or(&0), total_unevictable: *raw.get("total_unevictable").unwrap_or(&0),
raw: raw, raw,
}) })
} }
@@ -474,7 +535,7 @@ impl MemController {
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,
v2: v2, v2,
} }
} }
@@ -489,8 +550,8 @@ impl MemController {
for value in values { for value in values {
let v = value.0; let v = value.0;
let f = value.1; let f = value.1;
if v.is_some() { if let Some(v) = v {
let v = v.unwrap().to_string(); let v = v.to_string();
self.open_path(f, true).and_then(|mut file| { self.open_path(f, true).and_then(|mut file| {
file.write_all(v.as_ref()) file.write_all(v.as_ref())
.map_err(|e| Error::with_cause(WriteFailed, e)) .map_err(|e| Error::with_cause(WriteFailed, e))
@@ -531,7 +592,7 @@ impl MemController {
.open_path("memory.stat", false) .open_path("memory.stat", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_memory_stat) .and_then(parse_memory_stat)
.unwrap_or(MemoryStat::default()), .unwrap_or_default(),
swappiness: self swappiness: self
.open_path("memory.swap.current", false) .open_path("memory.swap.current", false)
.and_then(read_u64_from) .and_then(read_u64_from)
@@ -575,12 +636,12 @@ impl MemController {
.open_path("memory.numa_stat", false) .open_path("memory.numa_stat", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_numa_stat) .and_then(parse_numa_stat)
.unwrap_or(NumaStat::default()), .unwrap_or_default(),
oom_control: self oom_control: self
.open_path("memory.oom_control", false) .open_path("memory.oom_control", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_oom_control) .and_then(parse_oom_control)
.unwrap_or(OomControl::default()), .unwrap_or_default(),
soft_limit_in_bytes: self soft_limit_in_bytes: self
.open_path("memory.soft_limit_in_bytes", false) .open_path("memory.soft_limit_in_bytes", false)
.and_then(read_i64_from) .and_then(read_i64_from)
@@ -589,7 +650,7 @@ impl MemController {
.open_path("memory.stat", false) .open_path("memory.stat", false)
.and_then(read_string_from) .and_then(read_string_from)
.and_then(parse_memory_stat) .and_then(parse_memory_stat)
.unwrap_or(MemoryStat::default()), .unwrap_or_default(),
swappiness: self swappiness: self
.open_path("memory.swappiness", false) .open_path("memory.swappiness", false)
.and_then(read_u64_from) .and_then(read_u64_from)
@@ -623,7 +684,7 @@ impl MemController {
slabinfo: self slabinfo: self
.open_path("memory.kmem.slabinfo", false) .open_path("memory.kmem.slabinfo", false)
.and_then(read_string_from) .and_then(read_string_from)
.unwrap_or("".to_string()), .unwrap_or_default(),
} }
} }
@@ -655,7 +716,7 @@ impl MemController {
fail_cnt: self fail_cnt: self
.open_path("memory.swap.events", false) .open_path("memory.swap.events", false)
.and_then(flat_keyed_to_hashmap) .and_then(flat_keyed_to_hashmap)
.and_then(|x| Ok(*x.get("fail").unwrap_or(&0) as u64)) .map(|x| *x.get("fail").unwrap_or(&0) as u64)
.unwrap(), .unwrap(),
limit_in_bytes: self limit_in_bytes: self
.open_path("memory.swap.max", false) .open_path("memory.swap.max", false)
@@ -878,6 +939,7 @@ 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,
}; };
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
@@ -889,7 +951,24 @@ hierarchical_anon=770402 N0=770402 N1=123
hierarchical_unevictable=20 N0=20 N1=123 hierarchical_unevictable=20 N0=20 N1=123
"; ";
static GOOD_OOMCONTROL_VAL: &str = "\ static GOOD_VALUE_NON_HIERARCHICAL: &str = "\
total=51189 N0=51189 N1=123
file=50175 N0=50175 N1=123
anon=1014 N0=1014 N1=123
unevictable=0 N0=0 N1=123
";
static GOOD_OOMCONTROL_VAL_1: &str = "\
oom_kill_disable 0
oom_kill 1337
";
static GOOD_OOMCONTROL_VAL_2: &str = "\
oom_kill_disable 0
under_oom 1
";
static GOOD_OOMCONTROL_VAL_3: &str = "\
oom_kill_disable 0 oom_kill_disable 0
under_oom 1 under_oom 1
oom_kill 1337 oom_kill 1337
@@ -959,11 +1038,61 @@ total_unevictable 81920
hierarchical_unevictable_pages_per_node: vec![20, 123], hierarchical_unevictable_pages_per_node: vec![20, 123],
} }
); );
let ok = parse_numa_stat(GOOD_VALUE_NON_HIERARCHICAL.to_string()).unwrap();
assert_eq!(
ok,
NumaStat {
total_pages: 51189,
total_pages_per_node: vec![51189, 123],
file_pages: 50175,
file_pages_per_node: vec![50175, 123],
anon_pages: 1014,
anon_pages_per_node: vec![1014, 123],
unevictable_pages: 0,
unevictable_pages_per_node: vec![0, 123],
hierarchical_total_pages: 0,
hierarchical_total_pages_per_node: vec![],
hierarchical_file_pages: 0,
hierarchical_file_pages_per_node: vec![],
hierarchical_anon_pages: 0,
hierarchical_anon_pages_per_node: vec![],
hierarchical_unevictable_pages: 0,
hierarchical_unevictable_pages_per_node: vec![],
}
);
} }
#[test] #[test]
fn test_parse_oom_control() { fn test_parse_oom_control() {
let ok = parse_oom_control(GOOD_OOMCONTROL_VAL.to_string()).unwrap(); let ok = parse_oom_control("".to_string()).unwrap();
assert_eq!(
ok,
OomControl {
oom_kill_disable: false,
under_oom: false,
oom_kill: 0,
}
);
let ok = parse_oom_control(GOOD_OOMCONTROL_VAL_1.to_string()).unwrap();
assert_eq!(
ok,
OomControl {
oom_kill_disable: false,
under_oom: false,
oom_kill: 0,
}
);
let ok = parse_oom_control(GOOD_OOMCONTROL_VAL_2.to_string()).unwrap();
assert_eq!(
ok,
OomControl {
oom_kill_disable: false,
under_oom: true,
oom_kill: 0,
}
);
let ok = parse_oom_control(GOOD_OOMCONTROL_VAL_3.to_string()).unwrap();
assert_eq!( assert_eq!(
ok, ok,
OomControl { OomControl {
@@ -1017,7 +1146,7 @@ total_unevictable 81920
total_inactive_file: 1272135680, total_inactive_file: 1272135680,
total_active_file: 2338816000, total_active_file: 2338816000,
total_unevictable: 81920, total_unevictable: 81920,
raw: raw, raw,
} }
); );
} }

View File

@@ -49,7 +49,7 @@ impl ControllerInternal for NetClsController {
update_and_test!(self, set_class, res.class_id, get_class); update_and_test!(self, set_class, res.class_id, get_class);
return Ok(()); Ok(())
} }
} }
@@ -96,6 +96,6 @@ impl NetClsController {
/// Get the network class id of the outgoing packets of the control group's tasks. /// Get the network class id of the outgoing packets of the control group's tasks.
pub fn get_class(&self) -> Result<u64> { pub fn get_class(&self) -> Result<u64> {
self.open_path("net_cls.classid", false) self.open_path("net_cls.classid", false)
.and_then(|file| read_u64_from(file)) .and_then(read_u64_from)
} }
} }

View File

@@ -94,6 +94,7 @@ impl NetPrioController {
} }
/// A map of priorities for each network interface. /// A map of priorities for each network interface.
#[allow(clippy::iter_nth_zero, clippy::unnecessary_unwrap)]
pub fn ifpriomap(&self) -> Result<HashMap<String, u64>> { pub fn ifpriomap(&self) -> Result<HashMap<String, u64>> {
self.open_path("net_prio.ifpriomap", false) self.open_path("net_prio.ifpriomap", false)
.and_then(|file| { .and_then(|file| {
@@ -105,6 +106,7 @@ impl NetPrioController {
let mut acc = acc.unwrap(); let mut acc = acc.unwrap();
let l = line.unwrap(); let l = line.unwrap();
let mut sp = l.split_whitespace(); let mut sp = l.split_whitespace();
let ifname = sp.nth(0); let ifname = sp.nth(0);
let ifprio = sp.nth(1); let ifprio = sp.nth(1);
if ifname.is_none() || ifprio.is_none() { if ifname.is_none() || ifprio.is_none() {

View File

@@ -96,7 +96,7 @@ impl PidController {
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,
v2: v2, v2,
} }
} }

View File

@@ -66,7 +66,7 @@ impl SystemdController {
Self { Self {
base: root.clone(), base: root.clone(),
path: root, path: root,
v2: v2, v2,
} }
} }
} }

View File

@@ -48,7 +48,7 @@ fn test_cgroup_with_relative_paths() {
let cg = Cgroup::load(h, String::from(cgroup_name)); 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.iter().for_each(|sub| match sub {
Subsystem::Pid(c) => { Subsystem::Pid(c) => {
let cgroup_path = c.path().to_str().unwrap(); let cgroup_path = c.path().to_str().unwrap();
let relative_path = "/pids/"; let relative_path = "/pids/";

View File

@@ -36,24 +36,23 @@ fn test_cpuset_set_cpus() {
assert_eq!(0, set.cpus.len()); assert_eq!(0, set.cpus.len());
} else { } else {
// for cgroup v1, cpuset is copied from parent. // for cgroup v1, cpuset is copied from parent.
assert_eq!(true, set.cpus.len() > 0); assert!(!set.cpus.is_empty());
} }
// 0 // 0
let r = cpuset.set_cpus("0"); let r = cpuset.set_cpus("0");
assert_eq!(true, r.is_ok()); assert!(r.is_ok());
let set = cpuset.cpuset(); let set = cpuset.cpuset();
assert_eq!(1, set.cpus.len()); assert_eq!(1, set.cpus.len());
assert_eq!((0, 0), set.cpus[0]); assert_eq!((0, 0), set.cpus[0]);
// all cpus in system // all cpus in system
let cpus = let cpus = fs::read_to_string("/sys/fs/cgroup/cpuset.cpus.effective").unwrap_or_default();
fs::read_to_string("/sys/fs/cgroup/cpuset.cpus.effective").unwrap_or("".to_string());
let cpus = cpus.trim(); let cpus = cpus.trim();
if cpus != "" { if !cpus.is_empty() {
let r = cpuset.set_cpus(&cpus); let r = cpuset.set_cpus(&cpus);
assert_eq!(true, r.is_ok()); assert!(r.is_ok());
let set = cpuset.cpuset(); let set = cpuset.cpuset();
assert_eq!(1, set.cpus.len()); assert_eq!(1, set.cpus.len());
assert_eq!(format!("{}-{}", set.cpus[0].0, set.cpus[0].1), cpus); assert_eq!(format!("{}-{}", set.cpus[0].0, set.cpus[0].1), cpus);
@@ -73,14 +72,14 @@ fn test_cpuset_set_cpus_add_task() {
assert_eq!(0, set.cpus.len()); assert_eq!(0, set.cpus.len());
} else { } else {
// for cgroup v1, cpuset is copied from parent. // for cgroup v1, cpuset is copied from parent.
assert_eq!(true, set.cpus.len() > 0); assert!(!set.cpus.is_empty());
} }
// Add a task to the control group. // Add a task to the control group.
let pid_i = libc::pid_t::from(nix::unistd::getpid()) as u64; let pid_i = libc::pid_t::from(nix::unistd::getpid()) as u64;
let _ = cg.add_task(CgroupPid::from(pid_i)); let _ = cg.add_task(CgroupPid::from(pid_i));
let tasks = cg.tasks(); let tasks = cg.tasks();
assert_eq!(true, tasks.len() > 0); assert!(!tasks.is_empty());
println!("tasks after added: {:?}", tasks); println!("tasks after added: {:?}", tasks);
// remove task // remove task

View File

@@ -27,7 +27,7 @@ fn test_devices_parsing() {
DeviceType::All, DeviceType::All,
-1, -1,
-1, -1,
&vec![ &[
DevicePermissions::Read, DevicePermissions::Read,
DevicePermissions::Write, DevicePermissions::Write,
DevicePermissions::MkNod, DevicePermissions::MkNod,
@@ -42,7 +42,7 @@ fn test_devices_parsing() {
// Now add mknod access to /dev/null device // Now add mknod access to /dev/null device
devices devices
.allow_device(DeviceType::Char, 1, 3, &vec![DevicePermissions::MkNod]) .allow_device(DeviceType::Char, 1, 3, &[DevicePermissions::MkNod])
.unwrap(); .unwrap();
let allowed_devices = devices.allowed_devices(); let allowed_devices = devices.allowed_devices();
assert!(allowed_devices.is_ok()); assert!(allowed_devices.is_ok());

View File

@@ -29,7 +29,7 @@ fn test_hugetlb_sizes() {
for size in sizes { for size in sizes {
let supported = hugetlb_controller.size_supported(&size); let supported = hugetlb_controller.size_supported(&size);
assert_eq!(supported, true); assert!(supported);
assert_no_error(hugetlb_controller.failcnt(&size)); assert_no_error(hugetlb_controller.failcnt(&size));
assert_no_error(hugetlb_controller.limit_in_bytes(&size)); assert_no_error(hugetlb_controller.limit_in_bytes(&size));
assert_no_error(hugetlb_controller.usage_in_bytes(&size)); assert_no_error(hugetlb_controller.usage_in_bytes(&size));
@@ -40,5 +40,5 @@ fn test_hugetlb_sizes() {
} }
fn assert_no_error(r: Result<u64>) { fn assert_no_error(r: Result<u64>) {
assert_eq!(!r.is_err(), true) assert!(!r.is_err())
} }

View File

@@ -17,17 +17,17 @@ fn test_disable_oom_killer() {
// before disable // before disable
let m = mem_controller.memory_stat(); let m = mem_controller.memory_stat();
assert_eq!(m.oom_control.oom_kill_disable, false); assert!(!m.oom_control.oom_kill_disable);
// now only v1 // now only v1
if !mem_controller.v2() { if !mem_controller.v2() {
// disable oom killer // disable oom killer
let r = mem_controller.disable_oom_killer(); let r = mem_controller.disable_oom_killer();
assert_eq!(r.is_err(), false); assert!(!r.is_err());
// after disable // after disable
let m = mem_controller.memory_stat(); let m = mem_controller.memory_stat();
assert_eq!(m.oom_control.oom_kill_disable, true); assert!(m.oom_control.oom_kill_disable);
} }
} }
cg.delete().unwrap(); cg.delete().unwrap();
@@ -60,7 +60,7 @@ fn set_mem_v2() {
max: None, max: None,
}; };
let r = mem_controller.set_mem(m); let r = mem_controller.set_mem(m);
assert_eq!(true, r.is_ok()); assert!(r.is_ok());
let m = mem_controller.get_mem().unwrap(); let m = mem_controller.get_mem().unwrap();
// get // get
@@ -77,7 +77,7 @@ fn set_mem_v2() {
low: None, low: None,
}; };
let r = mem_controller.set_mem(m); let r = mem_controller.set_mem(m);
assert_eq!(true, r.is_ok()); assert!(r.is_ok());
let m = mem_controller.get_mem().unwrap(); let m = mem_controller.get_mem().unwrap();
// get // get

View File

@@ -62,7 +62,7 @@ fn test_pid_events_is_not_zero() {
let before = pids.get_pid_events(); let before = pids.get_pid_events();
let before = before.unwrap(); let before = before.unwrap();
match fork() { match unsafe { fork() } {
Ok(ForkResult::Parent { child, .. }) => { Ok(ForkResult::Parent { child, .. }) => {
// move the process into the control group // move the process into the control group
let _ = pids.add_task(&(pid_t::from(child) as u64).into()); let _ = pids.add_task(&(pid_t::from(child) as u64).into());
@@ -89,7 +89,7 @@ fn test_pid_events_is_not_zero() {
Ok(ForkResult::Child) => loop { Ok(ForkResult::Child) => loop {
let pids_max = pids.get_pid_max(); let pids_max = pids.get_pid_max();
if pids_max.is_ok() && pids_max.unwrap() == MaxValue::Value(1) { if pids_max.is_ok() && pids_max.unwrap() == MaxValue::Value(1) {
if let Err(_) = fork() { if unsafe { fork() }.is_err() {
unsafe { libc::exit(0) }; unsafe { libc::exit(0) };
} else { } else {
unsafe { libc::exit(1) }; unsafe { libc::exit(1) };

View File

@@ -24,7 +24,7 @@ fn pid_resources() {
// verify // verify
let pidcontroller: &PidController = cg.controller_of().unwrap(); let pidcontroller: &PidController = cg.controller_of().unwrap();
let pid_max = pidcontroller.get_pid_max(); let pid_max = pidcontroller.get_pid_max();
assert_eq!(pid_max.is_ok(), true); assert!(pid_max.is_ok());
assert_eq!(pid_max.unwrap(), MaxValue::Value(512)); assert_eq!(pid_max.unwrap(), MaxValue::Value(512));
} }
cg.delete().unwrap(); cg.delete().unwrap();