From 43c82267c060f5b1c33c05c2341a43ef675482f6 Mon Sep 17 00:00:00 2001 From: David Trudgian Date: Tue, 1 Feb 2022 10:50:50 -0600 Subject: [PATCH] feat: enable native v2 unified cgroups config Allow the `unified` key to be used in a cgroups config toml file, to directly apply resource limits using the v2 unified hierarchy, rather than v1 -> v2 translation. Fixes: #538 --- CHANGELOG.md | 2 ++ internal/pkg/cgroups/config_linux.go | 4 ++-- .../pkg/cgroups/example/cgroups-unified.toml | 6 +++++ internal/pkg/cgroups/manager_linux.go | 5 ++--- internal/pkg/cgroups/manager_linux_v2_test.go | 22 +++++++++++++++++++ 5 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 internal/pkg/cgroups/example/cgroups-unified.toml diff --git a/CHANGELOG.md b/CHANGELOG.md index ab62610776..a2bf686efb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ - Updated seccomp support allows use of seccomp profiles that set an error return code with `errnoRet` and `defaultErrnoRet`. Previously EPERM was hard coded. The example `etc/seccomp-profiles/default.json` has been updated. +- Native cgroups v2 resource limits can be specified using the `[unified]` key + in a cgroups toml file applied via `--apply-cgroups`. ### Bug fixes diff --git a/internal/pkg/cgroups/config_linux.go b/internal/pkg/cgroups/config_linux.go index e34fbd84b8..9a2bb9cc55 100644 --- a/internal/pkg/cgroups/config_linux.go +++ b/internal/pkg/cgroups/config_linux.go @@ -167,8 +167,8 @@ type Config struct { // Limits are a set of key value pairs that define RDMA resource limits, // where the key is device name and value is resource limits. Rdma map[string]LinuxRdma `toml:"rdma" json:"rdma,omitempty"` - // TODO: Enable support for native cgroup v2 resource specifications - // Unified map[string]string `toml:"unified" json:"unified,omitempty"` + // Native cgroups v2 unified hierarchy resource limits. + Unified map[string]string `toml:"unified" json:"unified,omitempty"` } // LoadConfig loads a cgroups config file into our native cgroups.Config struct diff --git a/internal/pkg/cgroups/example/cgroups-unified.toml b/internal/pkg/cgroups/example/cgroups-unified.toml new file mode 100644 index 0000000000..942941141f --- /dev/null +++ b/internal/pkg/cgroups/example/cgroups-unified.toml @@ -0,0 +1,6 @@ +# +# Cgroups configuration file example using unified key for cgroups v2 only +# + +[unified] + "pids.max" = "512" diff --git a/internal/pkg/cgroups/manager_linux.go b/internal/pkg/cgroups/manager_linux.go index 8edac44eb4..3f0a68677e 100644 --- a/internal/pkg/cgroups/manager_linux.go +++ b/internal/pkg/cgroups/manager_linux.go @@ -67,8 +67,7 @@ func (m *Manager) GetCgroupRootPath() (rootPath string, err error) { } // UpdateFromSpec updates the existing managed cgroup using configuration from -// an OCI LinuxResources spec struct. The `Unified` key for native v2 cgroup -// specifications is not yet supported. +// an OCI LinuxResources spec struct. func (m *Manager) UpdateFromSpec(resources *specs.LinuxResources) (err error) { if m.group == "" || m.cgroup == nil { return ErrUnitialized @@ -106,7 +105,7 @@ func (m *Manager) UpdateFromSpec(resources *specs.LinuxResources) (err error) { func (m *Manager) UpdateFromFile(path string) error { spec, err := LoadResources(path) if err != nil { - return err + return fmt.Errorf("while loading cgroups file %s: %w", path, err) } return m.UpdateFromSpec(&spec) } diff --git a/internal/pkg/cgroups/manager_linux_v2_test.go b/internal/pkg/cgroups/manager_linux_v2_test.go index 2417f816fc..0b5fa0543b 100644 --- a/internal/pkg/cgroups/manager_linux_v2_test.go +++ b/internal/pkg/cgroups/manager_linux_v2_test.go @@ -25,6 +25,7 @@ func TestCgroupsV2(t *testing.T) { require.CgroupsV2Unified(t) t.Run("GetCgroupRootPath", testGetCgroupRootPathV2) t.Run("NewUpdate", testNewUpdateV2) + t.Run("UpdateUnified", testUpdateUnifiedV2) t.Run("AddProc", testAddProcV2) t.Run("FreezeThaw", testFreezeThawV2) } @@ -87,6 +88,27 @@ func testNewUpdateV2(t *testing.T) { ensureInt(t, pidsMax, 512) } +//nolint:dupl +func testUpdateUnifiedV2(t *testing.T) { + test.EnsurePrivilege(t) + require.CgroupsV2Unified(t) + + // Apply a 1024 pids.max limit using the v1 style config that sets [pids] limit + _, manager, cleanup := testManager(t) + defer cleanup() + pidsMax := filepath.Join("/sys/fs/cgroup", manager.group, "pids.max") + ensureInt(t, pidsMax, 1024) + + // Update existing cgroup from unified style config setting [Unified] pids.max directly + if err := manager.UpdateFromFile("example/cgroups-unified.toml"); err != nil { + t.Fatalf("While updating cgroup: %v", err) + } + + // Check pids.max is now 512 + ensureInt(t, pidsMax, 512) +} + +//nolint:dupl func testAddProcV2(t *testing.T) { test.EnsurePrivilege(t) require.CgroupsV2Unified(t)