Skip to content

Commit

Permalink
cgroup: support to set threaded mode in cgroup v2
Browse files Browse the repository at this point in the history
Support to set threaded mode in cgroup v2. The premise of switching to threaded mode is that only the cgroup of cpuset, cpu and pids is supported.

Fixes: kata-containers#90

Signed-off-by: yaoyinnan <yaoyinnan@foxmail.com>
  • Loading branch information
yaoyinnan committed Nov 23, 2022
1 parent 4d8f704 commit 0e369d9
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 13 deletions.
58 changes: 50 additions & 8 deletions src/cgroup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,26 @@ impl Default for Cgroup {
}

impl Cgroup {
pub fn v2(&self) -> bool {
self.hier.v2()
}

/// Create this control group.
fn create(&self) {
if self.hier.v2() {
let _ret = create_v2_cgroup(self.hier.root(), &self.path);
let _ret = create_v2_cgroup(self.hier.root(), &self.path, None);
} else {
for subsystem in &self.subsystems {
subsystem.to_controller().create();
}
}
}

pub fn v2(&self) -> bool {
self.hier.v2()
/// Create this control group with specified controllers.
///
/// Note that this method is only meaningful for cgroup v2.
fn create_with_specified_controllers(&self, specified_controllers: Option<Vec<String>>) {
let _ret = create_v2_cgroup(self.hier.root(), &self.path, specified_controllers);
}

/// Create a new control group in the hierarchy `hier`, with name `path`.
Expand All @@ -83,11 +90,20 @@ impl Cgroup {
cg
}

/// 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.
pub fn new_with_specified_controllers<P: AsRef<Path>>(hier: Box<dyn Hierarchy>, path: P, specified_controllers: Option<Vec<String>>) -> Cgroup {
let cg = Cgroup::load(hier, path);
cg.create_with_specified_controllers(specified_controllers);
cg
}

/// Create a new control group in the hierarchy `hier`, with name `path` and `relative_paths`
///
/// Returns a handle to the control group that can be used to manipulate it.
///
/// Note that this method is only meaningful for cgroup v1, call it is equivalent to call `new` in the v2 mode
/// Note that this method is only meaningful for cgroup v1, call it is equivalent to call `new` in the v2 mode.
pub fn new_with_relative_paths<P: AsRef<Path>>(
hier: Box<dyn Hierarchy>,
path: P,
Expand Down Expand Up @@ -265,6 +281,13 @@ impl Cgroup {
.try_for_each(|sub| sub.to_controller().add_task_by_tgid(&pid))
}

/// set cgroup.type
pub fn set_cgroup_type(&self, cgroup_type: &str) -> Result<()> {
self.subsystems()
.iter()
.try_for_each(|sub| sub.to_controller().set_cgroup_type(cgroup_type))
}

/// Set notify_on_release to the control group.
pub fn set_notify_on_release(&self, enable: bool) -> Result<()> {
self.subsystems()
Expand Down Expand Up @@ -311,15 +334,15 @@ impl Cgroup {

pub const UNIFIED_MOUNTPOINT: &str = "/sys/fs/cgroup";

fn enable_controllers(controllers: &[String], path: &Path) {
fn enable_controllers(controllers: &Vec<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());
}
}

fn supported_controllers() -> Vec<String> {
fn get_supported_controllers() -> Vec<String> {
let p = format!("{}/{}", UNIFIED_MOUNTPOINT, "cgroup.controllers");
let ret = fs::read_to_string(p.as_str());
ret.unwrap_or_default()
Expand All @@ -328,9 +351,18 @@ fn supported_controllers() -> Vec<String> {
.collect::<Vec<String>>()
}

fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> {
fn create_v2_cgroup(root: PathBuf, path: &str, specified_controllers: Option<Vec<String>>) -> Result<()> {
// controler list ["memory", "cpu"]
let controllers = supported_controllers();
let controllers = if let Some(s_controllers) = specified_controllers {
if verify_supported_controllers(s_controllers.as_ref()) {
s_controllers.clone()
} else {
return Err(Error::new(ErrorKind::SpecifiedControllers));
}
} else {
get_supported_controllers()
};

let mut fp = root;

// enable for root
Expand Down Expand Up @@ -358,6 +390,16 @@ fn create_v2_cgroup(root: PathBuf, path: &str) -> Result<()> {
Ok(())
}

pub fn verify_supported_controllers(controllers: &Vec<String>) -> bool {
let supported_controllers = get_supported_controllers();
for controller in controllers.iter() {
if !supported_controllers.contains(controller) {
return false;
}
}
true
}

pub fn get_cgroups_relative_paths() -> Result<HashMap<String, String>> {
let path = "/proc/self/cgroup".to_string();
get_cgroups_relative_paths_by_path(path)
Expand Down
19 changes: 16 additions & 3 deletions src/cgroup_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ pub struct CgroupBuilder {
name: String,
/// Internal, unsupported field: use the associated builders instead.
resources: Resources,
specified_controllers: Option<Vec<String>>,
}

impl CgroupBuilder {
Expand All @@ -90,6 +91,7 @@ impl CgroupBuilder {
CgroupBuilder {
name: name.to_owned(),
resources: Resources::default(),
specified_controllers: None,
}
}

Expand Down Expand Up @@ -135,9 +137,20 @@ impl CgroupBuilder {

/// Finalize the control group, consuming the builder and creating the control group.
pub fn build(self, hier: Box<dyn Hierarchy>) -> Cgroup {
let cg = Cgroup::new(hier, self.name);
let _ret = cg.apply(&self.resources);
cg
if let Some(controllers) = self.specified_controllers {
let cg = Cgroup::new_with_specified_controllers(hier, self.name, Some(controllers));
let _ret = cg.apply(&self.resources);
cg
} else {
let cg = Cgroup::new(hier, self.name);
let _ret = cg.apply(&self.resources);
cg
}
}

pub fn set_specified_controllers(mut self, specified_controllers: Vec<String>) -> Self {
self.specified_controllers = Some(specified_controllers);
self
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ pub enum ErrorKind {

InvalidBytesSize,

/// The specified controller is not in the list of supported controllers.
SpecifiedControllers,

/// An unknown error has occured.
Other,
}
Expand All @@ -63,6 +66,7 @@ impl fmt::Display for Error {
ErrorKind::InvalidOperation => "the requested operation is invalid".to_string(),
ErrorKind::InvalidPath => "the given path is invalid".to_string(),
ErrorKind::InvalidBytesSize => "invalid bytes size".to_string(),
ErrorKind::SpecifiedControllers => "specified controller is not in the list of supported controllers".to_string(),
ErrorKind::Other => "an unknown error".to_string(),
};

Expand Down
15 changes: 13 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ pub trait Controller {
/// Attach a task to this controller.
fn add_task_by_tgid(&self, pid: &CgroupPid) -> Result<()>;

/// set cgroup type.
fn set_cgroup_type(&self, cgroup_type: &str) -> Result<()>;

/// Get the list of tasks that this controller has.
fn tasks(&self) -> Vec<CgroupPid>;

Expand Down Expand Up @@ -355,7 +358,7 @@ where
fn add_task(&self, pid: &CgroupPid) -> Result<()> {
let mut file = "tasks";
if self.is_v2() {
file = "cgroup.procs";
file = "cgroup.threads";
}
self.open_path(file, true).and_then(|mut file| {
file.write_all(pid.pid.to_string().as_ref())
Expand All @@ -375,7 +378,7 @@ where
fn tasks(&self) -> Vec<CgroupPid> {
let mut file = "tasks";
if self.is_v2() {
file = "cgroup.procs";
file = "cgroup.threads";
}
self.open_path(file, false)
.map(|file| {
Expand All @@ -395,6 +398,14 @@ where
.unwrap_or_default()
}

/// set cgroup.type
fn set_cgroup_type(&self, cgroup_type: &str) -> Result<()> {
self.open_path("cgroup.type", true).and_then(|mut file| {
file.write_all(cgroup_type.as_bytes())
.map_err(|e| Error::with_cause(ErrorKind::WriteFailed, e))
})
}

fn v2(&self) -> bool {
self.is_v2()
}
Expand Down

0 comments on commit 0e369d9

Please sign in to comment.