diff --git a/libcontainer/cgroups/cgroups.go b/libcontainer/cgroups/cgroups.go index 25ff5158..de835866 100644 --- a/libcontainer/cgroups/cgroups.go +++ b/libcontainer/cgroups/cgroups.go @@ -37,6 +37,13 @@ type Manager interface { // restore the object later. GetPaths() map[string]string + // GetUnifiedPath returns the unified path when running in unified mode. + // The value corresponds to the all values of GetPaths() map. + // + // GetUnifiedPath returns error when running in hybrid mode as well as + // in legacy mode. + GetUnifiedPath() (string, error) + // Sets the cgroup as configured. Set(container *configs.Config) error } diff --git a/libcontainer/cgroups/fs/apply_raw.go b/libcontainer/cgroups/fs/apply_raw.go index 512fd700..c3b6db83 100644 --- a/libcontainer/cgroups/fs/apply_raw.go +++ b/libcontainer/cgroups/fs/apply_raw.go @@ -224,6 +224,28 @@ func (m *Manager) GetPaths() map[string]string { return paths } +func (m *Manager) GetUnifiedPath() (string, error) { + if !cgroups.IsCgroup2UnifiedMode() { + return "", errors.New("unified path is only supported when running in unified mode") + } + unifiedPath := "" + m.mu.Lock() + defer m.mu.Unlock() + for k, v := range m.Paths { + if unifiedPath == "" { + unifiedPath = v + } else if v != unifiedPath { + return unifiedPath, + errors.Errorf("expected %q path to be unified path %q, got %q", k, unifiedPath, v) + } + } + if unifiedPath == "" { + // FIXME: unified path could be detected even when no controller is available + return unifiedPath, errors.New("cannot detect unified path") + } + return unifiedPath, nil +} + func (m *Manager) GetStats() (*cgroups.Stats, error) { m.mu.Lock() defer m.mu.Unlock() @@ -302,11 +324,25 @@ func (m *Manager) Freeze(state configs.FreezerState) error { } func (m *Manager) GetPids() ([]int, error) { + if cgroups.IsCgroup2UnifiedMode() { + path, err := m.GetUnifiedPath() + if err != nil { + return nil, err + } + return cgroups.GetPids(path) + } paths := m.GetPaths() return cgroups.GetPids(paths["devices"]) } func (m *Manager) GetAllPids() ([]int, error) { + if cgroups.IsCgroup2UnifiedMode() { + path, err := m.GetUnifiedPath() + if err != nil { + return nil, err + } + return cgroups.GetAllPids(path) + } paths := m.GetPaths() return cgroups.GetAllPids(paths["devices"]) } diff --git a/libcontainer/cgroups/systemd/apply_nosystemd.go b/libcontainer/cgroups/systemd/apply_nosystemd.go index c171365b..7fa91b18 100644 --- a/libcontainer/cgroups/systemd/apply_nosystemd.go +++ b/libcontainer/cgroups/systemd/apply_nosystemd.go @@ -42,6 +42,10 @@ func (m *Manager) GetPaths() map[string]string { return nil } +func (m *Manager) GetUnifiedPath() (string, error) { + return "", fmt.Errorf("Systemd not supported") +} + func (m *Manager) GetStats() (*cgroups.Stats, error) { return nil, fmt.Errorf("Systemd not supported") } diff --git a/libcontainer/cgroups/systemd/apply_systemd.go b/libcontainer/cgroups/systemd/apply_systemd.go index f274a49a..9a5aaec0 100644 --- a/libcontainer/cgroups/systemd/apply_systemd.go +++ b/libcontainer/cgroups/systemd/apply_systemd.go @@ -297,6 +297,10 @@ func (m *LegacyManager) GetPaths() map[string]string { return paths } +func (m *LegacyManager) GetUnifiedPath() (string, error) { + return "", errors.New("unified path is only supported when running in unified mode") +} + func join(c *configs.Cgroup, subsystem string, pid int) (string, error) { path, err := getSubsystemPath(c, subsystem) if err != nil { diff --git a/libcontainer/cgroups/systemd/unified_hierarchy.go b/libcontainer/cgroups/systemd/unified_hierarchy.go index d394e3a5..8737645c 100644 --- a/libcontainer/cgroups/systemd/unified_hierarchy.go +++ b/libcontainer/cgroups/systemd/unified_hierarchy.go @@ -16,6 +16,7 @@ import ( "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fs" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -195,7 +196,24 @@ func (m *UnifiedManager) GetPaths() map[string]string { m.mu.Unlock() return paths } - +func (m *UnifiedManager) GetUnifiedPath() (string, error) { + unifiedPath := "" + m.mu.Lock() + defer m.mu.Unlock() + for k, v := range m.Paths { + if unifiedPath == "" { + unifiedPath = v + } else if v != unifiedPath { + return unifiedPath, + errors.Errorf("expected %q path to be unified path %q, got %q", k, unifiedPath, v) + } + } + if unifiedPath == "" { + // FIXME: unified path could be detected even when no controller is available + return unifiedPath, errors.New("cannot detect unified path") + } + return unifiedPath, nil +} func createCgroupsv2Path(path string) (Err error) { content, err := ioutil.ReadFile("/sys/fs/cgroup/cgroup.controllers") if err != nil { @@ -270,7 +288,7 @@ func (m *UnifiedManager) Freeze(state configs.FreezerState) error { } func (m *UnifiedManager) GetPids() ([]int, error) { - path, err := getSubsystemPath(m.Cgroups, "devices") + path, err := m.GetUnifiedPath() if err != nil { return nil, err } @@ -278,7 +296,7 @@ func (m *UnifiedManager) GetPids() ([]int, error) { } func (m *UnifiedManager) GetAllPids() ([]int, error) { - path, err := getSubsystemPath(m.Cgroups, "devices") + path, err := m.GetUnifiedPath() if err != nil { return nil, err } diff --git a/libcontainer/container_linux_test.go b/libcontainer/container_linux_test.go index 0bf8803d..549c299a 100644 --- a/libcontainer/container_linux_test.go +++ b/libcontainer/container_linux_test.go @@ -54,6 +54,10 @@ func (m *mockCgroupManager) GetPaths() map[string]string { return m.paths } +func (m *mockCgroupManager) GetUnifiedPath() (string, error) { + return "", fmt.Errorf("unimplemented") +} + func (m *mockCgroupManager) Freeze(state configs.FreezerState) error { return nil }