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") +}