From e0c0b0cf321252b8d964fc64d62d21f107615304 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Mon, 6 Jul 2020 20:51:06 -0700 Subject: [PATCH] libct/cgroups/GetCgroupRoot: make it faster ...by checking the default path first. Quick benchmark shows it's about 5x faster on an idle system, and the gain should be much more on a system doing mounts etc. Signed-off-by: Kir Kolyshkin --- libcontainer/cgroups/fs/fs.go | 58 ++++++++++++++++++++++++++++++ libcontainer/cgroups/fs/fs_test.go | 13 +++++++ 2 files changed, 71 insertions(+) diff --git a/libcontainer/cgroups/fs/fs.go b/libcontainer/cgroups/fs/fs.go index 949fc01d..150442e0 100644 --- a/libcontainer/cgroups/fs/fs.go +++ b/libcontainer/cgroups/fs/fs.go @@ -68,6 +68,56 @@ func NewManager(cg *configs.Cgroup, paths map[string]string, rootless bool) cgro var cgroupRootLock sync.Mutex var cgroupRoot string +const defaultCgroupRoot = "/sys/fs/cgroup" + +func tryDefaultCgroupRoot() string { + var st, pst unix.Stat_t + + // (1) it should be a directory... + err := unix.Lstat(defaultCgroupRoot, &st) + if err != nil || st.Mode&unix.S_IFDIR == 0 { + return "" + } + + // (2) ... and a mount point ... + err = unix.Lstat(filepath.Dir(defaultCgroupRoot), &pst) + if err != nil { + return "" + } + + if st.Dev == pst.Dev { + // parent dir has the same dev -- not a mount point + return "" + } + + // (3) ... of 'tmpfs' fs type. + var fst unix.Statfs_t + err = unix.Statfs(defaultCgroupRoot, &fst) + if err != nil || fst.Type != unix.TMPFS_MAGIC { + return "" + } + + // (4) it should have at least 1 entry ... + dir, err := os.Open(defaultCgroupRoot) + if err != nil { + return "" + } + names, err := dir.Readdirnames(1) + if err != nil { + return "" + } + if len(names) < 1 { + return "" + } + // ... which is a cgroup mount point. + err = unix.Statfs(filepath.Join(defaultCgroupRoot, names[0]), &fst) + if err != nil || fst.Type != unix.CGROUP_SUPER_MAGIC { + return "" + } + + return defaultCgroupRoot +} + // Gets the cgroupRoot. func getCgroupRoot() (string, error) { cgroupRootLock.Lock() @@ -77,6 +127,14 @@ func getCgroupRoot() (string, error) { return cgroupRoot, nil } + // fast path + cgroupRoot = tryDefaultCgroupRoot() + if cgroupRoot != "" { + return cgroupRoot, nil + } + + // slow path: parse mountinfo, find the first mount where fs=cgroup + // (e.g. "/sys/fs/cgroup/memory"), use its parent. f, err := os.Open("/proc/self/mountinfo") if err != nil { return "", err diff --git a/libcontainer/cgroups/fs/fs_test.go b/libcontainer/cgroups/fs/fs_test.go index 4971d547..2467dff0 100644 --- a/libcontainer/cgroups/fs/fs_test.go +++ b/libcontainer/cgroups/fs/fs_test.go @@ -295,3 +295,16 @@ func TestInvalidAbsoluteCgroupNameAndParent(t *testing.T) { t.Errorf("SECURITY: cgroup path() is outside cgroup mountpoint!") } } + +func TestTryDefaultCgroupRoot(t *testing.T) { + res := tryDefaultCgroupRoot() + exp := defaultCgroupRoot + if cgroups.IsCgroup2UnifiedMode() { + // checking that tryDefaultCgroupRoot does return "" + // in case /sys/fs/cgroup is not cgroup v1 root dir. + exp = "" + } + if res != exp { + t.Errorf("tryDefaultCgroupRoot: want %q, got %q", exp, res) + } +}