diff --git a/libcontainer/cgroups/cgroups.go b/libcontainer/cgroups/cgroups.go index c0a965923f9..10487fdd80c 100644 --- a/libcontainer/cgroups/cgroups.go +++ b/libcontainer/cgroups/cgroups.go @@ -40,9 +40,9 @@ type Manager interface { // 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 + // GetUnifiedPath panics when running in hybrid mode as well as // in legacy mode. - GetUnifiedPath() (string, error) + GetUnifiedPath() string // 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 59ce5ea6b78..74283905c09 100644 --- a/libcontainer/cgroups/fs/apply_raw.go +++ b/libcontainer/cgroups/fs/apply_raw.go @@ -208,8 +208,8 @@ func (m *Manager) GetPaths() map[string]string { return paths } -func (m *Manager) GetUnifiedPath() (string, error) { - return "", errors.New("unified path is only supported when running in unified mode") +func (m *Manager) GetUnifiedPath() string { + panic("GetUnifiedPath is only supported when running in unified mode") } func (m *Manager) GetStats() (*cgroups.Stats, error) { diff --git a/libcontainer/cgroups/fs2/fs2.go b/libcontainer/cgroups/fs2/fs2.go index fc469e10377..971ddf24766 100644 --- a/libcontainer/cgroups/fs2/fs2.go +++ b/libcontainer/cgroups/fs2/fs2.go @@ -164,22 +164,12 @@ func (m *manager) Destroy() error { return nil } -// GetPaths is for compatibility purpose and should be removed in future func (m *manager) GetPaths() map[string]string { - _ = m.getControllers() - paths := map[string]string{ - // pseudo-controller for compatibility - "devices": m.dirPath, - "freezer": m.dirPath, - } - for c := range m.controllers { - paths[c] = m.dirPath - } - return paths + panic("GetPaths can only be used for cgroupv1") } -func (m *manager) GetUnifiedPath() (string, error) { - return m.dirPath, nil +func (m *manager) GetUnifiedPath() string { + return m.dirPath } func (m *manager) Set(container *configs.Config) error { diff --git a/libcontainer/cgroups/systemd/unsupported.go b/libcontainer/cgroups/systemd/unsupported.go index 5318a1e9188..30d97ad8f7f 100644 --- a/libcontainer/cgroups/systemd/unsupported.go +++ b/libcontainer/cgroups/systemd/unsupported.go @@ -42,8 +42,8 @@ func (m *Manager) GetPaths() map[string]string { return nil } -func (m *Manager) GetUnifiedPath() (string, error) { - return "", fmt.Errorf("Systemd not supported") +func (m *Manager) GetUnifiedPath() string { + return "" } func (m *Manager) GetStats() (*cgroups.Stats, error) { diff --git a/libcontainer/cgroups/systemd/v1.go b/libcontainer/cgroups/systemd/v1.go index 8bac7ca23c9..8b3bc6bc802 100644 --- a/libcontainer/cgroups/systemd/v1.go +++ b/libcontainer/cgroups/systemd/v1.go @@ -228,8 +228,8 @@ 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 (m *LegacyManager) GetUnifiedPath() string { + panic("GetUnifiedPath is only supported when running in unified mode") } func join(c *configs.Cgroup, subsystem string, pid int) (string, error) { diff --git a/libcontainer/cgroups/systemd/v2.go b/libcontainer/cgroups/systemd/v2.go index 77f7696e39b..6ba661b457c 100644 --- a/libcontainer/cgroups/systemd/v2.go +++ b/libcontainer/cgroups/systemd/v2.go @@ -144,8 +144,7 @@ func (m *unifiedManager) Apply(pid int) error { return err } - _, err = m.GetUnifiedPath() - if err != nil { + if err = m.initPath(); err != nil { return err } if err := fs2.CreateCgroupPath(m.path, m.cgroups); err != nil { @@ -175,26 +174,18 @@ func (m *unifiedManager) Destroy() error { return nil } -// this method is for v1 backward compatibility and will be removed +// must not be called for this controller func (m *unifiedManager) GetPaths() map[string]string { - _, _ = m.GetUnifiedPath() - paths := map[string]string{ - "pids": m.path, - "memory": m.path, - "io": m.path, - "cpu": m.path, - "devices": m.path, - "cpuset": m.path, - "freezer": m.path, - } - return paths + panic("GetPaths can only be used for cgroupv1") } -func (m *unifiedManager) GetUnifiedPath() (string, error) { - m.mu.Lock() - defer m.mu.Unlock() +func (m *unifiedManager) GetUnifiedPath() string { + return m.path +} + +func (m *unifiedManager) initPath() error { if m.path != "" { - return m.path, nil + return nil } c := m.cgroups @@ -205,25 +196,24 @@ func (m *unifiedManager) GetUnifiedPath() (string, error) { slice, err := ExpandSlice(slice) if err != nil { - return "", err + return err } path := filepath.Join(slice, getUnitName(c)) path, err = securejoin.SecureJoin(fs2.UnifiedMountpoint, path) if err != nil { - return "", err + return err } m.path = path - return m.path, nil + return nil } func (m *unifiedManager) fsManager() (cgroups.Manager, error) { - path, err := m.GetUnifiedPath() - if err != nil { + if err := m.initPath(); err != nil { return nil, err } - return fs2.NewManager(m.cgroups, path, m.rootless) + return fs2.NewManager(m.cgroups, m.path, m.rootless) } func (m *unifiedManager) Freeze(state configs.FreezerState) error { @@ -235,19 +225,17 @@ func (m *unifiedManager) Freeze(state configs.FreezerState) error { } func (m *unifiedManager) GetPids() ([]int, error) { - path, err := m.GetUnifiedPath() - if err != nil { + if err := m.initPath(); err != nil { return nil, err } - return cgroups.GetPids(path) + return cgroups.GetPids(m.path) } func (m *unifiedManager) GetAllPids() ([]int, error) { - path, err := m.GetUnifiedPath() - if err != nil { + if err := m.initPath(); err != nil { return nil, err } - return cgroups.GetAllPids(path) + return cgroups.GetAllPids(m.path) } func (m *unifiedManager) GetStats() (*cgroups.Stats, error) { diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go index 96bc66b2e63..aaaf838103f 100644 --- a/libcontainer/container_linux.go +++ b/libcontainer/container_linux.go @@ -64,8 +64,10 @@ type State struct { // Set to true if BaseState.Config.RootlessEUID && BaseState.Config.RootlessCgroups Rootless bool `json:"rootless"` - // Path to all the cgroups setup for a container. Key is cgroup subsystem name - // with the value as the path. + // Path to all the cgroups setup for a container. For cgroup v1, + // a key is cgroup subsystem name, and the value as the path. + // For cgroup v2, a key is the empty string, and the value + // is the unified cgroup path. CgroupPaths map[string]string `json:"cgroup_paths"` // NamespacePaths are filepaths to the container's namespaces. Key is the namespace type @@ -551,9 +553,18 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockP if err != nil { return nil, err } + var paths map[string]string + if cgroups.IsCgroup2UnifiedMode() { + // there's only one path to enter, add it to the map + paths = make(map[string]string, 1) + paths[""] = c.cgroupManager.GetUnifiedPath() + } else { + paths = c.cgroupManager.GetPaths() + } + return &setnsProcess{ cmd: cmd, - cgroupPaths: c.cgroupManager.GetPaths(), + cgroupPaths: paths, rootlessCgroups: c.config.RootlessCgroups, intelRdtPath: state.IntelRdtPath, messageSockPair: messageSockPair, @@ -1023,11 +1034,7 @@ func (c *linuxContainer) Checkpoint(criuOpts *CriuOpts) error { case true: // cgroup v2 freezer is only supported since CRIU release 3.14 if c.checkCriuVersion(31400) == nil { - fcg, err = c.cgroupManager.GetUnifiedPath() - if err != nil { - // should not happen - return err - } + fcg = c.cgroupManager.GetUnifiedPath() } } if fcg != "" { @@ -1861,12 +1868,7 @@ func (c *linuxContainer) isPaused() (bool, error) { filename = "freezer.state" pausedState = "FROZEN" } else { - var err error - fcg, err = c.cgroupManager.GetUnifiedPath() - if err != nil { - // should not happen - return false, err - } + fcg = c.cgroupManager.GetUnifiedPath() filename = "cgroup.freeze" pausedState = "1" } @@ -1906,11 +1908,17 @@ func (c *linuxContainer) currentState() (*State, error) { Created: c.created, }, Rootless: c.config.RootlessEUID && c.config.RootlessCgroups, - CgroupPaths: c.cgroupManager.GetPaths(), IntelRdtPath: intelRdtPath, NamespacePaths: make(map[configs.NamespaceType]string), ExternalDescriptors: externalDescriptors, } + if cgroups.IsCgroup2UnifiedMode() { + paths := make(map[string]string, 1) + paths[""] = c.cgroupManager.GetUnifiedPath() + state.CgroupPaths = paths + } else { + state.CgroupPaths = c.cgroupManager.GetPaths() + } if pid > 0 { for _, ns := range c.config.Namespaces { state.NamespacePaths[ns.Type] = ns.GetPath(pid) diff --git a/libcontainer/container_linux_test.go b/libcontainer/container_linux_test.go index 583c1c0c2fd..1607267c1de 100644 --- a/libcontainer/container_linux_test.go +++ b/libcontainer/container_linux_test.go @@ -55,8 +55,8 @@ func (m *mockCgroupManager) GetPaths() map[string]string { return m.paths } -func (m *mockCgroupManager) GetUnifiedPath() (string, error) { - return m.unifiedPath, nil +func (m *mockCgroupManager) GetUnifiedPath() string { + return m.unifiedPath } func (m *mockCgroupManager) Freeze(state configs.FreezerState) error { @@ -199,6 +199,7 @@ func TestGetContainerState(t *testing.T) { var ( pid = os.Getpid() expectedMemoryPath = "/sys/fs/cgroup/memory/myid" + expectedUnifiedPath = "/sys/fs/cgroup/myid" expectedNetworkPath = fmt.Sprintf("/proc/%d/ns/net", pid) expectedIntelRdtPath = "/sys/fs/resctrl/myid" ) @@ -228,9 +229,12 @@ func TestGetContainerState(t *testing.T) { }, }, }, + // cgroupv1 paths: map[string]string{ "memory": expectedMemoryPath, }, + // cgroupv2 + unifiedPath: expectedUnifiedPath, }, intelRdtManager: &mockIntelRdtManager{ stats: &intelrdt.Stats{ @@ -255,8 +259,16 @@ func TestGetContainerState(t *testing.T) { if paths == nil { t.Fatal("cgroup paths should not be nil") } - if memPath := paths["memory"]; memPath != expectedMemoryPath { - t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath) + if cgroups.IsCgroup2UnifiedMode() { + // cgroupv2 + if path := paths[""]; path != expectedUnifiedPath { + t.Fatalf("expected memory path %q but received %q", expectedUnifiedPath, path) + } + } else { + // cgroupv1 + if memPath := paths["memory"]; memPath != expectedMemoryPath { + t.Fatalf("expected memory path %q but received %q", expectedMemoryPath, memPath) + } } if intelrdt.IsCatEnabled() || intelrdt.IsMbaEnabled() { intelRdtPath := state.IntelRdtPath