proj/portage:master commit in: lib/portage/, lib/portage/package/ebuild/
"Matt Turner" <[email protected]>
| Newsgroups | gmane.linux.gentoo.cvs |
|---|---|
| Message-ID | <1786149767.9939201fc009bebc80f1442ce013c51e94b227d8.mattst88@gentoo> |
commit: 9939201fc009bebc80f1442ce013c51e94b227d8
Author: Matt Turner <mattst88 <AT> gentoo <DOT> org>
AuthorDate: Sun Jun 14 16:23:51 2026 +0000
Commit: Matt Turner <mattst88 <AT> gentoo <DOT> org>
CommitDate: Sat Aug 8 00:42:47 2026 +0000
URL: https://gitweb.gentoo.org/proj/portage.git/commit/?id=9939201f
Place build process trees in a per-build cgroup
When FEATURES="cgroup" is set, doebuild creates the build's leaf cgroup
(keyed by cpv) and passes its path to spawn(). The child process writes
its own PID to cgroup.procs as the first action in _exec_wrapper, before
any unshare() or fork(). This avoids a race with pid-sandbox: if the
parent wrote the PID after the fork, the child could already have forked
the pid-ns-init helper before cgroup membership was established, so that
helper and its descendants would not be tracked. Writing from the child
ensures the entire process tree is in the cgroup before it branches.
cgroup membership is inherited across fork and exec, so all descendants
(compiler, linker, test processes, etc.) are automatically tracked.
Any OSError writing to cgroup.procs is warned and the build continues.
FEATURES=cgroup was previously used for cgroup v1 process containment
(removed in commit 8d300b0). This reuses the name because the feature
serves the same user-visible purpose of grouping a build's processes,
just on cgroup v2, which supersedes v1 on all current kernels.
Signed-off-by: Matt Turner <mattst88 <AT> gentoo.org>
lib/portage/package/ebuild/doebuild.py | 9 +++++++++
lib/portage/process.py | 13 +++++++++++++
2 files changed, 22 insertions(+)
diff --git a/lib/portage/package/ebuild/doebuild.py b/lib/portage/package/ebuild/doebuild.py
index 506df6390..a9e35190a 100644
--- a/lib/portage/package/ebuild/doebuild.py
+++ b/lib/portage/package/ebuild/doebuild.py
@@ -2071,6 +2071,15 @@ def spawn(
keywords["unshare_ipc"] = not ipc
keywords["unshare_mount"] = mountns
keywords["unshare_pid"] = pidns
+ if "cgroup" in features and mysettings.mycpv is not None:
+ from portage.util.cgroup import ensure_leaf, DEFAULT_CGROUP_ROOT
+
+ leaf = ensure_leaf(
+ mysettings.get("PORTAGE_CGROUP_ROOT", DEFAULT_CGROUP_ROOT),
+ str(mysettings.mycpv),
+ )
+ if leaf:
+ keywords["cgroup"] = leaf
if (
not networked
diff --git a/lib/portage/process.py b/lib/portage/process.py
index c66d040c9..37ed66a33 100644
--- a/lib/portage/process.py
+++ b/lib/portage/process.py
@@ -547,6 +547,7 @@ def spawn(
unshare_ipc=False,
unshare_mount=False,
unshare_pid=False,
+ cgroup=None,
warn_on_large_env=False,
) -> Union[int, MultiprocessingProcess, list[int]]:
"""
@@ -739,6 +740,7 @@ def spawn(
unshare_pid,
unshare_flags,
env_stats,
+ cgroup,
),
fd_pipes=fd_pipes,
close_fds=close_fds,
@@ -887,6 +889,7 @@ def _exec_wrapper(
unshare_pid,
unshare_flags,
env_stats,
+ cgroup=None,
):
"""
Calls _exec with the given args and handles any raised Exception.
@@ -895,6 +898,16 @@ def _exec_wrapper(
"""
from portage.util import writemsg
+ if cgroup:
+ try:
+ with open(os.path.join(cgroup, "cgroup.procs"), "w", encoding="ascii") as f:
+ f.write(str(os.getpid()))
+ except OSError as e:
+ writemsg(
+ f"!!! cgroup: cannot add pid {os.getpid()} to {cgroup}: {e}\n",
+ noiselevel=-1,
+ )
+
try:
_exec(
binary,