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
- run: rustup component add rustfmt
- 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:
name: Run Unit Test
runs-on: ubuntu-latest
@@ -24,3 +31,4 @@ jobs:
- uses: actions/checkout@v2
- run: make test

View File

@@ -5,7 +5,7 @@ repository = "https://github.com/kata-containers/cgroups-rs"
keywords = ["linux", "cgroup", "containers", "isolation"]
categories = ["os", "api-bindings", "os::unix-apis"]
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>"]
edition = "2018"
homepage = "https://github.com/kata-containers/cgroups-rs"
@@ -14,7 +14,7 @@ readme = "README.md"
[dependencies]
log = "0.4"
regex = "1.1"
nix = "0.18.0"
nix = "0.20.0"
libc = "0.2"
[dev-dependencies]

View File

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

View File

@@ -62,7 +62,7 @@ impl Cgroup {
/// Create this control group.
fn create(&self) {
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 {
for subsystem in &self.subsystems {
subsystem.to_controller().create();
@@ -112,13 +112,11 @@ impl Cgroup {
.collect::<Vec<_>>();
}
let cg = Cgroup {
Cgroup {
path: path.to_str().unwrap().to_string(),
subsystems: subsystems,
subsystems,
hier,
};
cg
}
}
/// 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();
if relative_paths.contains_key(&cn) {
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);
p.push(path);
x.enter(p.as_ref())
@@ -157,13 +155,11 @@ impl Cgroup {
.collect::<Vec<_>>();
}
let cg = Cgroup {
subsystems: subsystems,
Cgroup {
subsystems,
hier,
path: path.to_str().unwrap().to_string(),
};
cg
}
}
/// The list of subsystems that this control group supports.
@@ -179,8 +175,8 @@ impl Cgroup {
/// will change.
pub fn delete(&self) -> Result<()> {
if self.v2() {
if self.path != "" {
let mut p = self.hier.root().clone();
if !self.path.is_empty() {
let mut p = self.hier.root();
p.push(self.path.clone());
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()
/// .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
&'a T: From<&'a Subsystem>,
T: Controller + ControllIdentifier,
@@ -249,7 +245,7 @@ impl Cgroup {
pub fn add_task(&self, pid: CgroupPid) -> Result<()> {
if self.v2() {
let subsystems = self.subsystems();
if subsystems.len() > 0 {
if !subsystems.is_empty() {
let c = subsystems[0].to_controller();
c.add_task(&pid)
} else {
@@ -291,7 +287,7 @@ impl Cgroup {
// Collect the tasks from all subsystems
let mut v = if self.v2() {
let subsystems = self.subsystems();
if subsystems.len() > 0 {
if !subsystems.is_empty() {
let c = subsystems[0].to_controller();
c.tasks()
} 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) {
let mut f = path.clone();
f.push("cgroup.subtree_control");
fn enable_controllers(controllers: &[String], path: &Path) {
let f = path.join("cgroup.subtree_control");
for c in controllers {
let body = format!("+{}", c);
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> {
let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers");
let ret = fs::read_to_string(p.as_str());
ret.unwrap_or(String::new())
.split(" ")
ret.unwrap_or_default()
.split(' ')
.map(|x| x.to_string())
.collect::<Vec<String>>()
}
@@ -342,16 +337,15 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> {
enable_controllers(&controllers, &fp);
// path: "a/b/c"
let elements = path.split("/").collect::<Vec<&str>>();
let elements = path.split('/').collect::<Vec<&str>>();
let last_index = elements.len() - 1;
for (i, ele) in elements.iter().enumerate() {
// ROOT/a
fp.push(ele);
// create dir, need not check if is a file or directory
if !fp.exists() {
match ::std::fs::create_dir(fp.clone()) {
Err(e) => return Err(Error::with_cause(ErrorKind::FsError, e)),
Ok(_) => {}
if let Err(e) = std::fs::create_dir(fp.clone()) {
return Err(Error::with_cause(ErrorKind::FsError, e));
}
}

View File

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

View File

@@ -45,7 +45,7 @@ pub struct Cpu {
/// The current state of the control group and its processes.
#[derive(Debug)]
struct CFSQuotaAndPeriod {
struct CfsQuotaAndPeriod {
quota: MaxValue,
period: u64,
}
@@ -116,7 +116,7 @@ impl CpuController {
Self {
base: root.clone(),
path: root,
v2: v2,
v2,
}
}
@@ -133,7 +133,7 @@ impl CpuController {
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 {}
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();
file.read_to_string(&mut content)
.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>()
.map_err(|e| Error::with_cause(ParseError, e))?;
Ok(CFSQuotaAndPeriod {
quota: quota,
period: period,
})
Ok(CfsQuotaAndPeriod { quota, period })
}

View File

@@ -111,35 +111,35 @@ impl CpuAcctController {
CpuAcct {
stat: self
.open_path("cpuacct.stat", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
.and_then(read_string_from)
.unwrap_or_default(),
usage: self
.open_path("cpuacct.usage", false)
.and_then(|file| read_u64_from(file))
.and_then(read_u64_from)
.unwrap_or(0),
usage_all: self
.open_path("cpuacct.usage_all", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
.and_then(read_string_from)
.unwrap_or_default(),
usage_percpu: self
.open_path("cpuacct.usage_percpu", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
.and_then(read_string_from)
.unwrap_or_default(),
usage_percpu_sys: self
.open_path("cpuacct.usage_percpu_sys", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
.and_then(read_string_from)
.unwrap_or_default(),
usage_percpu_user: self
.open_path("cpuacct.usage_percpu_user", false)
.and_then(|file| read_string_from(file))
.unwrap_or("".to_string()),
.and_then(read_string_from)
.unwrap_or_default(),
usage_sys: self
.open_path("cpuacct.usage_sys", false)
.and_then(|file| read_u64_from(file))
.and_then(read_u64_from)
.unwrap_or(0),
usage_user: self
.open_path("cpuacct.usage_user", false)
.and_then(|file| read_u64_from(file))
.and_then(read_u64_from)
.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)),
};
if current_value != "" {
if !current_value.is_empty() {
return Ok((current_value, v));
}
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.
let (value, parents) = find_no_empty_parent(current, file)?;
if value == "" || parents.len() == 0 {
if value.is_empty() || parents.is_empty() {
return Ok(());
}
@@ -208,17 +208,17 @@ impl<'a> From<&'a Subsystem> for &'a CpuSetController {
fn parse_range(s: String) -> Result<Vec<(u64, u64)>> {
let mut fin = Vec::new();
if s == "".to_string() {
if s.is_empty() {
return Ok(fin);
}
// first split by commas
let comma_split = s.split(",");
let comma_split = s.split(',');
for sp in comma_split {
if sp.contains("-") {
if sp.contains('-') {
// this is a true range
let dash_split = sp.split("-").collect::<Vec<_>>();
let dash_split = sp.split('-').collect::<Vec<_>>();
if dash_split.len() != 2 {
return Err(Error::new(ParseError));
}
@@ -247,7 +247,7 @@ impl CpuSetController {
Self {
base: root.clone(),
path: root,
v2: v2,
v2,
}
}
@@ -257,7 +257,7 @@ impl CpuSetController {
CpuSet {
cpu_exclusive: {
self.open_path("cpuset.cpu_exclusive", false)
.and_then(|file| read_u64_from(file))
.and_then(read_u64_from)
.map(|x| x == 1)
.unwrap_or(false)
},
@@ -265,19 +265,19 @@ impl CpuSetController {
self.open_path("cpuset.cpus", false)
.and_then(read_string_from)
.and_then(parse_range)
.unwrap_or(Vec::new())
.unwrap_or_default()
},
effective_cpus: {
self.open_path("cpuset.effective_cpus", false)
.and_then(read_string_from)
.and_then(parse_range)
.unwrap_or(Vec::new())
.unwrap_or_default()
},
effective_mems: {
self.open_path("cpuset.effective_mems", false)
.and_then(read_string_from)
.and_then(parse_range)
.unwrap_or(Vec::new())
.unwrap_or_default()
},
mem_exclusive: {
self.open_path("cpuset.mem_exclusive", false)
@@ -324,7 +324,7 @@ impl CpuSetController {
self.open_path("cpuset.mems", false)
.and_then(read_string_from)
.and_then(parse_range)
.unwrap_or(Vec::new())
.unwrap_or_default()
},
sched_load_balance: {
self.open_path("cpuset.sched_load_balance", false)

View File

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

View File

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

View File

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

View File

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

View File

@@ -35,7 +35,7 @@ use crate::cgroup::Cgroup;
/// Process mounts information.
///
/// See `proc(5)` for format details.
#[derive(Debug, PartialEq, Eq, Hash)]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Mountinfo {
/// Mount pathname relative to the process's root.
pub mount_point: PathBuf,
@@ -102,12 +102,12 @@ pub fn mountinfo_self() -> Vec<Mountinfo> {
}
/// The standard, original cgroup implementation. Often referred to as "cgroupv1".
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct V1 {
mountinfo: Vec<Mountinfo>,
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct V2 {
root: String,
}
@@ -268,6 +268,12 @@ impl V1 {
}
}
impl Default for V1 {
fn default() -> Self {
Self::new()
}
}
impl V2 {
/// Finds where control groups are mounted to and returns a hierarchy in which control groups
/// 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")))]
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
}
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"))]
pub fn is_cgroup2_unified_mode() -> bool {

View File

@@ -92,8 +92,8 @@ impl HugeTlbController {
Self {
base: root.clone(),
path: root,
sizes: sizes,
v2: v2,
sizes,
v2,
}
}
@@ -115,7 +115,7 @@ impl HugeTlbController {
self.open_path(&format!("hugetlb.{}.events", hugetlb_size), false)
.and_then(flat_keyed_to_vec)
.and_then(|x| {
if x.len() == 0 {
if x.is_empty() {
return Err(Error::from_string(format!(
"get empty from hugetlb.{}.events",
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 std::collections::HashMap;
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 num = caps.name("num");
let size: u128 = if num.is_some() {
let n = num.unwrap().as_str().trim().parse::<u128>();
let size: u128 = if let Some(num) = num {
let n = num.as_str().trim().parse::<u128>();
if n.is_err() {
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 mul: u128 = if q.is_some() {
let t = m.get(q.unwrap().as_str());
if t.is_some() {
*t.unwrap()
let mul: u128 = if let Some(q) = q {
let t = m.get(q.as_str());
if let Some(t) = t {
*t
} else {
return Err(Error::new(InvalidBytesSize));
}
@@ -289,7 +289,7 @@ fn parse_size(s: &str, m: &HashMap<String, u128>) -> Result<u128> {
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;
while size >= base && i < m.len() - 1 {
size /= base;

View File

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

View File

@@ -56,13 +56,32 @@ pub struct OomControl {
pub oom_kill: u64,
}
#[allow(clippy::unnecessary_wraps)]
fn parse_oom_control(s: String) -> Result<OomControl> {
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 {
oom_kill_disable: spl[1].parse::<u64>().unwrap() == 1,
under_oom: spl[3].parse::<u64>().unwrap() == 1,
oom_kill: spl[5].parse::<u64>().unwrap(),
oom_kill_disable,
under_oom,
oom_kill,
})
}
@@ -104,18 +123,19 @@ pub struct NumaStat {
pub hierarchical_unevictable_pages_per_node: Vec<u64>,
}
#[allow(clippy::unnecessary_wraps)]
fn parse_numa_stat(s: String) -> Result<NumaStat> {
// 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 total_line = ls.next().unwrap();
let file_line = ls.next().unwrap();
let anon_line = ls.next().unwrap();
let unevict_line = ls.next().unwrap();
let hier_total_line = ls.next().unwrap();
let hier_file_line = ls.next().unwrap();
let hier_anon_line = ls.next().unwrap();
let hier_unevict_line = ls.next().unwrap();
let hier_total_line = ls.next().unwrap_or_default();
let hier_file_line = ls.next().unwrap_or_default();
let hier_anon_line = ls.next().unwrap_or_default();
let hier_unevict_line = ls.next().unwrap_or_default();
Ok(NumaStat {
total_pages: total_line
@@ -124,10 +144,10 @@ fn parse_numa_stat(s: String) -> Result<NumaStat> {
.parse::<u64>()
.unwrap_or(0),
total_pages_per_node: {
let spl = &total_line.split(" ").collect::<Vec<_>>()[1..];
let spl = &total_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
@@ -139,10 +159,10 @@ fn parse_numa_stat(s: String) -> Result<NumaStat> {
.parse::<u64>()
.unwrap_or(0),
file_pages_per_node: {
let spl = &file_line.split(" ").collect::<Vec<_>>()[1..];
let spl = &file_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
@@ -154,10 +174,10 @@ fn parse_numa_stat(s: String) -> Result<NumaStat> {
.parse::<u64>()
.unwrap_or(0),
anon_pages_per_node: {
let spl = &anon_line.split(" ").collect::<Vec<_>>()[1..];
let spl = &anon_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
@@ -169,74 +189,114 @@ fn parse_numa_stat(s: String) -> Result<NumaStat> {
.parse::<u64>()
.unwrap_or(0),
unevictable_pages_per_node: {
let spl = &unevict_line.split(" ").collect::<Vec<_>>()[1..];
let spl = &unevict_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
.collect()
},
hierarchical_total_pages: hier_total_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0),
hierarchical_total_pages: {
if !hier_total_line.is_empty() {
hier_total_line
.split(|x| x == ' ' || x == '=')
.collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
} else {
0
}
},
hierarchical_total_pages_per_node: {
let spl = &hier_total_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
.collect()
if !hier_total_line.is_empty() {
let spl = &hier_total_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
.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: {
let spl = &hier_file_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
.collect()
if !hier_file_line.is_empty() {
let spl = &hier_file_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
.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: {
let spl = &hier_anon_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
.collect()
if !hier_anon_line.is_empty() {
let spl = &hier_anon_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
.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: {
let spl = &hier_unevict_line.split(" ").collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split("=").collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
.collect()
if !hier_unevict_line.is_empty() {
let spl = &hier_unevict_line.split(' ').collect::<Vec<_>>()[1..];
spl.iter()
.map(|x| {
x.split('=').collect::<Vec<_>>()[1]
.parse::<u64>()
.unwrap_or(0)
})
.collect()
} else {
Vec::new()
}
},
})
}
@@ -282,6 +342,7 @@ pub struct MemoryStat {
pub raw: HashMap<String, u64>,
}
#[allow(clippy::unnecessary_wraps)]
fn parse_memory_stat(s: String) -> Result<MemoryStat> {
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_active_file: *raw.get("total_active_file").unwrap_or(&0),
total_unevictable: *raw.get("total_unevictable").unwrap_or(&0),
raw: raw,
raw,
})
}
@@ -474,7 +535,7 @@ impl MemController {
Self {
base: root.clone(),
path: root,
v2: v2,
v2,
}
}
@@ -489,8 +550,8 @@ impl MemController {
for value in values {
let v = value.0;
let f = value.1;
if v.is_some() {
let v = v.unwrap().to_string();
if let Some(v) = v {
let v = v.to_string();
self.open_path(f, true).and_then(|mut file| {
file.write_all(v.as_ref())
.map_err(|e| Error::with_cause(WriteFailed, e))
@@ -531,7 +592,7 @@ impl MemController {
.open_path("memory.stat", false)
.and_then(read_string_from)
.and_then(parse_memory_stat)
.unwrap_or(MemoryStat::default()),
.unwrap_or_default(),
swappiness: self
.open_path("memory.swap.current", false)
.and_then(read_u64_from)
@@ -575,12 +636,12 @@ impl MemController {
.open_path("memory.numa_stat", false)
.and_then(read_string_from)
.and_then(parse_numa_stat)
.unwrap_or(NumaStat::default()),
.unwrap_or_default(),
oom_control: self
.open_path("memory.oom_control", false)
.and_then(read_string_from)
.and_then(parse_oom_control)
.unwrap_or(OomControl::default()),
.unwrap_or_default(),
soft_limit_in_bytes: self
.open_path("memory.soft_limit_in_bytes", false)
.and_then(read_i64_from)
@@ -589,7 +650,7 @@ impl MemController {
.open_path("memory.stat", false)
.and_then(read_string_from)
.and_then(parse_memory_stat)
.unwrap_or(MemoryStat::default()),
.unwrap_or_default(),
swappiness: self
.open_path("memory.swappiness", false)
.and_then(read_u64_from)
@@ -623,7 +684,7 @@ impl MemController {
slabinfo: self
.open_path("memory.kmem.slabinfo", false)
.and_then(read_string_from)
.unwrap_or("".to_string()),
.unwrap_or_default(),
}
}
@@ -655,7 +716,7 @@ impl MemController {
fail_cnt: self
.open_path("memory.swap.events", false)
.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(),
limit_in_bytes: self
.open_path("memory.swap.max", false)
@@ -878,6 +939,7 @@ mod tests {
use crate::memory::{
parse_memory_stat, parse_numa_stat, parse_oom_control, MemoryStat, NumaStat, OomControl,
};
static GOOD_VALUE: &str = "\
total=51189 N0=51189 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
";
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
under_oom 1
oom_kill 1337
@@ -959,11 +1038,61 @@ total_unevictable 81920
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]
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!(
ok,
OomControl {
@@ -1017,7 +1146,7 @@ total_unevictable 81920
total_inactive_file: 1272135680,
total_active_file: 2338816000,
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);
return Ok(());
Ok(())
}
}
@@ -96,6 +96,6 @@ impl NetClsController {
/// Get the network class id of the outgoing packets of the control group's tasks.
pub fn get_class(&self) -> Result<u64> {
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.
#[allow(clippy::iter_nth_zero, clippy::unnecessary_unwrap)]
pub fn ifpriomap(&self) -> Result<HashMap<String, u64>> {
self.open_path("net_prio.ifpriomap", false)
.and_then(|file| {
@@ -105,6 +106,7 @@ impl NetPrioController {
let mut acc = acc.unwrap();
let l = line.unwrap();
let mut sp = l.split_whitespace();
let ifname = sp.nth(0);
let ifprio = sp.nth(1);
if ifname.is_none() || ifprio.is_none() {

View File

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

View File

@@ -66,7 +66,7 @@ impl SystemdController {
Self {
base: root.clone(),
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 subsystems = cg.subsystems();
subsystems.into_iter().for_each(|sub| match sub {
subsystems.iter().for_each(|sub| match sub {
Subsystem::Pid(c) => {
let cgroup_path = c.path().to_str().unwrap();
let relative_path = "/pids/";

View File

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

View File

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

View File

@@ -29,7 +29,7 @@ fn test_hugetlb_sizes() {
for size in sizes {
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.limit_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>) {
assert_eq!(!r.is_err(), true)
assert!(!r.is_err())
}

View File

@@ -17,17 +17,17 @@ fn test_disable_oom_killer() {
// before disable
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
if !mem_controller.v2() {
// disable oom killer
let r = mem_controller.disable_oom_killer();
assert_eq!(r.is_err(), false);
assert!(!r.is_err());
// after disable
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();
@@ -60,7 +60,7 @@ fn set_mem_v2() {
max: None,
};
let r = mem_controller.set_mem(m);
assert_eq!(true, r.is_ok());
assert!(r.is_ok());
let m = mem_controller.get_mem().unwrap();
// get
@@ -77,7 +77,7 @@ fn set_mem_v2() {
low: None,
};
let r = mem_controller.set_mem(m);
assert_eq!(true, r.is_ok());
assert!(r.is_ok());
let m = mem_controller.get_mem().unwrap();
// get

View File

@@ -62,7 +62,7 @@ fn test_pid_events_is_not_zero() {
let before = pids.get_pid_events();
let before = before.unwrap();
match fork() {
match unsafe { fork() } {
Ok(ForkResult::Parent { child, .. }) => {
// move the process into the control group
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 {
let pids_max = pids.get_pid_max();
if pids_max.is_ok() && pids_max.unwrap() == MaxValue::Value(1) {
if let Err(_) = fork() {
if unsafe { fork() }.is_err() {
unsafe { libc::exit(0) };
} else {
unsafe { libc::exit(1) };

View File

@@ -24,7 +24,7 @@ fn pid_resources() {
// verify
let pidcontroller: &PidController = cg.controller_of().unwrap();
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));
}
cg.delete().unwrap();