patches and low-level development discussion
 help / color / mirror / code / Atom feed
From: Alyssa Ross <hi@alyssa.is>
To: Demi Marie Obenour <demiobenour@gmail.com>
Cc: Spectrum OS Development <devel@spectrum-os.org>
Subject: Re: [PATCH v5 02/19] tools: Add control group manager
Date: Mon, 3 Aug 2026 14:47:36 +0200	[thread overview]
Message-ID: <anB3K9GJBItOtZqx@fw12.qyliss.net> (raw)
In-Reply-To: <20260731-cgroups-v5-2-b325bac9d34f@gmail.com>

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?

> +    // 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?

> +            }
> +        }
> +    }
> +}
> +
> +// 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.)

> +        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.

> +    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.

> +        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!()
};

> +            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.

> +            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.

> +
> +        // 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.

> +}
> +
> +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.

> +
> +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?

> +    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.

> +    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?

> +        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.

> +            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?

> +            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?

 • What would the consequences be if we took the systemd_compat branch
   for a non-cgroup-aware Spectrum 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?

> +    {
> +        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

  reply	other threads:[~2026-08-03 12:47 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 [this message]
2026-08-05  1:36               ` Demi Marie Obenour
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=anB3K9GJBItOtZqx@fw12.qyliss.net \
    --to=hi@alyssa.is \
    --cc=demiobenour@gmail.com \
    --cc=devel@spectrum-os.org \
    /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).