Skip to content

Commit a4ade7d

Browse files
wintermelonsCQ Bot
authored andcommitted
[starnix][cgroup] Move FsNodes to Cgroup/CgroupRoot
CgroupDirectory is shared between Cgroup and CgroupRoot. However, some files should only exist in non-root cgroups, like cgroup.freezer which controls the Freezer. Test: cgroup syscall test Bug: 377712920 Change-Id: I449f3b731e67aae051e8dc657ac135f6a57d4144 Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/1163479 Reviewed-by: Adam Barth <[email protected]> Commit-Queue: David Song <[email protected]>
1 parent 7b820af commit a4ade7d

File tree

2 files changed

+124
-91
lines changed

2 files changed

+124
-91
lines changed

src/starnix/modules/cgroup/cgroup.rs

Lines changed: 122 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ use starnix_uapi::{errno, error, pid_t};
2727
use std::collections::btree_map::Entry;
2828
use std::collections::BTreeMap;
2929
use std::ops::Deref;
30-
use std::sync::{Arc, Weak};
30+
use std::sync::{Arc, OnceLock, Weak};
31+
32+
const CONTROLLERS_FILE: &str = "cgroup.controllers";
33+
const PROCS_FILE: &str = "cgroup.procs";
3134

3235
/// Common operations of all cgroups.
3336
pub trait CgroupOps: Send + Sync + 'static {
@@ -47,12 +50,12 @@ pub trait CgroupOps: Send + Sync + 'static {
4750
/// child with `name` is not found.
4851
fn remove_child(&self, name: &FsStr) -> Result<CgroupHandle, Errno>;
4952

50-
/// Return a `VecDirectoryEntry` for each child of the cgroup.
51-
fn get_directory_entries(&self) -> Vec<VecDirectoryEntry>;
53+
/// Return a `VecDirectoryEntry` for each interface file and each child.
54+
fn get_entries(&self) -> Vec<VecDirectoryEntry>;
5255

53-
/// Find a child with the given name and return its `node`, if exists. Errors if a child with
54-
/// `name` is not found.
55-
fn get_child_node(&self, name: &FsStr) -> Result<FsNodeHandle, Errno>;
56+
/// Find a child or interface file with the given name and return its `node`, if exists. Errors
57+
/// if such a node was not found.
58+
fn get_node(&self, name: &FsStr) -> Result<FsNodeHandle, Errno>;
5659

5760
/// Return all pids that belong to this cgroup.
5861
fn get_pids(&self) -> Vec<pid_t>;
@@ -73,20 +76,46 @@ pub trait CgroupOps: Send + Sync + 'static {
7376
pub struct CgroupRoot {
7477
/// Sub-cgroups of this cgroup.
7578
children: Mutex<CgroupChildren>,
79+
80+
/// Interface nodes of the root cgroup. Lazily by `init()` and immutable after.
81+
interface_nodes: OnceLock<BTreeMap<FsString, FsNodeHandle>>,
7682
}
7783
impl CgroupRoot {
84+
/// Since `CgroupRoot` is part of the `FileSystem` (see `CgroupFsV1::new_fs` and
85+
/// `CgroupFsV2::new_fs`), initializing a `CgroupRoot` has two steps:
86+
///
87+
/// - new() to create a `FileSystem`,
88+
/// - init() to use the newly created `FileSystem` to create the `FsNode`s of the `CgroupRoot`.
7889
pub fn new() -> Arc<CgroupRoot> {
7990
Arc::new(Self::default())
8091
}
8192

82-
/// Since the `FileSystem` owns the `FsNode` of the root node, create the `FsNodeOps` so that
83-
/// the `FileSystem` can create the `FsNode` of the root.
84-
pub fn create_node_ops(
85-
self: Arc<Self>,
86-
current_task: &CurrentTask,
87-
fs: &FileSystemHandle,
88-
) -> CgroupDirectoryHandle {
89-
CgroupDirectory::new(current_task, fs, Arc::downgrade(&(self as Arc<dyn CgroupOps>)))
93+
/// Populate `interface_nodes` with nodes of the cgroup root directory, then set
94+
/// `CgroupDirectoryHandle` to be the root node of the `FileSystem`. Can only be called once.
95+
pub fn init(self: &Arc<Self>, current_task: &CurrentTask, fs: &FileSystemHandle) {
96+
let cloned = self.clone();
97+
let weak_ops = Arc::downgrade(&(cloned as Arc<dyn CgroupOps>));
98+
self.interface_nodes
99+
.set(BTreeMap::from([
100+
(
101+
PROCS_FILE.into(),
102+
fs.create_node(
103+
current_task,
104+
ControlGroupNode::new(weak_ops.clone()),
105+
FsNodeInfo::new_factory(mode!(IFREG, 0o644), FsCred::root()),
106+
),
107+
),
108+
(
109+
CONTROLLERS_FILE.into(),
110+
fs.create_node(
111+
current_task,
112+
BytesFile::new_node(b"".to_vec()),
113+
FsNodeInfo::new_factory(mode!(IFREG, 0o444), FsCred::root()),
114+
),
115+
),
116+
]))
117+
.expect("CgroupRoot is only initialized once");
118+
fs.set_root(CgroupDirectory::new(weak_ops));
90119
}
91120
}
92121

@@ -111,14 +140,26 @@ impl CgroupOps for CgroupRoot {
111140
children.remove_child(name)
112141
}
113142

114-
fn get_directory_entries(&self) -> Vec<VecDirectoryEntry> {
143+
fn get_entries(&self) -> Vec<VecDirectoryEntry> {
144+
let entries = self.interface_nodes.get().expect("CgroupRoot is initialized").iter().map(
145+
|(name, child)| VecDirectoryEntry {
146+
entry_type: DirectoryEntryType::REG,
147+
name: name.clone(),
148+
inode: Some(child.info().ino),
149+
},
150+
);
115151
let children = self.children.lock();
116-
children.get_directory_entries()
152+
entries.chain(children.get_entries()).collect()
117153
}
118154

119-
fn get_child_node(&self, name: &FsStr) -> Result<FsNodeHandle, Errno> {
120-
let children = self.children.lock();
121-
children.get_node(name)
155+
fn get_node(&self, name: &FsStr) -> Result<FsNodeHandle, Errno> {
156+
if let Some(node) = self.interface_nodes.get().expect("CgroupRoot is initialized").get(name)
157+
{
158+
Ok(node.clone())
159+
} else {
160+
let children = self.children.lock();
161+
children.get_node(name)
162+
}
122163
}
123164

124165
fn get_pids(&self) -> Vec<pid_t> {
@@ -160,19 +201,16 @@ impl CgroupChildren {
160201
Ok(child_entry.remove())
161202
}
162203

163-
fn get_directory_entries(&self) -> Vec<VecDirectoryEntry> {
164-
self.0
165-
.iter()
166-
.map(|(name, child)| VecDirectoryEntry {
167-
entry_type: DirectoryEntryType::DIR,
168-
name: name.clone(),
169-
inode: Some(child.node.info().ino),
170-
})
171-
.collect()
204+
fn get_entries(&self) -> impl IntoIterator<Item = VecDirectoryEntry> + '_ {
205+
self.0.iter().map(|(name, child)| VecDirectoryEntry {
206+
entry_type: DirectoryEntryType::DIR,
207+
name: name.clone(),
208+
inode: Some(child.directory_node.info().ino),
209+
})
172210
}
173211

174212
fn get_node(&self, name: &FsStr) -> Result<FsNodeHandle, Errno> {
175-
self.0.get(name).map(|child| child.node.clone()).ok_or_else(|| errno!(ENOENT))
213+
self.0.get(name).map(|child| child.directory_node.clone()).ok_or_else(|| errno!(ENOENT))
176214
}
177215
}
178216

@@ -201,19 +239,43 @@ pub struct Cgroup {
201239
state: Mutex<CgroupState>,
202240

203241
/// The directory node associated with this control group.
204-
node: FsNodeHandle,
242+
directory_node: FsNodeHandle,
243+
244+
/// The interface nodes associated with this control group.
245+
interface_nodes: BTreeMap<FsString, FsNodeHandle>,
205246
}
206247
pub type CgroupHandle = Arc<Cgroup>;
207248

208249
impl Cgroup {
209250
pub fn new(current_task: &CurrentTask, fs: &FileSystemHandle) -> CgroupHandle {
210251
Arc::new_cyclic(|weak| {
211-
let node = fs.create_node(
212-
current_task,
213-
CgroupDirectory::new(current_task, fs, weak.clone() as Weak<dyn CgroupOps>),
214-
FsNodeInfo::new_factory(mode!(IFDIR, 0o755), FsCred::root()),
215-
);
216-
Self { state: Default::default(), node }
252+
let weak_ops = weak.clone() as Weak<dyn CgroupOps>;
253+
Self {
254+
state: Default::default(),
255+
directory_node: fs.create_node(
256+
current_task,
257+
CgroupDirectory::new(weak_ops.clone()),
258+
FsNodeInfo::new_factory(mode!(IFDIR, 0o755), FsCred::root()),
259+
),
260+
interface_nodes: BTreeMap::from([
261+
(
262+
PROCS_FILE.into(),
263+
fs.create_node(
264+
current_task,
265+
ControlGroupNode::new(weak_ops.clone()),
266+
FsNodeInfo::new_factory(mode!(IFREG, 0o644), FsCred::root()),
267+
),
268+
),
269+
(
270+
CONTROLLERS_FILE.into(),
271+
fs.create_node(
272+
current_task,
273+
BytesFile::new_node(b"".to_vec()),
274+
FsNodeInfo::new_factory(mode!(IFREG, 0o444), FsCred::root()),
275+
),
276+
),
277+
]),
278+
}
217279
})
218280
}
219281
}
@@ -249,14 +311,23 @@ impl CgroupOps for Cgroup {
249311
state.children.remove_child(name)
250312
}
251313

252-
fn get_directory_entries(&self) -> Vec<VecDirectoryEntry> {
314+
fn get_entries(&self) -> Vec<VecDirectoryEntry> {
315+
let entries = self.interface_nodes.iter().map(|(name, child)| VecDirectoryEntry {
316+
entry_type: DirectoryEntryType::REG,
317+
name: name.clone(),
318+
inode: Some(child.info().ino),
319+
});
253320
let state = self.state.lock();
254-
state.children.get_directory_entries()
321+
entries.chain(state.children.get_entries()).collect()
255322
}
256323

257-
fn get_child_node(&self, name: &FsStr) -> Result<FsNodeHandle, Errno> {
258-
let state = self.state.lock();
259-
state.children.get_node(name)
324+
fn get_node(&self, name: &FsStr) -> Result<FsNodeHandle, Errno> {
325+
if let Some(node) = self.interface_nodes.get(name) {
326+
Ok(node.clone())
327+
} else {
328+
let state = self.state.lock();
329+
state.children.get_node(name)
330+
}
260331
}
261332

262333
fn get_pids(&self) -> Vec<pid_t> {
@@ -280,33 +351,11 @@ impl CgroupOps for Cgroup {
280351
pub struct CgroupDirectory {
281352
/// The associated cgroup.
282353
cgroup: Weak<dyn CgroupOps>,
283-
284-
/// Node that backs `cgroup.procs`
285-
procs_node: FsNodeHandle,
286-
287-
/// Node that backs `cgroup.controllers`
288-
controllers_node: FsNodeHandle,
289354
}
290355

291356
impl CgroupDirectory {
292-
pub fn new(
293-
current_task: &CurrentTask,
294-
fs: &FileSystemHandle,
295-
cgroup: Weak<dyn CgroupOps>,
296-
) -> CgroupDirectoryHandle {
297-
let procs_node = fs.create_node(
298-
current_task,
299-
ControlGroupNode::new(cgroup.clone()),
300-
FsNodeInfo::new_factory(mode!(IFREG, 0o644), FsCred::root()),
301-
);
302-
303-
let controllers_node = fs.create_node(
304-
current_task,
305-
BytesFile::new_node(b"".to_vec()),
306-
FsNodeInfo::new_factory(mode!(IFREG, 0o444), FsCred::root()),
307-
);
308-
309-
CgroupDirectoryHandle(Arc::new(Self { cgroup, procs_node, controllers_node }))
357+
pub fn new(cgroup: Weak<dyn CgroupOps>) -> CgroupDirectoryHandle {
358+
CgroupDirectoryHandle(Arc::new(Self { cgroup }))
310359
}
311360
}
312361

@@ -335,22 +384,7 @@ impl FsNodeOps for CgroupDirectoryHandle {
335384
_current_task: &CurrentTask,
336385
_flags: OpenFlags,
337386
) -> Result<Box<dyn FileOps>, Errno> {
338-
let mut entries = vec![
339-
VecDirectoryEntry {
340-
entry_type: DirectoryEntryType::REG,
341-
name: FsString::from("cgroup.procs"),
342-
inode: Some(self.procs_node.info().ino),
343-
},
344-
VecDirectoryEntry {
345-
entry_type: DirectoryEntryType::REG,
346-
name: FsString::from("cgroup.controllers"),
347-
inode: Some(self.controllers_node.info().ino),
348-
},
349-
];
350-
351-
entries.extend(self.cgroup()?.get_directory_entries());
352-
353-
Ok(VecDirectory::new_file(entries))
387+
Ok(VecDirectory::new_file(self.cgroup()?.get_entries()))
354388
}
355389

356390
fn mkdir(
@@ -366,7 +400,7 @@ impl FsNodeOps for CgroupDirectoryHandle {
366400
node.update_info(|info| {
367401
info.link_count += 1;
368402
});
369-
Ok(child.node.clone())
403+
Ok(child.directory_node.clone())
370404
}
371405

372406
fn mknod(
@@ -385,7 +419,7 @@ impl FsNodeOps for CgroupDirectoryHandle {
385419
fn unlink(
386420
&self,
387421
_locked: &mut Locked<'_, FileOpsCore>,
388-
_node: &FsNode,
422+
node: &FsNode,
389423
_current_task: &CurrentTask,
390424
name: &FsStr,
391425
child: &FsNodeHandle,
@@ -401,6 +435,10 @@ impl FsNodeOps for CgroupDirectoryHandle {
401435
let removed = cgroup.remove_child(name)?;
402436
assert!(Arc::ptr_eq(&(removed as Arc<dyn CgroupOps>), &child_cgroup));
403437

438+
node.update_info(|info| {
439+
info.link_count -= 1;
440+
});
441+
404442
Ok(())
405443
}
406444

@@ -423,12 +461,7 @@ impl FsNodeOps for CgroupDirectoryHandle {
423461
_current_task: &CurrentTask,
424462
name: &FsStr,
425463
) -> Result<FsNodeHandle, Errno> {
426-
let cgroup = self.cgroup()?;
427-
match &**name {
428-
b"cgroup.controllers" => Ok(self.controllers_node.clone()),
429-
b"cgroup.procs" => Ok(self.procs_node.clone()),
430-
_ => cgroup.get_child_node(name),
431-
}
464+
self.cgroup()?.get_node(name)
432465
}
433466
}
434467

src/starnix/modules/cgroup/fs.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ impl CgroupV1Fs {
3333
CgroupV1Fs { root: root.clone() },
3434
options,
3535
)?;
36-
fs.set_root(root.create_node_ops(current_task, &fs));
36+
root.init(current_task, &fs);
3737
Ok(fs)
3838
}
3939
}
@@ -70,7 +70,7 @@ impl CgroupV2Fs {
7070
CgroupV2Fs { root: root.clone() },
7171
options,
7272
)?;
73-
fs.set_root(root.create_node_ops(current_task, &fs));
73+
root.init(current_task, &fs);
7474
Ok(fs)
7575
}
7676
}

0 commit comments

Comments
 (0)