cgroups_rs/fs/
freezer.rs

1// Copyright (c) 2018 Levente Kurusa
2// Copyright (c) 2020 Ant Group
3//
4// SPDX-License-Identifier: Apache-2.0 or MIT
5//
6
7//! This module contains the implementation of the `freezer` cgroup subsystem.
8//!
9//! See the Kernel's documentation for more information about this subsystem, found at:
10//!  [Documentation/cgroup-v1/freezer-subsystem.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt)
11use std::io::{Read, Write};
12use std::path::PathBuf;
13
14use crate::fs::error::ErrorKind::*;
15use crate::fs::error::*;
16use crate::fs::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
17use crate::FreezerState;
18
19/// A controller that allows controlling the `freezer` subsystem of a Cgroup.
20///
21/// In essence, this subsystem allows the user to freeze and thaw (== "un-freeze") the processes in
22/// the control group. This is done _transparently_ so that neither the parent, nor the children of
23/// the processes can observe the freeze.
24///
25/// Note that if the control group is currently in the `Frozen` or `Freezing` state, then no
26/// processes can be added to it.
27#[derive(Debug, Clone)]
28pub struct FreezerController {
29    base: PathBuf,
30    path: PathBuf,
31    v2: bool,
32}
33
34impl ControllerInternal for FreezerController {
35    fn control_type(&self) -> Controllers {
36        Controllers::Freezer
37    }
38    fn get_path(&self) -> &PathBuf {
39        &self.path
40    }
41    fn get_path_mut(&mut self) -> &mut PathBuf {
42        &mut self.path
43    }
44    fn get_base(&self) -> &PathBuf {
45        &self.base
46    }
47
48    fn apply(&self, _res: &Resources) -> Result<()> {
49        Ok(())
50    }
51}
52
53impl ControllIdentifier for FreezerController {
54    fn controller_type() -> Controllers {
55        Controllers::Freezer
56    }
57}
58
59impl<'a> From<&'a Subsystem> for &'a FreezerController {
60    fn from(sub: &'a Subsystem) -> &'a FreezerController {
61        unsafe {
62            match sub {
63                Subsystem::Freezer(c) => c,
64                _ => {
65                    assert_eq!(1, 0);
66                    let v = std::mem::MaybeUninit::uninit();
67                    v.assume_init()
68                }
69            }
70        }
71    }
72}
73
74impl FreezerController {
75    /// Contructs a new `FreezerController` with `root` serving as the root of the control group.
76    pub fn new(point: PathBuf, root: PathBuf, v2: bool) -> Self {
77        Self {
78            base: root,
79            path: point,
80            v2,
81        }
82    }
83    /// Freezes the processes in the control group.
84    pub fn freeze(&self) -> Result<()> {
85        let mut file_name = "freezer.state";
86        let mut content = "FROZEN".to_string();
87        if self.v2 {
88            file_name = "cgroup.freeze";
89            content = "1".to_string();
90        }
91
92        self.open_path(file_name, true).and_then(|mut file| {
93            file.write_all(content.as_ref())
94                .map_err(|e| Error::with_cause(WriteFailed(file_name.to_string(), content), e))
95        })
96    }
97
98    /// Thaws, that is, unfreezes the processes in the control group.
99    pub fn thaw(&self) -> Result<()> {
100        let mut file_name = "freezer.state";
101        let mut content = "THAWED".to_string();
102        if self.v2 {
103            file_name = "cgroup.freeze";
104            content = "0".to_string();
105        }
106        self.open_path(file_name, true).and_then(|mut file| {
107            file.write_all(content.as_ref())
108                .map_err(|e| Error::with_cause(WriteFailed(file_name.to_string(), content), e))
109        })
110    }
111
112    /// Retrieve the state of processes in the control group.
113    pub fn state(&self) -> Result<FreezerState> {
114        let mut file_name = "freezer.state";
115        if self.v2 {
116            file_name = "cgroup.freeze";
117        }
118        self.open_path(file_name, false).and_then(|mut file| {
119            let mut s = String::new();
120            let res = file.read_to_string(&mut s);
121            match res {
122                Ok(_) => match s.trim() {
123                    "FROZEN" => Ok(FreezerState::Frozen),
124                    "THAWED" => Ok(FreezerState::Thawed),
125                    "1" => Ok(FreezerState::Frozen),
126                    "0" => Ok(FreezerState::Thawed),
127                    "FREEZING" => Ok(FreezerState::Freezing),
128                    _ => Err(Error::new(ParseError)),
129                },
130                Err(e) => Err(Error::with_cause(ReadFailed(file_name.to_string()), e)),
131            }
132        })
133    }
134}