Compare commits

...

11 Commits

Author SHA1 Message Date
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
22 changed files with 478 additions and 362 deletions

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.4"
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,9 +309,9 @@ 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: &PathBuf) {
let mut f = path.clone(); let mut f = path.clone();
f.push("cgroup.subtree_control"); f.push("cgroup.subtree_control");
for c in controllers { for c in controllers {
@@ -327,8 +323,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 +338,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

@@ -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(),
} }
} }
@@ -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

@@ -102,7 +102,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 +110,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 +123,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 +207,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 +239,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 +275,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 +296,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

@@ -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,
} }
} }

View File

@@ -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,7 +362,7 @@ 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() {
@@ -369,9 +371,9 @@ where
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 {
@@ -387,17 +389,15 @@ fn remove_dir(dir: &PathBuf) -> Result<()> {
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 +641,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
}), }),
} }
} }
@@ -760,16 +746,18 @@ impl MaxValue {
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 +779,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 +799,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 +818,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,7 +36,7 @@ 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_eq!(true, !set.cpus.is_empty());
} }
// 0 // 0
@@ -48,10 +48,9 @@ fn test_cpuset_set_cpus() {
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_eq!(true, r.is_ok());
let set = cpuset.cpuset(); let set = cpuset.cpuset();
@@ -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_eq!(true, !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_eq!(true, !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

@@ -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) };