[1.4] libct: move exec sub-cgroup handling down the line

Remove cgroupPaths field from struct setnsProcess, because:
 - we can get base cgroup paths from p.manager.GetPaths();
 - we can get sub-cgroup paths from p.process.SubCgroupPaths.

But mostly because we are going to need separate cgroup paths when
adopting cgroups.AddPid.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
(cherry picked from commit 5730a141f1)
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
This commit is contained in:
Kir Kolyshkin
2025-07-25 17:19:00 -07:00
committed by Aleksa Sarai
parent f19a4c7122
commit 7db9930fab
2 changed files with 32 additions and 39 deletions
-31
View File
@@ -7,7 +7,6 @@ import (
"io"
"os"
"os/exec"
"path"
"path/filepath"
"reflect"
"strconv"
@@ -655,40 +654,10 @@ func (c *Container) newSetnsProcess(p *Process, cmd *exec.Cmd, comm *processComm
bootstrapData: data,
container: c,
},
cgroupPaths: state.CgroupPaths,
rootlessCgroups: c.config.RootlessCgroups,
intelRdtPath: state.IntelRdtPath,
initProcessPid: state.InitProcessPid,
}
if len(p.SubCgroupPaths) > 0 {
if add, ok := p.SubCgroupPaths[""]; ok {
// cgroup v1: using the same path for all controllers.
// cgroup v2: the only possible way.
for k := range proc.cgroupPaths {
subPath := path.Join(proc.cgroupPaths[k], add)
if !strings.HasPrefix(subPath, proc.cgroupPaths[k]) {
return nil, fmt.Errorf("%s is not a sub cgroup path", add)
}
proc.cgroupPaths[k] = subPath
}
// cgroup v2: do not try to join init process's cgroup
// as a fallback (see (*setnsProcess).start).
proc.initProcessPid = 0
} else {
// Per-controller paths.
for ctrl, add := range p.SubCgroupPaths {
if val, ok := proc.cgroupPaths[ctrl]; ok {
subPath := path.Join(val, add)
if !strings.HasPrefix(subPath, val) {
return nil, fmt.Errorf("%s is not a sub cgroup path", add)
}
proc.cgroupPaths[ctrl] = subPath
} else {
return nil, fmt.Errorf("unknown controller %s in SubCgroupPaths", ctrl)
}
}
}
}
return proc, nil
}
+32 -8
View File
@@ -6,12 +6,15 @@ import (
"errors"
"fmt"
"io"
"maps"
"net"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"sync"
"time"
@@ -153,7 +156,6 @@ func (p *containerProcess) wait() (*os.ProcessState, error) { //nolint:unparam
type setnsProcess struct {
containerProcess
cgroupPaths map[string]string
rootlessCgroups bool
intelRdtPath string
initProcessPid int
@@ -245,7 +247,20 @@ func (p *setnsProcess) setFinalCPUAffinity() error {
}
func (p *setnsProcess) addIntoCgroupV1() error {
for _, path := range p.cgroupPaths {
paths := maps.Clone(p.manager.GetPaths())
for ctrl, sub := range p.process.SubCgroupPaths {
base, ok := paths[ctrl]
if !ok {
return fmt.Errorf("unknown controller %s in SubCgroupPaths", ctrl)
}
cgPath := path.Join(base, sub)
if !strings.HasPrefix(cgPath, base) {
return fmt.Errorf("%s is not a sub cgroup path", sub)
}
paths[ctrl] = cgPath
}
for _, path := range paths {
if err := cgroups.WriteCgroupProc(path, p.pid()); err != nil && !p.rootlessCgroups {
return fmt.Errorf("error adding pid %d to cgroups: %w", p.pid(), err)
}
@@ -255,19 +270,28 @@ func (p *setnsProcess) addIntoCgroupV1() error {
}
func (p *setnsProcess) addIntoCgroupV2() error {
path := p.cgroupPaths[""]
if err := cgroups.WriteCgroupProc(path, p.pid()); err != nil && !p.rootlessCgroups {
base := p.manager.Path("")
sub := ""
if p.process.SubCgroupPaths != nil {
sub = p.process.SubCgroupPaths[""]
}
cgPath := path.Join(base, sub)
if !strings.HasPrefix(cgPath, base) {
return fmt.Errorf("%s is not a sub cgroup path", sub)
}
if err := cgroups.WriteCgroupProc(cgPath, p.pid()); err != nil && !p.rootlessCgroups {
// On cgroup v2 + nesting + domain controllers, WriteCgroupProc may fail with EBUSY.
// https://github.com/opencontainers/runc/issues/2356#issuecomment-621277643
// Try to join the cgroup of InitProcessPid.
if p.initProcessPid != 0 {
// Try to join the cgroup of InitProcessPid, unless sub-cgroup is explicitly set.
if p.initProcessPid != 0 && sub == "" {
initProcCgroupFile := fmt.Sprintf("/proc/%d/cgroup", p.initProcessPid)
initCg, initCgErr := cgroups.ParseCgroupFile(initProcCgroupFile)
if initCgErr == nil {
if initCgPath, ok := initCg[""]; ok {
initCgDirpath := filepath.Join(fs2.UnifiedMountpoint, initCgPath)
logrus.Debugf("adding pid %d to cgroups %v failed (%v), attempting to join %q (obtained from %s)",
p.pid(), p.cgroupPaths, err, initCg, initCgDirpath)
logrus.Debugf("adding pid %d to cgroup %s failed (%v), attempting to join %s",
p.pid(), cgPath, err, initCgDirpath)
// NOTE: initCgDirPath is not guaranteed to exist because we didn't pause the container.
err = cgroups.WriteCgroupProc(initCgDirpath, p.pid())
}