diff --git a/src/blkio.rs b/src/blkio.rs index 1a98eea..a585dc4 100644 --- a/src/blkio.rs +++ b/src/blkio.rs @@ -1,50 +1,96 @@ -/* block IO controller */ +//! This module contains the implementation of the `blkio` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/cgroup-v1/blkio-controller.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt) use std::path::PathBuf; use std::io::{Read, Write}; use std::fs::File; use {BlkIoResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem}; +/// A controller that allows controlling the `blkio` subsystem of a Cgroup. +/// +/// In essence, using the `blkio` controller one can limit and throttle the tasks' usage of block +/// devices in the control group. #[derive(Debug, Clone)] pub struct BlkIoController { base: PathBuf, path: PathBuf, } +/// Current state and statistics about how throttled are the block devices when accessed from the +/// controller's control group. #[derive(Debug)] pub struct BlkIoThrottle { + /// Total amount of bytes transferred to and from the block devices. pub io_service_bytes: String, + /// Same as `io_service_bytes`, but contains all descendant control groups. pub io_service_bytes_recursive: String, + /// The number of I/O operations performed on the devices as seen by the throttling policy. pub io_serviced: String, + /// Same as `io_serviced`, but contains all descendant control groups. pub io_serviced_recursive: String, + /// The upper limit of bytes per second rate of read operation on the block devices by the + /// control group's tasks. pub read_bps_device: String, + /// The upper limit of I/O operation per second, when said operation is a read operation. pub read_iops_device: String, + /// The upper limit of bytes per second rate of write operation on the block devices by the + /// control group's tasks. pub write_bps_device: String, + /// The upper limit of I/O operation per second, when said operation is a write operation. pub write_iops_device: String, } +/// Statistics and state of the block devices. #[derive(Debug)] pub struct BlkIo { + /// The number of BIOS requests merged into I/O requests by the control group's tasks. pub io_merged: String, + /// Same as `io_merged`, but contains all descendant control groups. pub io_merged_recursive: String, + /// The number of requests queued for I/O operations by the tasks of the control group. pub io_queued: String, + /// Same as `io_queued`, but contains all descendant control groups. pub io_queued_recursive: String, + /// The number of bytes transferred from and to the block device (as seen by the CFQ I/O + /// scheduler). pub io_service_bytes: String, + /// Same as `io_service_bytes`, but contains all descendant control groups. pub io_service_bytes_recursive: String, + /// The number of I/O operations (as seen by the CFQ I/O scheduler) between the devices and the + /// control group's tasks. pub io_serviced: String, + /// Same as `io_serviced`, but contains all descendant control groups. pub io_serviced_recursive: String, + /// The total time spent between dispatch and request completion for I/O requests (as seen by + /// the CFQ I/O scheduler) by the control group's tasks. pub io_service_time: String, + /// Same as `io_service_time`, but contains all descendant control groups. pub io_service_time_recursive: String, + /// Total amount of time spent waiting for a free slot in the CFQ I/O scheduler's queue. pub io_wait_time: String, + /// Same as `io_wait_time`, but contains all descendant control groups. pub io_wait_time_recursive: String, + /// How much weight do the control group's tasks have when competing against the descendant + /// control group's tasks. pub leaf_weight: u64, + /// Same as `leaf_weight`, but per-block-device. pub leaf_weight_device: String, + /// Total number of sectors transferred between the block devices and the control group's + /// tasks. pub sectors: String, + /// Same as `sectors`, but contains all descendant control groups. pub sectors_recursive: String, + /// Similar statistics, but as seen by the throttle policy. pub throttle: BlkIoThrottle, + /// The time the control group had access to the I/O devices. pub time: String, + /// Same as `time`, but contains all descendant control groups. pub time_recursive: String, + /// The weight of this control group. pub weight: u64, + /// Same as `weight`, but per-block-device. pub weight_device: String, } @@ -119,6 +165,7 @@ fn read_u64_from(mut file: File) -> Option { } impl BlkIoController { + /// Constructs a new `BlkIoController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -127,6 +174,9 @@ impl BlkIoController { path: root, } } + + /// Gathers statistics about and reports the state of the block devices used by the control + /// group's tasks. pub fn blkio(self: &Self) -> BlkIo { BlkIo { io_merged: self.open_path("blkio.io_merged", false).and_then(|file| { @@ -218,54 +268,67 @@ impl BlkIoController { } } + /// Set the leaf weight on the control group's tasks, i.e., how are they weighted against the + /// descendant control groups' tasks. pub fn set_leaf_weight(self: &Self, w: u64) { self.open_path("blkio.leaf_weight", true).and_then(|mut file| { file.write_all(w.to_string().as_ref()).ok() }); } + /// Same as `set_leaf_weight()`, but settable per each block device. pub fn set_leaf_weight_for_device(self: &Self, d: String) { self.open_path("blkio.leaf_weight_device", true).and_then(|mut file| { file.write_all(d.as_ref()).ok() }); } + /// Reset the statistics the kernel has gathered so far and start fresh. pub fn reset_stats(self: &Self) { self.open_path("blkio.leaf_weight_device", true).and_then(|mut file| { file.write_all("1".to_string().as_ref()).ok() }); } + /// Throttle the bytes per second rate of read operation affecting the block device + /// `major:minor` to `bps`. pub fn throttle_read_bps_for_device(self: &Self, major: u64, minor: u64, bps: u64) { self.open_path("blkio.throttle.read_bps_device", true).and_then(|mut file| { file.write_all(format!("{}:{} {}", major, minor, bps).to_string().as_ref()).ok() }); } + /// Throttle the I/O operations per second rate of read operation affecting the block device + /// `major:minor` to `bps`. pub fn throttle_read_iops_for_device(self: &Self, major: u64, minor: u64, iops: u64) { self.open_path("blkio.throttle.read_iops_device", true).and_then(|mut file| { file.write_all(format!("{}:{} {}", major, minor, iops).to_string().as_ref()).ok() }); } - + /// Throttle the bytes per second rate of write operation affecting the block device + /// `major:minor` to `bps`. pub fn throttle_write_bps_for_device(self: &Self, major: u64, minor: u64, bps: u64) { self.open_path("blkio.throttle.write_bps_device", true).and_then(|mut file| { file.write_all(format!("{}:{} {}", major, minor, bps).to_string().as_ref()).ok() }); } + /// Throttle the I/O operations per second rate of write operation affecting the block device + /// `major:minor` to `bps`. pub fn throttle_write_iops_for_device(self: &Self, major: u64, minor: u64, iops: u64) { self.open_path("blkio.throttle.write_iops_device", true).and_then(|mut file| { file.write_all(format!("{}:{} {}", major, minor, iops).to_string().as_ref()).ok() }); } + /// Set the weight of the control group's tasks. pub fn set_weight(self: &Self, w: u64) { self.open_path("blkio.leaf_weight", true).and_then(|mut file| { file.write_all(w.to_string().as_ref()).ok() }); } + /// Same as `set_weight()`, but settable per each block device. pub fn set_weight_for_device(self: &Self, d: String) { self.open_path("blkio.weight_device", true).and_then(|mut file| { file.write_all(d.as_ref()).ok() diff --git a/src/cgroup.rs b/src/cgroup.rs index 5e0aec4..809a198 100644 --- a/src/cgroup.rs +++ b/src/cgroup.rs @@ -1,24 +1,43 @@ +//! This module handles cgroup operations. Start here! + use {CgroupPid, Resources, ControllIdentifier, Controller, Hierarchy, Subsystem}; use std::convert::From; -/* Describe a cgroup in a simple fashion */ +/// A control group is the central structure to this crate. +/// +/// +/// # What are control groups? +/// +/// Lifting over from the Linux kernel sources: +/// +/// > Control Groups provide a mechanism for aggregating/partitioning sets of +/// > tasks, and all their future children, into hierarchical groups with +/// > specialized behaviour. +/// +/// This crate is an attempt at providing a Rust-native way of managing these cgroups. pub struct Cgroup { - /// Name of the cgroup - //name: String, /// The list of subsystems that control this cgroup subsystems: Vec, } impl Cgroup { + + /// Create this control group. fn create(self: &Self) { for subsystem in &self.subsystems { subsystem.to_controller().create(); } } - pub fn new(hier: &Hierarchy, path: String, _resources: i64) -> Cgroup { + /// Create a new control group in the hierarchy `hier`, with name `path`. + /// + /// Returns a handle to the control group that can be used to manipulate it. + /// + /// Note that if the handle goes out of scope and is dropped, the control group is _not_ + /// destroyed. + pub fn new(hier: &Hierarchy, path: String) -> Cgroup { let mut subsystems = hier.subsystems(); subsystems = subsystems.into_iter().map(|x| x.enter(&path)).collect::>(); diff --git a/src/devices.rs b/src/devices.rs index 469ff92..ad3e9a0 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -1,9 +1,16 @@ -/* Devices controller */ +//! This module contains the implementation of the `devices` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/cgroup-v1/devices.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/devices.txt) use std::path::PathBuf; use std::io::{Read, Write}; use {DeviceResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem}; +/// A controller that allows controlling the `devices` subsystem of a Cgroup. +/// +/// In essence, using the devices controller, it is possible to allow or disallow sets of devices to +/// be used by the control group's tasks. #[derive(Debug, Clone)] pub struct DevicesController{ base: PathBuf, @@ -55,6 +62,7 @@ impl<'a> From<&'a Subsystem> for &'a DevicesController { } impl DevicesController { + /// Constructs a new `DevicesController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -63,18 +71,38 @@ impl DevicesController { path: root, } } + + /// Allow a (possibly, set of) device(s) to be used by the tasks in the control group. + /// + /// The format of `dev` is rather simple: + /// `$type $major:$minor $rwm` + /// where `$rwm` is a combination of the characters `r`, `w`, `m`, each standing for read, + /// write, mknod permissions. + /// + /// Note that `dev` can be "regex"-like: both `$major` and `$minor` can be `*` which implies + /// that their value does not matter. pub fn allow_device(self: &Self, dev: &String) { self.open_path("devices.allow", true).and_then(|mut file| { file.write_all(dev.as_ref()).ok() }); } + /// Deny the control group's tasks access to the devices covered by `dev`. + /// + /// The format of `dev` is rather simple: + /// `$type $major:$minor $rwm` + /// where `$rwm` is a combination of the characters `r`, `w`, `m`, each standing for read, + /// write, mknod permissions. + /// + /// Note that `dev` can be "regex"-like: both `$major` and `$minor` can be `*` which implies + /// that their value does not matter. pub fn deny_device(self: &Self, dev: &String) { self.open_path("devices.deny", true).and_then(|mut file| { file.write_all(dev.as_ref()).ok() }); } + /// Get the current list of allowed devices. pub fn allowed_devices(self: &Self) -> String { self.open_path("devices.list", false).and_then(|mut file| { let mut s = String::new(); diff --git a/src/freezer.rs b/src/freezer.rs index dffdbe2..1d56fc6 100644 --- a/src/freezer.rs +++ b/src/freezer.rs @@ -1,18 +1,33 @@ -/* Freezer controller */ +//! This module contains the implementation of the `freezer` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/cgroup-v1/freezer-subsystem.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt) use std::path::PathBuf; use std::io::{Read, Write}; use {Controllers, Controller, Resources, ControllIdentifier, Subsystem}; +/// A controller that allows controlling the `freezer` subsystem of a Cgroup. +/// +/// In essence, this subsystem allows the user to freeze and thaw (== "un-freeze") the processes in +/// the control group. This is done _transparently_ so that neither the parent, nor the children of +/// the processes can observe the freeze. +/// +/// Note that if the control group is currently in the `Frozen` or `Freezing` state, then no +/// processes can be added to it. #[derive(Debug, Clone)] pub struct FreezerController{ base: PathBuf, path: PathBuf, } +/// The current state of the control group pub enum FreezerState { + /// The processes in the control group are _not_ frozen. Thawed, + /// The processes in the control group are in the processes of being frozen. Freezing, + /// The processes in the control group are frozen. Frozen, } @@ -47,6 +62,7 @@ impl<'a> From<&'a Subsystem> for &'a FreezerController { } impl FreezerController { + /// Contructs a new `FreezerController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -55,18 +71,22 @@ impl FreezerController { path: root, } } + + /// Freezes the processes in the control group. pub fn freeze(self: &Self) { self.open_path("freezer.state", true).and_then(|mut file| { file.write_all("FROZEN".to_string().as_ref()).ok() }); } + /// Thaws, that is, unfreezes the processes in the control group. pub fn thaw(self: &Self) { self.open_path("freezer.state", true).and_then(|mut file| { file.write_all("THAWED".to_string().as_ref()).ok() }); } + /// Retrieve the state of processes in the control group. pub fn state(self: &Self) -> FreezerState { self.open_path("freezer.state", false).and_then(|mut file| { let mut s = String::new(); diff --git a/src/hugetlb.rs b/src/hugetlb.rs index 914256d..00b14bf 100644 --- a/src/hugetlb.rs +++ b/src/hugetlb.rs @@ -1,10 +1,18 @@ -/* Hugetlb controller */ +//! This module contains the implementation of the `hugetlb` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/cgroup-v1/hugetlb.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/hugetlb.txt) use std::path::PathBuf; use std::fs::File; use std::io::{Write, Read}; use {HugePageResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem}; + +/// A controller that allows controlling the `hugetlb` subsystem of a Cgroup. +/// +/// In essence, using this controller it is possible to limit the use of hugepages in the tasks of +/// the control group. #[derive(Debug, Clone)] pub struct HugeTlbController { base: PathBuf, @@ -56,6 +64,7 @@ fn read_u64_from(mut file: File) -> Option { } impl HugeTlbController { + /// Constructs a new `HugeTlbController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -64,30 +73,42 @@ impl HugeTlbController { path: root, } } + + /// Whether the system supports `hugetlb_size` hugepages. pub fn size_supported(self: &Self, _hugetlb_size: String) -> bool { /* TODO */ true } + /// Check how many times has the limit of `hugetlb_size` hugepages been hit. pub fn failcnt(self: &Self, hugetlb_size: &String) -> Option { self.open_path(&format!("hugetlb.{}.failcnt", hugetlb_size), false) .and_then(read_u64_from) } + /// Get the limit (in bytes) of how much memory can be backed by hugepages of a certain size + /// (`hugetlb_size`). pub fn limit_in_bytes(self: &Self, hugetlb_size: &String) -> Option { self.open_path(&format!("hugetlb.{}.limit_in_bytes", hugetlb_size), false) .and_then(read_u64_from) } + /// Get the current usage of memory that is backed by hugepages of a certain size + /// (`hugetlb_size`). pub fn usage_in_bytes(self: &Self, hugetlb_size: &String) -> Option { self.open_path(&format!("hugetlb.{}.usage_in_bytes", hugetlb_size), false) .and_then(read_u64_from) } + + /// Get the maximum observed usage of memory that is backed by hugepages of a certain size + /// (`hugetlb_size`). pub fn max_usage_in_bytes(self: &Self, hugetlb_size: &String) -> Option { self.open_path(&format!("hugetlb.{}.max_usage_in_bytes", hugetlb_size), false) .and_then(read_u64_from) } + /// Set the limit (in bytes) of how much memory can be backed by hugepages of a certain size + /// (`hugetlb_size`). pub fn set_limit_in_bytes(self: &Self, hugetlb_size: &String, limit: u64) { self.open_path(&format!("hugetlb.{}.limit_in_bytes", hugetlb_size), false) .and_then(|mut file| { diff --git a/src/lib.rs b/src/lib.rs index 6091256..02b85a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,22 +35,35 @@ use rdma::RdmaController; /// Contains all the subsystems that are available in this crate. #[derive(Debug)] pub enum Subsystem { + /// Controller for the `Pid` subsystem, see `PidController` for more information. Pid(PidController), + /// Controller for the `Mem` subsystem, see `MemController` for more information. Mem(MemController), + /// Controller for the `CpuSet subsystem, see `CpuSetController` for more information. CpuSet(CpuSetController), + /// Controller for the `CpuAcct` subsystem, see `CpuAcctController` for more information. CpuAcct(CpuAcctController), + /// Controller for the `Cpu` subsystem, see `CpuController` for more information. Cpu(CpuController), + /// Controller for the `Devices` subsystem, see `DevicesController` for more information. Devices(DevicesController), + /// Controller for the `Freezer` subsystem, see `FreezerController` for more information. Freezer(FreezerController), + /// Controller for the `NetCls` subsystem, see `NetClsController` for more information. NetCls(NetClsController), + /// Controller for the `BlkIo` subsystem, see `BlkIoController` for more information. BlkIo(BlkIoController), + /// Controller for the `PerfEvent` subsystem, see `PerfEventController` for more information. PerfEvent(PerfEventController), + /// Controller for the `NetPrio` subsystem, see `NetPrioController` for more information. NetPrio(NetPrioController), + /// Controller for the `HugeTlb` subsystem, see `HugeTlbController` for more information. HugeTlb(HugeTlbController), + /// Controller for the `Rdma` subsystem, see `RdmaController` for more information. Rdma(RdmaController), } -/// Subsystem identifier without the controller attached. +#[doc(hidden)] #[derive(Eq, PartialEq, Debug)] pub enum Controllers { Pids, @@ -88,20 +101,30 @@ impl Controllers { } } +/// A Controller is a subsystem attached to the control group. +/// +/// Implementors are able to control certain aspects of a control group. pub trait Controller { - /* actual API */ + /// Apply a set of resources to the Controller, invoking its internal functions to pass the + /// kernel the information. fn apply(self: &Self, res: &Resources); /* meta stuff */ + #[doc(hidden)] fn control_type(self: &Self) -> Controllers; + #[doc(hidden)] fn get_path<'a>(self: &'a Self) -> &'a PathBuf; + #[doc(hidden)] fn get_path_mut<'a>(self: &'a mut Self) -> &'a mut PathBuf; + #[doc(hidden)] fn get_base<'a>(self: &'a Self) -> &'a PathBuf; + #[doc(hidden)] fn verify_path(self: &Self) -> bool { self.get_path().starts_with(self.get_base()) } + /// Create this controller fn create(self: &Self) { if self.verify_path() { match ::std::fs::create_dir(self.get_path()) { @@ -111,16 +134,19 @@ pub trait Controller { } } + /// Does this controller already exist? fn exists(self: &Self) -> bool { self.get_path().exists() } + /// Delete the controller. fn delete(self: &Self) { if self.get_path().exists() { let _ = ::std::fs::remove_dir(self.get_path()); } } + #[doc(hidden)] fn open_path(self: &Self, p: &str, w: bool) -> Option { let mut path = self.get_path().clone(); path.push(p); @@ -142,6 +168,7 @@ pub trait Controller { } } + /// Attach a task to this controller. fn add_task(self: &Self, pid: &CgroupPid) { self.open_path("tasks", true).and_then(|mut file| { file.write_all(pid.pid.to_string().as_ref()).ok() @@ -149,10 +176,13 @@ pub trait Controller { } } +#[doc(hidden)] pub trait ControllIdentifier { fn controller_type() -> Controllers; } +/// Control group hierarchy (right now, only V1 is supported, but in the future Unified will be +/// implemented as well). pub trait Hierarchy { fn subsystems(self: &Self) -> Vec; fn can_create_cgroup(self: &Self) -> bool; diff --git a/src/memory.rs b/src/memory.rs index 13efc24..35d047a 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,56 +1,116 @@ -/* Memory controller */ +//! This module contains the implementation of the `memory` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/cgroup-v1/memory.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt) use std::path::PathBuf; use std::io::{Write, Read}; use std::fs::File; use {Resources, MemoryResources, Controller, Controllers, Subsystem, ControllIdentifier}; +/// A controller that allows controlling the `memory` subsystem of a Cgroup. +/// +/// In essence, using the memory controller, the user can gather statistics about the memory usage +/// of the tasks in the control group. Additonally, one can also set powerful limits on their +/// memory usage. #[derive(Debug, Clone)] pub struct MemController{ base: PathBuf, path: PathBuf, } +/// Contains statistics about the current usage of memory and swap (together, not seperately) by +/// the control group's tasks. #[derive(Debug)] pub struct MemSwap { + /// How many times the limit has been hit. pub fail_cnt: u64, + /// Memory and swap usage limit in bytes. pub limit_in_bytes: u64, + /// Current usage of memory and swap in bytes. pub usage_in_bytes: u64, + /// The maximum observed usage of memory and swap in bytes. pub max_usage_in_bytes: u64, } +/// State of and statistics gathered by the kernel about the memory usage of the control group's +/// tasks. #[derive(Debug)] pub struct Memory { + /// How many times the limit has been hit. pub fail_cnt: u64, + /// The limit in bytes of the memory usage of the control group's tasks. pub limit_in_bytes: u64, + /// The current usage of memory by the control group's tasks. pub usage_in_bytes: u64, + /// The maximum observed usage of memory by the control group's tasks. pub max_usage_in_bytes: u64, + /// Whether moving charges at immigrate is allowed. pub move_charge_at_immigrate: u64, /* TODO: parse this */ + /// Contains various statistics about the NUMA locality of the control group's tasks. + /// + /// The format of this field (as lifted from the kernel sources): + /// ``` + /// total= N0= N1= ... + /// file= N0= N1= ... + /// anon= N0= N1= ... + /// unevictable= N0= N1= ... + /// hierarchical_= N0= N1= ... + /// ``` pub numa_stat: String, - /* TODO: parse this */ + /// If this equals "1", then the OOM killer is enabled for this control group (this is the + /// default setting). pub oom_control: String, + /// Allows setting a limit to memory usage which is enforced when the system (note, _not_ the + /// control group) detects memory pressure. pub soft_limit_in_bytes: u64, /* TODO: parse this */ + /// Contains a wide array of statistics about the memory usage of the tasks in the control + /// group. pub stat: String, + /// Set the tendency of the kernel to swap out parts of the address space consumed by the + /// control group's tasks. + /// + /// Note that setting this to zero does *not* prevent swapping, use `mlock(2)` for that + /// purpose. pub swappiness: u64, + /// If set, then under OOM conditions, the kernel will try to reclaim memory from the children + /// of the offending process too. By default, this is not allowed. pub use_hierarchy: u64, } +/// The current state of and gathered statistics about the kernel's memory usage for TCP-related +/// data structures. #[derive(Debug)] pub struct Tcp { + /// How many times the limit has been hit. pub fail_cnt: u64, + /// The limit in bytes of the memory usage of the kernel's TCP buffers by control group's + /// tasks. pub limit_in_bytes: u64, + /// The current memory used by the kernel's TCP buffers related to these tasks. pub usage_in_bytes: u64, + /// The observed maximum usage of memory by the kernel's TCP buffers (that originated from + /// these tasks). pub max_usage_in_bytes: u64, } +/// Gathered statistics and the current state of limitation of the kernel's memory usage. Note that +/// this is per-cgroup, so the kernel can of course use more memory, but it will fail operations by +/// these tasks if it would think that the limits here would be violated. It's important to note +/// that interrupts in particular might not be able to enforce these limits. #[derive(Debug)] pub struct Kmem { + /// How many times the limit has been hit. pub fail_cnt: u64, + /// The limit in bytes of the kernel memory used by the control group's tasks. pub limit_in_bytes: u64, + /// The current usage of kernel memory used by the control group's tasks, in bytes. pub usage_in_bytes: u64, + /// The maximum observed usage of kernel memory used by the control group's tasks, in bytes. pub max_usage_in_bytes: u64, + /// Contains information about the memory usage of the kernel's caches, per control group. pub slabinfo: String, } @@ -76,6 +136,7 @@ impl Controller for MemController { } impl MemController { + /// Contructs a new `MemController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -85,6 +146,11 @@ impl MemController { } } + /// Gathers overall statistics (and the current state of) about the memory usage of the control + /// group's tasks. + /// + /// See the individual fields for more explanation, and as always, remember to consult the + /// kernel Documentation and/or sources. pub fn memory_stat(self: &Self) -> Memory { Memory { fail_cnt: self.open_path("memory.failcnt", false) @@ -132,6 +198,7 @@ impl MemController { } } + /// Gathers information about the kernel memory usage of the control group's tasks. pub fn kmem_stat(self: &Self) -> Kmem { Kmem { fail_cnt: self.open_path("memory.kmem.failcnt", false) @@ -155,6 +222,8 @@ impl MemController { } } + /// Gathers information about the control group's kernel memory usage where said memory is + /// TCP-related. pub fn kmem_tcp_stat(self: &Self) -> Tcp { Tcp { fail_cnt: self.open_path("memory.kmem.tcp.failcnt", false) @@ -172,6 +241,8 @@ impl MemController { } } + /// Gathers information about the memory usage of the control group including the swap usage + /// (if any). pub fn memswap(self: &Self) -> MemSwap { MemSwap { fail_cnt: self.open_path("memory.memsw.failcnt", false) @@ -189,36 +260,50 @@ impl MemController { } } + /// Set the memory usage limit of the control group, in bytes. pub fn set_limit(self: &Self, limit: u64) { self.open_path("memory.limit_in_bytes", true).and_then(|mut file| { file.write_all(limit.to_string().as_ref()).ok() }); } + /// Set the kernel memory limit of the control group, in bytes. pub fn set_kmem_limit(self: &Self, limit: u64) { self.open_path("memory.kmem.limit_in_bytes", true).and_then(|mut file| { file.write_all(limit.to_string().as_ref()).ok() }); } + /// Set the memory+swap limit of the control group, in bytes. pub fn set_memswap_limit(self: &Self, limit: u64) { self.open_path("memory.memsw.limit_in_bytes", true).and_then(|mut file| { file.write_all(limit.to_string().as_ref()).ok() }); } + /// Set how much kernel memory can be used for TCP-related buffers by the control group. pub fn set_tcp_limit(self: &Self, limit: u64) { self.open_path("memory.kmem.tcp.limit_in_bytes", true).and_then(|mut file| { file.write_all(limit.to_string().as_ref()).ok() }); } + + /// Set the soft limit of the control group, in bytes. + /// + /// This limit is enforced when the system is nearing OOM conditions. Contrast this with the + /// hard limit, which is _always_ enforced. pub fn set_soft_limit(self: &Self, limit: u64) { self.open_path("memory.soft_limit_in_bytes", true).and_then(|mut file| { file.write_all(limit.to_string().as_ref()).ok() }); } + + /// Set how likely the kernel is to swap out parts of the address space used by the control + /// group. + /// + /// Note that a value of zero does not imply that the process will not be swapped out. pub fn set_swappiness(self: &Self, swp: u64) { self.open_path("memory.swappiness", true).and_then(|mut file| { file.write_all(swp.to_string().as_ref()).ok() diff --git a/src/net_cls.rs b/src/net_cls.rs index db1f7cd..61ab7d2 100644 --- a/src/net_cls.rs +++ b/src/net_cls.rs @@ -1,17 +1,24 @@ -/* Network classifier controller */ +//! This module contains the implementation of the `net_cls` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/cgroup-v1/net_cls.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/net_cls.txt) use std::path::PathBuf; use std::io::{Read, Write}; use std::fs::File; use {NetworkResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem}; +/// A controller that allows controlling the `net_cls` subsystem of a Cgroup. +/// +/// In esssence, using the `net_cls` controller, one can attach a custom class to the network +/// packets emitted by the control group's tasks. This can then later be used in iptables to have +/// custom firewall rules, QoS, etc. #[derive(Debug, Clone)] pub struct NetClsController { base: PathBuf, path: PathBuf, } - impl Controller for NetClsController { fn control_type(self: &Self) -> Controllers { Controllers::NetCls } fn get_path<'a>(self: &'a Self) -> &'a PathBuf { &self.path } @@ -55,6 +62,7 @@ fn read_u64_from(mut file: File) -> Option { } impl NetClsController { + /// Constructs a new `NetClsController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -63,6 +71,8 @@ impl NetClsController { path: root, } } + + /// Set the network class id of the outgoing packets of the control group's tasks. pub fn set_class(self: &Self, class: u64) { self.open_path("net_cls.classid", true).and_then(|mut file| { let s = format!("{:#08X}", class); @@ -70,6 +80,7 @@ impl NetClsController { }); } + /// Get the network class id of the outgoing packets of the control group's tasks. pub fn get_class(self: &Self) -> u64 { self.open_path("net_cls.classid", false).and_then(|file| { read_u64_from(file) diff --git a/src/net_prio.rs b/src/net_prio.rs index 8ab44c4..bc7c2b9 100644 --- a/src/net_prio.rs +++ b/src/net_prio.rs @@ -1,4 +1,7 @@ -/* Network priority controller */ +//! This module contains the implementation of the `net_prio` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/cgroup-v1/net_prio.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/net_prio.txt) use std::path::PathBuf; use std::io::{BufReader, BufRead, Write, Read}; use std::fs::File; @@ -6,6 +9,11 @@ use std::collections::HashMap; use {NetworkResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem}; +/// A controller that allows controlling the `net_prio` subsystem of a Cgroup. +/// +/// In essence, using `net_prio` one can set the priority of the packets emitted from the control +/// group's tasks. This can then be used to have QoS restrictions on certain control groups and +/// thus, prioritizing certain tasks. #[derive(Debug, Clone)] pub struct NetPrioController { base: PathBuf, @@ -57,6 +65,7 @@ fn read_u64_from(mut file: File) -> Option { } impl NetPrioController { + /// Constructs a new `NetPrioController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -65,12 +74,15 @@ impl NetPrioController { path: root, } } + + /// Retrieves the current priority of the emitted packets. pub fn prio_idx(self: &Self) -> u64 { self.open_path("net_prio.prioidx", false) .and_then(read_u64_from) .unwrap_or(0) } + /// A map of priorities for each network interface. pub fn ifpriomap(self: &Self) -> HashMap { self.open_path("net_prio.ifpriomap", false) .and_then(|file| { @@ -84,6 +96,7 @@ impl NetPrioController { }).unwrap_or(HashMap::new()) } + /// Set the priority of the network traffic on `eif` to be `prio`. pub fn set_if_prio(self: &Self, eif: &String, prio: u64) { self.open_path("net_prio.ifpriomap", true) .and_then(|mut file| { diff --git a/src/perf_event.rs b/src/perf_event.rs index 26d6e8a..313f570 100644 --- a/src/perf_event.rs +++ b/src/perf_event.rs @@ -1,8 +1,15 @@ -/* Perf event controller */ +//! This module contains the implementation of the `perf_event` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [tools/perf/Documentation/perf-record.txt](https://raw.githubusercontent.com/torvalds/linux/master/tools/perf/Documentation/perf-record.txt) use std::path::PathBuf; use {Controllers, Controller, Resources, ControllIdentifier, Subsystem}; +/// A controller that allows controlling the `perf_event` subsystem of a Cgroup. +/// +/// In essence, when processes belong to the same `perf_event` controller, they can be monitored +/// together using the `perf` performance monitoring and reporting tool. #[derive(Debug, Clone)] pub struct PerfEventController { base: PathBuf, @@ -40,6 +47,7 @@ impl<'a> From<&'a Subsystem> for &'a PerfEventController { } impl PerfEventController { + /// Constructs a new `PerfEventController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); diff --git a/src/rdma.rs b/src/rdma.rs index 795c825..e326c8a 100644 --- a/src/rdma.rs +++ b/src/rdma.rs @@ -1,10 +1,17 @@ -/* RDMA controller */ +//! This module contains the implementation of the `rdma` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/cgroup-v1/rdma.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/rdma.txt) use std::path::PathBuf; use std::io::{Write, Read}; use std::fs::File; use {Controllers, Controller, Resources, ControllIdentifier, Subsystem}; +/// A controller that allows controlling the `rdma` subsystem of a Cgroup. +/// +/// In essence, using this controller one can limit the RDMA/IB specific resources that the tasks +/// in the control group can use. #[derive(Debug, Clone)] pub struct RdmaController { base: PathBuf, @@ -48,6 +55,7 @@ fn read_string_from(mut file: File) -> Option { } impl RdmaController { + /// Constructs a new `RdmaController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -56,12 +64,15 @@ impl RdmaController { path: root, } } + + /// Returns the current usage of RDMA/IB specific resources. pub fn current(self: &Self) -> String { self.open_path("rdma.current", false) .and_then(read_string_from) .unwrap_or("".to_string()) } + /// Set a maximum usage for each RDMA/IB resource. pub fn set_max(self: &Self, max: &String) { self.open_path("rdma.max", true) .and_then(|mut file| {