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
next prev parent 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).