cgroups_rs/
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::error::ErrorKind::*;
15use crate::error::*;
16
17use crate::{ControllIdentifier, ControllerInternal, Controllers, Resources, Subsystem};
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
34/// The current state of the control group
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36pub enum FreezerState {
37    /// The processes in the control group are _not_ frozen.
38    Thawed,
39    /// The processes in the control group are in the processes of being frozen.
40    Freezing,
41    /// The processes in the control group are frozen.
42    Frozen,
43}
44
45impl ControllerInternal for FreezerController {
46    fn control_type(&self) -> Controllers {
47        Controllers::Freezer
48    }
49    fn get_path(&self) -> &PathBuf {
50        &self.path
51    }
52    fn get_path_mut(&mut self) -> &mut PathBuf {
53        &mut self.path
54    }
55    fn get_base(&self) -> &PathBuf {
56        &self.base
57    }
58
59    fn apply(&self, _res: &Resources) -> Result<()> {
60        Ok(())
61    }
62}
63
64impl ControllIdentifier for FreezerController {
65    fn controller_type() -> Controllers {
66        Controllers::Freezer
67    }
68}
69
70impl<'a> From<&'a Subsystem> for &'a FreezerController {
71    fn from(sub: &'a Subsystem) -> &'a FreezerController {
72        unsafe {
73            match sub {
74                Subsystem::Freezer(c) => c,
75                _ => {
76                    assert_eq!(1, 0);
77                    let v = std::mem::MaybeUninit::uninit();
78                    v.assume_init()
79                }
80            }
81        }
82    }
83}
84
85impl FreezerController {
86    /// Contructs a new `FreezerController` with `root` serving as the root of the control group.
87    pub fn new(root: PathBuf, v2: bool) -> Self {
88        Self {
89            base: root.clone(),
90            path: root,
91            v2,
92        }
93    }
94
95    /// Freezes the processes in the control group.
96    pub fn freeze(&self) -> Result<()> {
97        let mut file_name = "freezer.state";
98        let mut content = "FROZEN".to_string();
99        if self.v2 {
100            file_name = "cgroup.freeze";
101            content = "1".to_string();
102        }
103
104        self.open_path(file_name, true).and_then(|mut file| {
105            file.write_all(content.as_ref())
106                .map_err(|e| Error::with_cause(WriteFailed(file_name.to_string(), content), e))
107        })
108    }
109
110    /// Thaws, that is, unfreezes the processes in the control group.
111    pub fn thaw(&self) -> Result<()> {
112        let mut file_name = "freezer.state";
113        let mut content = "THAWED".to_string();
114        if self.v2 {
115            file_name = "cgroup.freeze";
116            content = "0".to_string();
117        }
118        self.open_path(file_name, true).and_then(|mut file| {
119            file.write_all(content.as_ref())
120                .map_err(|e| Error::with_cause(WriteFailed(file_name.to_string(), content), e))
121        })
122    }
123
124    /// Retrieve the state of processes in the control group.
125    pub fn state(&self) -> Result<FreezerState> {
126        let mut file_name = "freezer.state";
127        if self.v2 {
128            file_name = "cgroup.freeze";
129        }
130        self.open_path(file_name, false).and_then(|mut file| {
131            let mut s = String::new();
132            let res = file.read_to_string(&mut s);
133            match res {
134                Ok(_) => match s.trim() {
135                    "FROZEN" => Ok(FreezerState::Frozen),
136                    "THAWED" => Ok(FreezerState::Thawed),
137                    "1" => Ok(FreezerState::Frozen),
138                    "0" => Ok(FreezerState::Thawed),
139                    "FREEZING" => Ok(FreezerState::Freezing),
140                    _ => Err(Error::new(ParseError)),
141                },
142                Err(e) => Err(Error::with_cause(ReadFailed(file_name.to_string()), e)),
143            }
144        })
145    }
146}