From 601c779d645132c4e78ff0d3ffe3e949bd5a9168 Mon Sep 17 00:00:00 2001 From: Filipe Brandenburger Date: Thu, 22 Aug 2019 09:17:38 -0700 Subject: [PATCH] Split support for unified cgroup2 hierarchy into its own Manager Detection is done only once, as the manager is instantiated, and then the two implementations are for the most part separate. This will allow us to iterate on the unified cgroup2 implementation without worrying about compatibility with the legacy implementation. For now, the unified cgroup2 implementation consists of stubs that need to be filled up with actual implementation. Signed-off-by: Filipe Brandenburger --- libcontainer/cgroups/systemd/apply_systemd.go | 43 ++++++++----- .../cgroups/systemd/unified_hierarchy.go | 62 +++++++++++++++++++ 2 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 libcontainer/cgroups/systemd/unified_hierarchy.go diff --git a/libcontainer/cgroups/systemd/apply_systemd.go b/libcontainer/cgroups/systemd/apply_systemd.go index 3bf723bf964..d4be87820c5 100644 --- a/libcontainer/cgroups/systemd/apply_systemd.go +++ b/libcontainer/cgroups/systemd/apply_systemd.go @@ -22,7 +22,7 @@ import ( "github.com/sirupsen/logrus" ) -type Manager struct { +type LegacyManager struct { mu sync.Mutex Cgroups *configs.Cgroup Paths map[string]string @@ -167,15 +167,28 @@ func NewSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]s if !systemdUtil.IsRunningSystemd() { return nil, fmt.Errorf("systemd not running on this host, can't use systemd as a cgroups.Manager") } - return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { - return &Manager{ - Cgroups: config, - Paths: paths, - } - }, nil + unified, err := IsCgroup2UnifiedMode() + if err != nil { + return nil, err + } + if unified { + return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { + return &UnifiedManager{ + Cgroups: config, + Paths: paths, + } + }, nil + } else { + return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { + return &LegacyManager{ + Cgroups: config, + Paths: paths, + } + }, nil + } } -func (m *Manager) Apply(pid int) error { +func (m *LegacyManager) Apply(pid int) error { var ( c = m.Cgroups unitName = getUnitName(c) @@ -325,7 +338,7 @@ func (m *Manager) Apply(pid int) error { return nil } -func (m *Manager) Destroy() error { +func (m *LegacyManager) Destroy() error { if m.Cgroups.Paths != nil { return nil } @@ -339,7 +352,7 @@ func (m *Manager) Destroy() error { return nil } -func (m *Manager) GetPaths() map[string]string { +func (m *LegacyManager) GetPaths() map[string]string { m.mu.Lock() paths := m.Paths m.mu.Unlock() @@ -456,7 +469,7 @@ func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) { return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil } -func (m *Manager) Freeze(state configs.FreezerState) error { +func (m *LegacyManager) Freeze(state configs.FreezerState) error { path, err := getSubsystemPath(m.Cgroups, "freezer") if err != nil { return err @@ -475,7 +488,7 @@ func (m *Manager) Freeze(state configs.FreezerState) error { return nil } -func (m *Manager) GetPids() ([]int, error) { +func (m *LegacyManager) GetPids() ([]int, error) { path, err := getSubsystemPath(m.Cgroups, "devices") if err != nil { return nil, err @@ -483,7 +496,7 @@ func (m *Manager) GetPids() ([]int, error) { return cgroups.GetPids(path) } -func (m *Manager) GetAllPids() ([]int, error) { +func (m *LegacyManager) GetAllPids() ([]int, error) { path, err := getSubsystemPath(m.Cgroups, "devices") if err != nil { return nil, err @@ -491,7 +504,7 @@ func (m *Manager) GetAllPids() ([]int, error) { return cgroups.GetAllPids(path) } -func (m *Manager) GetStats() (*cgroups.Stats, error) { +func (m *LegacyManager) GetStats() (*cgroups.Stats, error) { m.mu.Lock() defer m.mu.Unlock() stats := cgroups.NewStats() @@ -508,7 +521,7 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) { return stats, nil } -func (m *Manager) Set(container *configs.Config) error { +func (m *LegacyManager) Set(container *configs.Config) error { // If Paths are set, then we are just joining cgroups paths // and there is no need to set any values. if m.Cgroups.Paths != nil { diff --git a/libcontainer/cgroups/systemd/unified_hierarchy.go b/libcontainer/cgroups/systemd/unified_hierarchy.go new file mode 100644 index 00000000000..fd50f98e4e7 --- /dev/null +++ b/libcontainer/cgroups/systemd/unified_hierarchy.go @@ -0,0 +1,62 @@ +// +build linux,!static_build + +package systemd + +import ( + "fmt" + "syscall" + + "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/configs" + "golang.org/x/sys/unix" +) + +// IsCgroup2UnifiedMode returns whether we are running in cgroup v2 unified mode. +func IsCgroup2UnifiedMode() (bool, error) { + var st syscall.Statfs_t + if err := syscall.Statfs("/sys/fs/cgroup", &st); err != nil { + return false, fmt.Errorf("cannot statfs cgroup root: %v", err) + } + return st.Type == unix.CGROUP2_SUPER_MAGIC, nil +} + +type UnifiedManager struct { + Cgroups *configs.Cgroup + Paths map[string]string +} + +func NewUnifiedSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]string) cgroups.Manager, error) { + return nil, fmt.Errorf("unified hierarchy not supported") +} + +func (m *UnifiedManager) Apply(pid int) error { + return fmt.Errorf("unified hierarchy not supported") +} + +func (m *UnifiedManager) GetPids() ([]int, error) { + return nil, fmt.Errorf("unified hierarchy not supported") +} + +func (m *UnifiedManager) GetAllPids() ([]int, error) { + return nil, fmt.Errorf("unified hierarchy not supported") +} + +func (m *UnifiedManager) Destroy() error { + return fmt.Errorf("unified hierarchy not supported") +} + +func (m *UnifiedManager) GetPaths() map[string]string { + return nil +} + +func (m *UnifiedManager) GetStats() (*cgroups.Stats, error) { + return nil, fmt.Errorf("unified hierarchy not supported") +} + +func (m *UnifiedManager) Set(container *configs.Config) error { + return fmt.Errorf("unified hierarchy not supported") +} + +func (m *UnifiedManager) Freeze(state configs.FreezerState) error { + return fmt.Errorf("unified hierarchy not supported") +}