From: Demi Marie Obenour <demiobenour@gmail.com>
To: Alyssa Ross <hi@alyssa.is>
Cc: Spectrum OS Development <devel@spectrum-os.org>
Subject: Re: [PATCH v5 02/19] tools: Add control group manager
Date: Tue, 4 Aug 2026 21:36:00 -0400 [thread overview]
Message-ID: <2ce7b61d-faad-49b1-9f15-019140e2dca1@gmail.com> (raw)
In-Reply-To: <anB3K9GJBItOtZqx@fw12.qyliss.net>
[-- Attachment #1.1: Type: text/plain, Size: 23782 bytes --]
On 8/3/26 08:47, Alyssa Ross wrote:
> Demi Marie Obenour <demiobenour@gmail.com> writes:
>
>> The cgroup-setup Rust program can create and purge cgroups. It can also
>> wait for one to become empty, spawn a program in a cgroup, and more. In
>> the future, it will also support cgroup-based resource control. Locking
>> is used to ensure that concurrent invocations are safe.
>>
>> Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
>> ---
>> .codespellrc | 2 +-
>> host/rootfs/default.nix | 6 +-
>> pkgs/default.nix | 1 +
>> tools/cgroup-setup/Cargo.lock | 67 ++++++++
>> tools/cgroup-setup/Cargo.lock.license | 2 +
>> tools/cgroup-setup/Cargo.toml | 10 ++
>> tools/cgroup-setup/default.nix | 22 +++
>> tools/cgroup-setup/src/cgroup.rs | 308 ++++++++++++++++++++++++++++++++++
>> tools/cgroup-setup/src/main.rs | 186 ++++++++++++++++++++
>> 9 files changed, 600 insertions(+), 4 deletions(-)
>
> Looking much better, thank you!
>
>> +fn push_child_fds(fds: &mut Vec<(Rc<RefCell<Dir>>, PathBuf)>, fd: OwnedFd) {
>
> Would it not make more sense to take Dir than OwnedFd?
Easy fix.
>> + // The rustix source code shows that Dir::new() never fails.
>> + let child_fd = Rc::new(RefCell::new(Dir::new(fd).unwrap()));
>> + while let Some(element) = child_fd.borrow_mut().next() {
>> + let element = element.expect("Iterating through a cgroup directory failed?");
>> + if element.file_type() != rustix::fs::FileType::Directory {
>> + continue;
>> + }
>> + match element.file_name().to_bytes() {
>> + b"." | b".." => {}
>> + other => {
>> + let other = Path::new(OsStr::from_bytes(other)).to_owned();
>> + assert_single_component(&other);
>> + fds.push((child_fd.clone(), other));
>
> The data structures used here are still very confusing. Why are we
> storing a reference to the same file descriptor in every entry in the
> Vec?
Consider the recursive implementation (in pseudo-Rust):
fn recursive_remove(fd) {
for entry in get_entries(&fd) {
if entry.is_dir_and_not_dot_or_dotdot() {
let directory = open_dir(&fd, &entry.path())?;
recursive_remove(directory)?;
remove_dir(&fd, entry.path())?;
}
}
}
The compiler knows that fd will stay open through recursive calls,
so this doesn't need any unsafe code. Using an explicit stack takes
away this information from the compiler, so unsafe code is required.
Using Rc<RefCell<Dir>> avoids the need for unsafe code at a cost
in performance.
For what it is worth, the standard library implementation of
fs::remove_dir_all() is recursive. Standard library security hole?
>> + }
>> + }
>> + }
>> +}
>> +
>> +// Remove all subdirectories of the given directory recursively,
>> +// but not the directory itself. The directory file descriptor
>> +// is closed.
>> +//
>> +// This isn't the most efficient possible algorithm, but
>> +// simplicity is more important than performance in this
>> +// case. Also, it keeps open more file descriptors than
>> +// strictly necessary, but Spectrum runs with a very high
>> +// limit for the number of open file descriptors, and it
>> +// uses shallow control group hierarchies.
>> +fn remove_child_directories(dirfd: OwnedFd) -> Result<(), Errno> {
>> + let mut fds = Vec::new();
>> + // Push the children of this directory onto the stack.
>> + push_child_fds(&mut fds, dirfd);
>> + while let Some((d, path)) = fds.pop() {
>
> Couldn't we call push_child_fds() once here, rather than twice as is
> currently done? (And then consider inlining it, depending on how
> complex it's looking at the time.)
Can you provide an example? I don't see how to make this change
while preserving semantics. Only directories meant for deletion
can appear on the stack, and the root of the traversal must not
be deleted (yet).
>> + assert_single_component(&path);
>> + // Try to delete the directory. If that fails because there are child
>> + // directories, push the child directories onto the stack, then push
>> + // this directory again.
>> + match rustix::fs::unlinkat(
>> + // The rustix source code shows that Dir::fd() never fails.
>> + d.borrow().fd().unwrap(),
>> + &path,
>> + AtFlags::REMOVEDIR,
>> + ) {
>> + Err(Errno::NOTEMPTY) => {}
>> + Ok(()) => continue,
>> + Err(bad) => return Err(bad),
>> + }
>> + let fd = openat2_simple(
>> + // The rustix source code shows that Dir::fd() never fails.
>> + &d.borrow().fd().unwrap(),
>> + &path,
>> + OFlags::DIRECTORY | OFlags::RDONLY,
>> + )?;
>> + // Process child directories first, then attempt to delete the
>> + // directory again.
>> + fds.push((d, path));
>> + push_child_fds(&mut fds, fd);
>> + }
>> + Ok(())
>> +}
>
>> +impl Cgroup {
>> + pub fn open_beneath(&self, path: &Path, flags: OFlags) -> Result<OwnedFd, Errno> {
>> + openat2_simple(self, path, flags)
>> + }
>
> This method looks pretty redundant now.
Will remove.
>> + pub fn new(path: &Path) -> Result<Self, String> {
>> + let cgroup_root = rustix::fs::openat2(
>> + CWD,
>> + Path::new("/sys/fs/cgroup"),
>> + OFlags::CLOEXEC | OFlags::DIRECTORY | OFlags::RDONLY,
>> + Mode::empty(),
>> + ResolveFlags::NO_SYMLINKS | ResolveFlags::NO_MAGICLINKS,
>> + )
>> + .map_err(|e| format!("Cannot open /sys/fs/cgroup: {e}"))?;
>
> Can we not use openat2_simple here? It's missing e.g. NOCTTY.
NOCTTY is redundant with DIRECTORY, as directories can't be terminals.
openat2_simple() uses NO_XDEV, which won't work here because
/sys/fs/cgroup is not the same filesystem as /.
>> + let mut cgroup = Self {
>> + fd: vec![(cgroup_root)],
>> + };
>> +
>> + let path = prepend_current_cgroup_if_needed(path);
>> + for component in path.components() {
>> + let component = match component {
>> + Component::Normal(component) => component,
>> + _ => unreachable!(),
>> + };
>
> I think it would be slightly more idiomatic to do:
>
> let Component::Normal(component) = component else {
> unreachable!()
> };
Will fix in v6.
>> + let sub_fd = cgroup
>> + .open_beneath(Path::new(component), OFlags::RDONLY | OFlags::DIRECTORY)
>> + .map_err(|e| format!("Cannot open sub-cgroup {component:?}: {e}"))?;
>> + // Take a shared lock on the *previous* file descriptor.
>> + rustix::fs::flock(&cgroup, FlockOperation::LockShared)
>> + .map_err(|e| format!("Cannot lock sub-cgroup {component:?}: {e}"))?;
>> + cgroup.fd.push(sub_fd);
>> + }
>> + // Take an exclusive lock on the final file descriptor.
>> + rustix::fs::flock(&cgroup, FlockOperation::LockExclusive)
>> + .map_err(|e| format!("Cannot lock {path:?}: {e}"))?;
>> + Ok(cgroup)
>> + }
>> +
>> + pub fn wait_for_empty(fd: &dyn AsFd) -> std::io::Result<()> {
>> + let wait_file = openat2_simple(fd, Path::new("cgroup.events"), OFlags::RDONLY)?;
>> + let poll_fd = wait_file.as_raw_fd();
>> + let mut wait_fd = File::from(wait_file);
>> + let mut fds = libc::pollfd {
>> + fd: poll_fd,
>
> I would inline poll_fd here. RawFd is easy to misuse, so I like to
> avoid having them hang around.
I will move `fds` into the inner loop.
>> + events: libc::POLLPRI | libc::POLLERR,
>> + revents: 0,
>> + };
>> + let mut v = vec![];
>> + loop {
>> + v.clear();
>> + wait_fd
>> + .seek(std::io::SeekFrom::Start(0))
>> + .expect("Seek on control group file should succeed");
>> + wait_fd
>> + .read_to_end(&mut v)
>> + .expect("reading from control group should work");
>> + // Check that the cgroup isn't already empty. If it was,
>> + // the kernel would not send an event and poll() would wait
>> + // forever.
>> + if v.split(|&c| c == b'\n').any(|line| line == b"populated 0") {
>> + break;
>> + }
>> + // SAFETY: FFI call, valid arguments, fds contains 1 element
>> + if unsafe { libc::poll(&raw mut fds, 1, -1) } != 1 {
>> + panic!("poll failed");
>> + }
>> + }
>> + Ok(())
>> + }
>> +
>> + pub fn purge_child(&mut self, path: &Path) -> Result<(), String> {
>> + assert_single_component(path);
>> + // See if we can just delete the child directly.
>> + match rustix::fs::unlinkat(&self, Path::new(path), AtFlags::REMOVEDIR) {
>> + // If the cgroup was successfully deleted, or if it
>> + // has already been deleted, we are done.
>> + Ok(()) | Err(Errno::NOENT) => return Ok(()),
>> + // If this cgroup is in use, keep going.
>> + Err(Errno::BUSY) => {}
>> + Err(e) => return Err(format!("Cannot purge {path:?}: {e}")),
>> + }
>> +
>> + let sub_fd = match self.open_beneath(path, OFlags::RDONLY | OFlags::DIRECTORY) {
>> + Ok(sub_fd) => sub_fd,
>> + Err(Errno::NOENT) => return Ok(()),
>> + Err(e) => {
>> + return Err(format!("Cannot open sub-cgroup {path:?}: {e}",));
>> + }
>> + };
>> +
>> + // Take an exclusive lock on the cgroup that is about to be
>> + // removed. This avoids concurrent executions of this program
>> + // operating on deleted sub-cgroups.
>> + rustix::fs::flock(&sub_fd, FlockOperation::LockExclusive)
>> + .map_err(|e| format!("Cannot lock sub-cgroup: {e}"))?;
>> +
>> + // Drop the exclusive lock on the original cgroup,
>> + // This avoids blocking concurrent operations on other
>> + // child cgroups while the cgroup is being purged,
>> + // or while waiting for programs to exit.
>> + rustix::fs::flock(&self, FlockOperation::LockShared)
>> + .map_err(|e| format!("Cannot relock: {e}"))?;
>
> Could you add some extra explanation here of why it's okay for the
> exclusive lock to be temporarily dropped here?
>
> I'm wondering whether taking a lock, then dropping it temporarily is a
> sign that we're taking the lock too early in the first place, and should
> scope it better to where it's actually needed.
Indeed so. Programs that are modifying a cgroup need an exclusive
lock on it. Adding or removing to the cgroup does *not* count as
modification: both operations are idempotent, removing an in-use
cgroup fails with -EBUSY, and operating on a deleted cgroup fails
with -ENODEV or -ENOENT depending on what one is doing. Operations on
control files *do* require an exclusive lock.
>> +
>> + // Kill all processes in the child cgroup.
>> + write_value(&sub_fd, Path::new("cgroup.kill"), b"1")?;
>> +
>> + // Wait for the child cgroup to become empty.
>> + Self::wait_for_empty(&sub_fd)
>> + .map_err(|e| format!("Cannot wait for cgroup to become empty: {e}"))
>> + .inspect_err(|_| {
>> + self.fd.pop().unwrap();
>> + })?;
>> +
>> + // Remove the child cgroup and its contents recursively.
>> + remove_child_directories(sub_fd).map_err(|e| format!("Cannot remove: {e}"))?;
>> + // Re-take an exclusive lock on the parent of the cgroup being purged.
>> + // Otherwise, a concurrent instance of cgroup-setup might create a cgroup
>> + // only for this one to delete it. The other instance could then try to
>> + // create a sub-cgroup of a deleted cgroup, which would fail. Waiting
>> + // until nobody is using the parent cgroup ensures these problems can't
>> + // happen.
>> + //
>> + // This must happen *after* the lock on the cgroup being purged is released.
>> + // Another instance of the program might have a shared lock on the parent
>> + // and be waiting for an exclusive lock on the child. Trying to take an
>> + // exclusive lock on the parent while a lock is held on the child would
>> + // result in an ABBA deadlock.
>> + rustix::fs::flock(&self, FlockOperation::LockExclusive)
>> + .map_err(|e| format!("Cannot re-lock exclusively: {e}"))?;
>> + // Delete the cgroup. If it's been re-created in the meantime
>> + // and is currently in use, this is not an error. Another
>> + // process deleting the cgroup is also not an error. Both of
>> + // these can happen because of the time period between
>> + // remove_child_directories() closing the file descriptor
>> + // (releasing its lock) and the above call to flock().
>> + match rustix::fs::unlinkat(&self, path, AtFlags::REMOVEDIR) {
>> + Ok(()) | Err(Errno::BUSY) | Err(Errno::NOENT) => Ok(()),
>> + Err(e) => Err(format!("Cannot delete: {e}")),
>> + }
>> + }
>> +}
>> diff --git a/tools/cgroup-setup/src/main.rs b/tools/cgroup-setup/src/main.rs
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..e8d9e9d7c2111857cc25b36433d8f33ddb28c27b
>> --- /dev/null
>> +++ b/tools/cgroup-setup/src/main.rs
>> @@ -0,0 +1,186 @@
>> +// SPDX-License-Identifier: EUPL-1.2+
>> +// SPDX-FileCopyrightText: 2026 Demi Marie Obenour <demiobenour@gmail.com>
>> +
>> +mod cgroup;
>> +
>> +use cgroup::{Cgroup, openat2_simple, write_value};
>> +use rustix::{
>> + fs::{FlockOperation, Mode, OFlags, XattrFlags},
>> + io::Errno,
>> +};
>> +use std::{
>> + env::ArgsOs,
>> + ffi::OsStr,
>> + fs::File,
>> + io::Read as _,
>> + os::unix::prelude::*,
>> + path::{Path, PathBuf},
>> +};
>> +
>> +// Check that the path is canonical,
>> +// then split it into basename and filename.
>> +fn split_path(path: &Path) -> Result<(&Path, &Path), String> {
>> + cgroup::check_path(path)
>> + .map(|()| (path.parent().unwrap(), Path::new(path.file_name().unwrap())))
>
> Doing this with map rather than ? is a little strange.
Will change in v6.
>> +}
>> +
>> +fn read_control_file(fd: &dyn AsFd, p: &Path) -> Result<Vec<u8>, String> {
>> + let mut buf = Vec::new();
>> + File::from(
>> + openat2_simple(&fd, Path::new(p), OFlags::RDONLY)
>> + .map_err(|e| format!("Cannot open {p:?}: {e}"))?,
>> + )
>> + .read_to_end(&mut buf)
>> + .map_err(|e| format!("Cannot read {p:?}: {e}"))?;
>> + Ok(buf)
>> +}
>
> Nothing control-file-specific about this method. It just reads a file.
> And a bit odd for write_value to be in cgroup.rs while this is here.
It's only used once, so I'll inline it.
>> +
>> +fn enable_subtree_control(fd: &dyn AsFd) -> Result<(), String> {
>
> Would it not make sense for this to be an instance method on Cgroup,
> since it's a Cgroup-specific operation?
We don't create a Cgroup struct for the child cgroup
FD on which this function is called.
>> + let p = Path::new("cgroup.controllers");
>> + let buf = read_control_file(fd, p)?;
>
> p is only used here, so can just be inlined. If read_control_file took
> AsRef<Path> like the standard library functions do, you wouldn't even
> need to construct the path here.
I will just inline the whole read_control_file function.
It's only used once.
>> + let mut subtree = vec![];
>> + for controller in buf.split(|&b| b == b' ').filter(|e| !e.is_empty()) {
>
> Are there ever likely to be empty works in this file?
No, there will not be unless there is a kernel bug.
>> + if !subtree.is_empty() {
>> + subtree.push(b' ');
>> + }
>> + subtree.push(b'+');
>> + subtree.extend_from_slice(controller);
>> + }
>> + if !subtree.is_empty() {
>> + write_value(&fd, Path::new("cgroup.subtree_control"), &subtree)?;
>> + }
>> + Ok(())
>> +}
>> +
>> +fn cgroup_setup(mut args: ArgsOs) -> Result<(), String> {
>> + let mut leaf = false;
>> + let mut cgroup_path;
>> + let mut systemd_compat = false;
>> + let mut wait = true;
>> + loop {
>> + cgroup_path = args.next();
>> + let Some(ref arg_) = cgroup_path else {
>> + break;
>> + };
>> + let arg_ = arg_.as_bytes();
>> + if arg_ == b"--" {
>> + cgroup_path = args.next();
>
> This cgroup_path thing is a bit complicated. I feel like this could
> probably be cleaned up with a peekable iterator and a while loop.
Easy to fix.
>> + break;
>> + }
>> + if !arg_.starts_with(b"-") {
>> + break;
>> + }
>> +
>> + if !arg_.starts_with(b"--") {
>> + return Err("takes no short options".to_owned());
>> + }
>> +
>> + match &arg_[2..] {
>> + b"leaf" => leaf = true,
>> + b"wait" => wait = true,
>> + b"no-wait" => wait = false,
>> + b"systemd-compat" => systemd_compat = true,
>
> Why do we have --wait and --no-wait, but no --no-leaf or --no-systemd-compat?
Spectrum never needs --wait, so I'll remove it.
>> + arg => return Err(format!("unknown long option {:?}", OsStr::from_bytes(arg))),
>> + }
>> + }
>> + let Some(cgroup_path) = cgroup_path.map(PathBuf::from) else {
>> + return Err("have no positional arguments, expected at least 1".to_owned());
>> + };
>> +
>> + let (parent_cgroup_path, child_cgroup_path) = split_path(&cgroup_path)?;
>> + let cgroup = Cgroup::new(parent_cgroup_path)?;
>> + match rustix::fs::mkdirat(&cgroup, child_cgroup_path, Mode::from_raw_mode(0o755)) {
>> + Ok(()) | Err(Errno::EXIST) => {}
>> + Err(e) => return Err(format!("Cannot make child cgroup: {e}")),
>> + }
>> + let child = cgroup
>> + .open_beneath(child_cgroup_path, OFlags::RDONLY | OFlags::DIRECTORY)
>> + .map_err(|e| format!("Cannot make child cgroup: {e}"))?;
>> + if wait {
>> + // While waiting, only hold an exclusive lock on the child, not the parent.
>> + rustix::fs::flock(&child, FlockOperation::LockExclusive)
>> + .map_err(|e| format!("Cannot take an exclusive lock on child cgroup: {e}"))?;
>> + rustix::fs::flock(&cgroup, FlockOperation::LockShared)
>> + .map_err(|e| format!("Cannot downgrade lock on cgroup to a shared lock: {e}"))?;
>> + Cgroup::wait_for_empty(&child)
>> + .map_err(|e| format!("Cannot wait for {parent_cgroup_path:?} to be empty: {e}"))?;
>> + }
>> + let pid = std::process::id().to_string();
>> + if leaf {
>> + if args.len() != 0 {
>> + // If we aren't delegating any cgroups, don't create a sub-cgroup.
>> + write_value(&child, Path::new("cgroup.procs"), pid.as_bytes())
>> + .map_err(|e| format!("Cannot move process to child cgroup: {e}"))?;
>> + }
>> + } else {
>> + // If the child process will need to manage cgroups itself, it will need
>> + // to set up a sub-cgroup due to the "no internal processes" rule. It's
>> + // simplest to just do it automatically. If the cgroup already exists,
>> + // that isn't an error.
>> + match rustix::fs::mkdirat(&child, cgroup::DEFAULT_LEAF, Mode::from_raw_mode(0o755)) {
>> + Ok(()) | Err(Errno::EXIST) => {}
>> + Err(e) => return Err(format!("Cannot make child cgroup: {e}")),
>> + }
>> + if args.len() != 0 {
>> + let child_proc_path = Path::new(cgroup::DEFAULT_LEAF).join(Path::new("cgroup.procs"));
>> + write_value(&child, &child_proc_path, pid.as_bytes())
>> + .map_err(|e| format!("Cannot move process to child cgroup: {e}"))?;
>> + }
>> + if systemd_compat {
>> + // systemd-aware programs expect to have user.delegate=1
>> + // and to set cgroup.subtree_control themselves
>> + rustix::fs::fsetxattr(&child, c"user.delegate", b"1", XattrFlags::empty()).map_err(
>> + |e| format!("Cannot enable cgroup delegation in {parent_cgroup_path:?}: {e}"),
>> + )?
>> + } else {
>> + // Spectrum's programs do not check for user.delegate=1
>> + // and expect the caller to set cgroup.subtree_control.
>> + enable_subtree_control(&child)?;
>> + }
>> + }
>
> So looking at this I still see several different modes and am wondering
> whether we could simplify this further.
>
> • Why do we need a separate leaf mode? Why not just still use a
> $inner.service in that case?
$inner.service is just wasteful and makes it harder to inspect the cgroup
tree by hand.
> • What would the consequences be if we took the systemd_compat branch
> for a non-cgroup-aware Spectrum program?
Non-cgroup-aware programs would be fine, but nested calls to cgroup-setup
would break because they need the enable_subtree_control() call. However,
in the future, I would like to check the user.delegate xattr to determine
if one can safely write to the control files of the cgroup or if the cgroup
is owned by another program.
>> + let Some(program_name) = args.next() else {
>> + return Ok(());
>> + };
>> + let e = std::process::Command::new(&program_name).args(args).exec();
>> + Err(format!("Cannot spawn child {:?}: {}", program_name, e))
>> +}
>> +
>> +fn cgroup_purge(mut args: ArgsOs) -> Result<(), String> {
>> + if args.len() != 1 {
>> + return Err("usage: cgroup-purge CGROUP_TO_PURGE".to_owned());
>> + }
>> + let arg = args.next().unwrap();
>> + let (parent, child) = split_path(Path::new(&arg))?;
>> + Cgroup::new(parent)?.purge_child(child)
>> +}
>> +
>> +fn run(prog_name: &OsStr, args: ArgsOs) -> Result<(), String> {
>> + match prog_name
>> + .as_bytes()
>> + .split(|&b| b == b'/')
>> + .next_back()
>> + .unwrap()
>
> prog_name.file_name(), where prog_name is &Path?
Works for me :)
>> + {
>> + b"cgroup-setup" => cgroup_setup(args),
>> + b"cgroup-purge" => cgroup_purge(args),
>> + _ => Err(format!(
>> + "must be invoked as \"cgroup-setup\" or \
>> + \"cgroup-purge\", got {prog_name:?}",
>> + )),
>> + }
>> +}
>> +
>> +fn main() {
>> + let mut args = std::env::args_os();
>> + let Some(prog_name) = args.next() else {
>> + eprintln!("No command line arguments (argv[0] is NULL)");
>> + std::process::exit(1);
>> + };
>> + match run(&prog_name, args) {
>> + Ok(()) => {}
>> + Err(e) => {
>> + eprintln!("{prog_name:?}: {}", e);
>> + std::process::exit(1);
>> + }
>> + }
>> +}
>>
>> --
>> 2.55.0
--
Sincerely,
Demi Marie Obenour (she/her/hers)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2026-08-05 1:36 UTC|newest]
Thread overview: 132+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-20 14:23 [PATCH] Set up control groups for most services Demi Marie Obenour
2026-06-20 17:27 ` [PATCH v2] " Demi Marie Obenour
2026-06-24 12:13 ` Alyssa Ross
2026-06-24 12:36 ` Alyssa Ross
2026-06-25 2:03 ` Demi Marie Obenour
2026-06-25 3:03 ` Demi Marie Obenour
2026-06-25 9:55 ` Alyssa Ross
2026-06-25 9:49 ` Alyssa Ross
2026-07-11 20:12 ` [PATCH v3 00/22] Control group support Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 01/22] host/rootfs: Mount filesystems before s6-rc-init Demi Marie Obenour
2026-07-13 9:39 ` Alyssa Ross
2026-07-13 17:27 ` Demi Marie Obenour
2026-07-15 18:28 ` Alyssa Ross
2026-07-22 1:59 ` [PATCH v4 00/20] Control group support Demi Marie Obenour
2026-07-22 1:59 ` [PATCH v4 01/20] host/rootfs: Mount filesystems before s6-rc-init Demi Marie Obenour
2026-07-22 1:59 ` [PATCH v4 02/20] tools: Add control group manager Demi Marie Obenour
2026-07-22 16:01 ` Alyssa Ross
2026-07-23 23:07 ` Demi Marie Obenour
2026-07-27 12:10 ` Alyssa Ross
2026-07-30 0:40 ` Demi Marie Obenour
2026-07-30 14:53 ` Alyssa Ross
2026-07-22 1:59 ` [PATCH v4 03/20] Documentation: Mention control groups Demi Marie Obenour
2026-07-27 11:22 ` Alyssa Ross
2026-07-28 10:41 ` Valentin Gagarin
2026-07-22 1:59 ` [PATCH v4 04/20] Mount cgroup2 filesystem at /sys/fs/cgroup Demi Marie Obenour
2026-07-27 11:23 ` Alyssa Ross
2026-07-22 1:59 ` [PATCH v4 05/20] host/rootfs: Add helper program for per-VM services Demi Marie Obenour
2026-07-27 11:27 ` Alyssa Ross
2026-07-22 1:59 ` [PATCH v4 06/20] host/rootfs: Enable controllers in sub-cgroups Demi Marie Obenour
2026-07-27 12:11 ` Alyssa Ross
2026-07-28 2:19 ` Demi Marie Obenour
2026-07-29 14:13 ` Alyssa Ross
2026-07-22 1:59 ` [PATCH v4 07/20] host/rootfs: Add comments where cgroups are intentionally not used Demi Marie Obenour
2026-07-27 12:12 ` Alyssa Ross
2026-07-22 1:59 ` [PATCH v4 08/20] host/rootfs: serial-getty-generator: Use cgroups Demi Marie Obenour
2026-07-27 12:14 ` Alyssa Ross
2026-07-22 1:59 ` [PATCH v4 09/20] host/rootfs: Set up parent cgroup for all per-VM services Demi Marie Obenour
2026-07-27 12:16 ` Alyssa Ross
2026-07-28 3:01 ` Demi Marie Obenour
2026-07-29 14:29 ` Alyssa Ross
2026-07-29 20:20 ` Demi Marie Obenour
2026-07-22 1:59 ` [PATCH v4 10/20] host/rootfs: Create per-VM cgroup for all of the VM's services Demi Marie Obenour
2026-07-22 1:59 ` [PATCH v4 11/20] host/rootfs: run-vmm: Create per-VM cgroup Demi Marie Obenour
2026-07-22 1:59 ` [PATCH v4 12/20] host/rootfs: run-appimage: Purge the " Demi Marie Obenour
2026-07-27 12:18 ` Alyssa Ross
2026-07-22 1:59 ` [PATCH v4 13/20] host/rootfs: run-flatpak: " Demi Marie Obenour
2026-07-27 12:19 ` Alyssa Ross
2026-07-22 1:59 ` [PATCH v4 14/20] host/rootfs: dbus: Run in cgroup Demi Marie Obenour
2026-07-22 1:59 ` [PATCH v4 15/20] host/rootfs: vhost-user-fs: " Demi Marie Obenour
2026-07-22 1:59 ` [PATCH v4 16/20] host/rootfs: vhost-user-gpu: " Demi Marie Obenour
2026-07-22 1:59 ` [PATCH v4 17/20] host/rootfs: xdg-desktop-portal-spectrum-host: " Demi Marie Obenour
2026-07-22 1:59 ` [PATCH v4 18/20] host/rootfs: systemd-udevd: " Demi Marie Obenour
2026-07-27 12:20 ` Alyssa Ross
2026-07-28 3:11 ` Demi Marie Obenour
2026-07-29 14:15 ` Alyssa Ross
2026-07-29 20:39 ` Demi Marie Obenour
2026-07-30 14:55 ` Alyssa Ross
2026-07-22 1:59 ` [PATCH v4 19/20] host/rootfs: weston: " Demi Marie Obenour
2026-07-27 12:23 ` Alyssa Ross
2026-07-28 3:14 ` Demi Marie Obenour
2026-07-22 1:59 ` [PATCH v4 20/20] host/rootfs: spectrum-router: " Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 00/19] Control group support Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 01/19] host/rootfs: Mount filesystems before s6-rc-init Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 02/19] tools: Add control group manager Demi Marie Obenour
2026-08-03 12:47 ` Alyssa Ross
2026-08-05 1:36 ` Demi Marie Obenour [this message]
2026-08-05 16:39 ` Alyssa Ross
2026-07-31 21:54 ` [PATCH v5 03/19] Documentation: Mention control groups Demi Marie Obenour
2026-08-03 13:22 ` Alyssa Ross
2026-07-31 21:54 ` [PATCH v5 04/19] Mount cgroup2 filesystem at /sys/fs/cgroup Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 05/19] host/rootfs: Enable controllers in non-root cgroups Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 06/19] host/rootfs: Add comments where cgroups are intentionally not used Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 07/19] host/rootfs: serial-getty-generator: Use cgroups Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 08/19] host/rootfs: systemd-udevd: Run in cgroup Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 09/19] host/rootfs: weston: " Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 10/19] host/rootfs: Set up parent cgroup for all per-VM services Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 11/19] host/rootfs: Create per-VM cgroup for all of the VM's services Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 12/19] host/rootfs: run-vmm: Create per-VM cgroup Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 13/19] host/rootfs: run-appimage: Purge the " Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 14/19] host/rootfs: run-flatpak: " Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 15/19] host/rootfs: dbus: Run in cgroup Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 16/19] host/rootfs: vhost-user-fs: " Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 17/19] host/rootfs: vhost-user-gpu: " Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 18/19] host/rootfs: xdg-desktop-portal-spectrum-host: " Demi Marie Obenour
2026-07-31 21:54 ` [PATCH v5 19/19] host/rootfs: spectrum-router: " Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 00/19] Control group support Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 01/19] host/rootfs: Mount filesystems before s6-rc-init Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 02/19] tools: Add control group manager Demi Marie Obenour
2026-08-06 6:58 ` Demi Marie Obenour
2026-08-12 21:10 ` Alyssa Ross
2026-08-06 1:16 ` [PATCH v6 03/19] Documentation: Mention control groups Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 04/19] Mount cgroup2 filesystem at /sys/fs/cgroup Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 05/19] host/rootfs: Enable controllers in non-root cgroups Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 06/19] host/rootfs: Add comments where cgroups are intentionally not used Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 07/19] host/rootfs: serial-getty-generator: Use cgroups Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 08/19] host/rootfs: systemd-udevd: Run in cgroup Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 09/19] host/rootfs: weston: " Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 10/19] host/rootfs: Set up parent cgroup for all per-VM services Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 11/19] host/rootfs: Create per-VM cgroup for all of the VM's services Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 12/19] host/rootfs: run-vmm: Create per-VM cgroup Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 13/19] host/rootfs: run-appimage: Purge the " Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 14/19] host/rootfs: run-flatpak: " Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 15/19] host/rootfs: dbus: Run in cgroup Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 16/19] host/rootfs: vhost-user-fs: " Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 17/19] host/rootfs: vhost-user-gpu: " Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 18/19] host/rootfs: xdg-desktop-portal-spectrum-host: " Demi Marie Obenour
2026-08-06 1:16 ` [PATCH v6 19/19] host/rootfs: spectrum-router: " Demi Marie Obenour
2026-08-12 21:06 ` [PATCH v6 00/19] Control group support Alyssa Ross
2026-07-11 20:12 ` [PATCH v3 02/22] scripts: Support symlinks in s6-rc-compile inputs Demi Marie Obenour
2026-07-13 9:42 ` Alyssa Ross
2026-07-13 14:19 ` Demi Marie Obenour
2026-07-15 18:30 ` Alyssa Ross
2026-07-11 20:12 ` [PATCH v3 03/22] tools: Add control group manager Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 04/22] Documentation: Mention control groups Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 05/22] Mount cgroup2 filesystem at /sys/fs/cgroup Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 06/22] host/rootfs: Add helper program for per-VM services Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 07/22] host/rootfs: Enable controllers in sub-cgroups Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 08/22] host/rootfs: Add comments where cgroups are intentionally not used Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 09/22] host/rootfs: serial-getty-generator: Use cgroups Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 10/22] host/rootfs: Set up parent cgroup for all per-VM services Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 11/22] host/rootfs: Create per-VM cgroup for all of the VM's services Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 12/22] host/rootfs: run-vmm: Create per-VM cgroup Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 13/22] host/rootfs: run-appimage: Purge the " Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 14/22] host/rootfs: run-flatpak: " Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 15/22] host/rootfs: dbus: Run in cgroup Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 16/22] host/rootfs: vhost-user-fs: " Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 17/22] host/rootfs: vhost-user-gpu: " Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 18/22] host/rootfs: xdg-desktop-portal-spectrum-host: " Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 19/22] host/rootfs: systemd-udevd: " Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 20/22] host/rootfs: weston: " Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 21/22] host/rootfs: spectrum-router: " Demi Marie Obenour
2026-07-11 20:12 ` [PATCH v3 22/22] host/rootfs: vm-import: Use elglob -w Demi Marie Obenour
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2ce7b61d-faad-49b1-9f15-019140e2dca1@gmail.com \
--to=demiobenour@gmail.com \
--cc=devel@spectrum-os.org \
--cc=hi@alyssa.is \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://spectrum-os.org/git/doc
https://spectrum-os.org/git/mktuntap
https://spectrum-os.org/git/spectrum
https://spectrum-os.org/git/ucspi-vsock
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).