Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions libcontainer/cgroups/fs/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,26 +179,25 @@ func (m *manager) Apply(pid int) (err error) {

var c = m.cgroups

d, err := getCgroupData(m.cgroups, pid)
if err != nil {
return err
}

m.paths = make(map[string]string)
if c.Paths != nil {
for name, path := range c.Paths {
_, err := d.path(name)
cgMap, err := cgroups.ParseCgroupFile("/proc/self/cgroup")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a check to see whether the subsystem is available. I am not quite sure in which scenario such a check is required. Maybe we need to just drop it.

if err != nil {
if cgroups.IsNotFound(err) {
continue
}
return err
}
m.paths[name] = path
if _, ok := cgMap[name]; ok {
m.paths[name] = path
}
}
return cgroups.EnterPid(m.paths, pid)
}

d, err := getCgroupData(m.cgroups, pid)
if err != nil {
return err
}

for _, sys := range m.getSubsystems() {
p, err := d.path(sys.Name())
if err != nil {
Expand Down
14 changes: 6 additions & 8 deletions libcontainer/cgroups/systemd/v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,16 +116,14 @@ func (m *legacyManager) Apply(pid int) error {
defer m.mu.Unlock()
if c.Paths != nil {
paths := make(map[string]string)
cgMap, err := cgroups.ParseCgroupFile("/proc/self/cgroup")
if err != nil {
return err
}
for name, path := range c.Paths {
_, err := getSubsystemPath(m.cgroups, name)
if err != nil {
// Don't fail if a cgroup hierarchy was not found, just skip this subsystem
if cgroups.IsNotFound(err) {
continue
}
return err
if _, ok := cgMap[name]; ok {
paths[name] = path
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

}
paths[name] = path
}
m.paths = paths
return cgroups.EnterPid(m.paths, pid)
Expand Down
58 changes: 55 additions & 3 deletions libcontainer/cgroups/v1_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"os"
"path/filepath"
"strings"
"syscall"

securejoin "github.com/cyphar/filepath-securejoin"
"golang.org/x/sys/unix"
)

// Code in this source file are specific to cgroup v1,
Expand All @@ -19,6 +23,8 @@ const (

var (
errUnified = errors.New("not implemented for cgroup v2 unified hierarchy")

defaultPrefix = "/sys/fs/cgroup"
)

type NotFoundError struct {
Expand All @@ -43,11 +49,59 @@ func IsNotFound(err error) bool {
return ok
}

func tryDefaultPath(cgroupPath, subsystem string) string {
if !strings.HasPrefix(defaultPrefix, cgroupPath) {
return ""
}

// remove possible prefix
subsystem = strings.TrimPrefix(subsystem, CgroupNamePrefix)

// Make sure we're still under defaultPrefix, and resolve
// a possible symlink (like cpu -> cpu,cpuacct).
path, err := securejoin.SecureJoin(defaultPrefix, subsystem)
if err != nil {
return ""
}

// (1) path should be a directory.
st, err := os.Lstat(path)
if err != nil || !st.IsDir() {
return ""
}

// (2) path should be a mount point.
pst, err := os.Lstat(filepath.Dir(path))
if err != nil {
return ""
}

if st.Sys().(*syscall.Stat_t).Dev == pst.Sys().(*syscall.Stat_t).Dev {
// parent dir has the same dev -- path is not a mount point
return ""
}

// (3) path should have 'cgroup' fs type.
fst := unix.Statfs_t{}
err = unix.Statfs(path, &fst)
if err != nil || fst.Type != unix.CGROUP_SUPER_MAGIC {
return ""
}

return path
}

// https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt
func FindCgroupMountpoint(cgroupPath, subsystem string) (string, error) {
if IsCgroup2UnifiedMode() {
return "", errUnified
}

// Avoid parsing mountinfo by trying the default path first, if possible.
if path := tryDefaultPath(cgroupPath, subsystem); path != "" {
return path, nil
}

mnt, _, err := FindCgroupMountpointAndRoot(cgroupPath, subsystem)
return mnt, err
}
Expand All @@ -57,9 +111,7 @@ func FindCgroupMountpointAndRoot(cgroupPath, subsystem string) (string, string,
return "", "", errUnified
}

// We are not using mount.GetMounts() because it's super-inefficient,
// parsing it directly sped up x10 times because of not using Sscanf.
// It was one of two major performance drawbacks in container start.
// Avoid parsing mountinfo by checking if subsystem is valid/available
if !isSubsystemAvailable(subsystem) {
return "", "", NewNotFoundError(subsystem)
}
Expand Down