|
 |
1adcb1 |
From bbe03e61a375416180432fbd9d00d23a7c2a4714 Mon Sep 17 00:00:00 2001
|
|
 |
1adcb1 |
From: Giuseppe Scrivano <gscrivan@redhat.com>
|
|
 |
1adcb1 |
Date: Mon, 8 Jul 2019 10:16:13 +0200
|
|
 |
1adcb1 |
Subject: [PATCH] cgroups: support creating cgroupsv2 paths
|
|
 |
1adcb1 |
|
|
 |
1adcb1 |
drop the limitation of not supporting creating new cgroups v2 paths.
|
|
 |
1adcb1 |
Every controller enabled /sys/fs/cgroup will be propagated down to the
|
|
 |
1adcb1 |
created path. This won't work for rootless cgroupsv2, but it is not
|
|
 |
1adcb1 |
an issue for now, as this code is used only by CRI-O.
|
|
 |
1adcb1 |
|
|
 |
1adcb1 |
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
|
|
 |
1adcb1 |
---
|
|
 |
1adcb1 |
pkg/cgroups/blkio.go | 2 +-
|
|
 |
1adcb1 |
pkg/cgroups/cgroups.go | 52 +++++++++++++++++++++++++++++++++++++++++-
|
|
 |
1adcb1 |
pkg/cgroups/cpu.go | 2 +-
|
|
 |
1adcb1 |
pkg/cgroups/cpuset.go | 19 +++++++++------
|
|
 |
1adcb1 |
pkg/cgroups/memory.go | 2 +-
|
|
 |
1adcb1 |
pkg/cgroups/pids.go | 3 ---
|
|
 |
1adcb1 |
6 files changed, 66 insertions(+), 14 deletions(-)
|
|
 |
1adcb1 |
|
|
 |
1adcb1 |
diff --git a/pkg/cgroups/blkio.go b/pkg/cgroups/blkio.go
|
|
 |
1adcb1 |
index ca9107d977..9c2a811d9e 100644
|
|
 |
1adcb1 |
--- a/pkg/cgroups/blkio.go
|
|
 |
1adcb1 |
+++ b/pkg/cgroups/blkio.go
|
|
 |
1adcb1 |
@@ -30,7 +30,7 @@ func (c *blkioHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) error
|
|
 |
1adcb1 |
// Create the cgroup
|
|
 |
1adcb1 |
func (c *blkioHandler) Create(ctr *CgroupControl) (bool, error) {
|
|
 |
1adcb1 |
if ctr.cgroup2 {
|
|
 |
1adcb1 |
- return false, fmt.Errorf("io create not implemented for cgroup v2")
|
|
 |
1adcb1 |
+ return false, nil
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
return ctr.createCgroupDirectory(Blkio)
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go
|
|
 |
1adcb1 |
index d6c19212bc..1dad45d7f7 100644
|
|
 |
1adcb1 |
--- a/pkg/cgroups/cgroups.go
|
|
 |
1adcb1 |
+++ b/pkg/cgroups/cgroups.go
|
|
 |
1adcb1 |
@@ -149,6 +149,51 @@ func (c *CgroupControl) getCgroupv1Path(name string) string {
|
|
 |
1adcb1 |
return filepath.Join(cgroupRoot, name, c.path)
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
|
|
 |
1adcb1 |
+// createCgroupv2Path creates the cgroupv2 path and enables all the available controllers
|
|
 |
1adcb1 |
+func createCgroupv2Path(path string) (Err error) {
|
|
 |
1adcb1 |
+ content, err := ioutil.ReadFile("/sys/fs/cgroup/cgroup.controllers")
|
|
 |
1adcb1 |
+ if err != nil {
|
|
 |
1adcb1 |
+ return errors.Wrapf(err, "read /sys/fs/cgroup/cgroup.controllers")
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ if !filepath.HasPrefix(path, "/sys/fs/cgroup") {
|
|
 |
1adcb1 |
+ return fmt.Errorf("invalid cgroup path %s", path)
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+
|
|
 |
1adcb1 |
+ res := ""
|
|
 |
1adcb1 |
+ for i, c := range strings.Split(strings.TrimSpace(string(content)), " ") {
|
|
 |
1adcb1 |
+ if i == 0 {
|
|
 |
1adcb1 |
+ res = fmt.Sprintf("+%s", c)
|
|
 |
1adcb1 |
+ } else {
|
|
 |
1adcb1 |
+ res = res + fmt.Sprintf(" +%s", c)
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ resByte := []byte(res)
|
|
 |
1adcb1 |
+
|
|
 |
1adcb1 |
+ current := "/sys/fs"
|
|
 |
1adcb1 |
+ elements := strings.Split(path, "/")
|
|
 |
1adcb1 |
+ for i, e := range elements[3:] {
|
|
 |
1adcb1 |
+ current = filepath.Join(current, e)
|
|
 |
1adcb1 |
+ if i > 0 {
|
|
 |
1adcb1 |
+ if err := os.Mkdir(current, 0755); err != nil {
|
|
 |
1adcb1 |
+ if !os.IsExist(err) {
|
|
 |
1adcb1 |
+ return errors.Wrapf(err, "mkdir %s", path)
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ } else {
|
|
 |
1adcb1 |
+ // If the directory was created, be sure it is not left around on errors.
|
|
 |
1adcb1 |
+ defer func() {
|
|
 |
1adcb1 |
+ if Err != nil {
|
|
 |
1adcb1 |
+ os.Remove(current)
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ }()
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ if err := ioutil.WriteFile(filepath.Join(current, "cgroup.subtree_control"), resByte, 0755); err != nil {
|
|
 |
1adcb1 |
+ return errors.Wrapf(err, "write %s", filepath.Join(current, "cgroup.subtree_control"))
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ return nil
|
|
 |
1adcb1 |
+}
|
|
 |
1adcb1 |
+
|
|
 |
1adcb1 |
// initialize initializes the specified hierarchy
|
|
 |
1adcb1 |
func (c *CgroupControl) initialize() (err error) {
|
|
 |
1adcb1 |
createdSoFar := map[string]controllerHandler{}
|
|
 |
1adcb1 |
@@ -161,6 +206,11 @@ func (c *CgroupControl) initialize() (err error) {
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
}()
|
|
 |
1adcb1 |
+ if c.cgroup2 {
|
|
 |
1adcb1 |
+ if err := createCgroupv2Path(filepath.Join(cgroupRoot, c.path)); err != nil {
|
|
 |
1adcb1 |
+ return errors.Wrapf(err, "error creating cgroup path %s", c.path)
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
for name, handler := range handlers {
|
|
 |
1adcb1 |
created, err := handler.Create(c)
|
|
 |
1adcb1 |
if err != nil {
|
|
 |
1adcb1 |
@@ -341,7 +391,7 @@ func (c *CgroupControl) AddPid(pid int) error {
|
|
 |
1adcb1 |
pidString := []byte(fmt.Sprintf("%d\n", pid))
|
|
 |
1adcb1 |
|
|
 |
1adcb1 |
if c.cgroup2 {
|
|
 |
1adcb1 |
- p := filepath.Join(cgroupRoot, c.path, "tasks")
|
|
 |
1adcb1 |
+ p := filepath.Join(cgroupRoot, c.path, "cgroup.procs")
|
|
 |
1adcb1 |
if err := ioutil.WriteFile(p, pidString, 0644); err != nil {
|
|
 |
1adcb1 |
return errors.Wrapf(err, "write %s", p)
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
diff --git a/pkg/cgroups/cpu.go b/pkg/cgroups/cpu.go
|
|
 |
1adcb1 |
index 8640d490e6..c9325946b4 100644
|
|
 |
1adcb1 |
--- a/pkg/cgroups/cpu.go
|
|
 |
1adcb1 |
+++ b/pkg/cgroups/cpu.go
|
|
 |
1adcb1 |
@@ -61,7 +61,7 @@ func (c *cpuHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) error {
|
|
 |
1adcb1 |
// Create the cgroup
|
|
 |
1adcb1 |
func (c *cpuHandler) Create(ctr *CgroupControl) (bool, error) {
|
|
 |
1adcb1 |
if ctr.cgroup2 {
|
|
 |
1adcb1 |
- return false, fmt.Errorf("cpu create not implemented for cgroup v2")
|
|
 |
1adcb1 |
+ return false, nil
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
return ctr.createCgroupDirectory(CPU)
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
diff --git a/pkg/cgroups/cpuset.go b/pkg/cgroups/cpuset.go
|
|
 |
1adcb1 |
index 9aef493c9f..25d2f7f769 100644
|
|
 |
1adcb1 |
--- a/pkg/cgroups/cpuset.go
|
|
 |
1adcb1 |
+++ b/pkg/cgroups/cpuset.go
|
|
 |
1adcb1 |
@@ -14,19 +14,23 @@ import (
|
|
 |
1adcb1 |
type cpusetHandler struct {
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
|
|
 |
1adcb1 |
-func cpusetCopyFileFromParent(dir, file string) ([]byte, error) {
|
|
 |
1adcb1 |
+func cpusetCopyFileFromParent(dir, file string, cgroupv2 bool) ([]byte, error) {
|
|
 |
1adcb1 |
if dir == cgroupRoot {
|
|
 |
1adcb1 |
return nil, fmt.Errorf("could not find parent to initialize cpuset %s", file)
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
path := filepath.Join(dir, file)
|
|
 |
1adcb1 |
- data, err := ioutil.ReadFile(path)
|
|
 |
1adcb1 |
+ parentPath := path
|
|
 |
1adcb1 |
+ if cgroupv2 {
|
|
 |
1adcb1 |
+ parentPath = fmt.Sprintf("%s.effective", parentPath)
|
|
 |
1adcb1 |
+ }
|
|
 |
1adcb1 |
+ data, err := ioutil.ReadFile(parentPath)
|
|
 |
1adcb1 |
if err != nil {
|
|
 |
1adcb1 |
return nil, errors.Wrapf(err, "open %s", path)
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
if len(strings.Trim(string(data), "\n")) != 0 {
|
|
 |
1adcb1 |
return data, nil
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
- data, err = cpusetCopyFileFromParent(filepath.Dir(dir), file)
|
|
 |
1adcb1 |
+ data, err = cpusetCopyFileFromParent(filepath.Dir(dir), file, cgroupv2)
|
|
 |
1adcb1 |
if err != nil {
|
|
 |
1adcb1 |
return nil, err
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
@@ -36,9 +40,9 @@ func cpusetCopyFileFromParent(dir, file string) ([]byte, error) {
|
|
 |
1adcb1 |
return data, nil
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
|
|
 |
1adcb1 |
-func cpusetCopyFromParent(path string) error {
|
|
 |
1adcb1 |
+func cpusetCopyFromParent(path string, cgroupv2 bool) error {
|
|
 |
1adcb1 |
for _, file := range []string{"cpuset.cpus", "cpuset.mems"} {
|
|
 |
1adcb1 |
- if _, err := cpusetCopyFileFromParent(path, file); err != nil {
|
|
 |
1adcb1 |
+ if _, err := cpusetCopyFileFromParent(path, file, cgroupv2); err != nil {
|
|
 |
1adcb1 |
return err
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
@@ -60,14 +64,15 @@ func (c *cpusetHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) erro
|
|
 |
1adcb1 |
// Create the cgroup
|
|
 |
1adcb1 |
func (c *cpusetHandler) Create(ctr *CgroupControl) (bool, error) {
|
|
 |
1adcb1 |
if ctr.cgroup2 {
|
|
 |
1adcb1 |
- return false, fmt.Errorf("cpuset create not implemented for cgroup v2")
|
|
 |
1adcb1 |
+ path := filepath.Join(cgroupRoot, ctr.path)
|
|
 |
1adcb1 |
+ return true, cpusetCopyFromParent(path, true)
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
|
|
 |
1adcb1 |
created, err := ctr.createCgroupDirectory(CPUset)
|
|
 |
1adcb1 |
if !created || err != nil {
|
|
 |
1adcb1 |
return created, err
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
- return true, cpusetCopyFromParent(ctr.getCgroupv1Path(CPUset))
|
|
 |
1adcb1 |
+ return true, cpusetCopyFromParent(ctr.getCgroupv1Path(CPUset), false)
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
|
|
 |
1adcb1 |
// Destroy the cgroup
|
|
 |
1adcb1 |
diff --git a/pkg/cgroups/memory.go b/pkg/cgroups/memory.go
|
|
 |
1adcb1 |
index 0505eac409..80e88d17c4 100644
|
|
 |
1adcb1 |
--- a/pkg/cgroups/memory.go
|
|
 |
1adcb1 |
+++ b/pkg/cgroups/memory.go
|
|
 |
1adcb1 |
@@ -26,7 +26,7 @@ func (c *memHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) error {
|
|
 |
1adcb1 |
// Create the cgroup
|
|
 |
1adcb1 |
func (c *memHandler) Create(ctr *CgroupControl) (bool, error) {
|
|
 |
1adcb1 |
if ctr.cgroup2 {
|
|
 |
1adcb1 |
- return false, fmt.Errorf("memory create not implemented for cgroup v2")
|
|
 |
1adcb1 |
+ return false, nil
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
return ctr.createCgroupDirectory(Memory)
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
diff --git a/pkg/cgroups/pids.go b/pkg/cgroups/pids.go
|
|
 |
1adcb1 |
index c90dc1c020..ffbde100dd 100644
|
|
 |
1adcb1 |
--- a/pkg/cgroups/pids.go
|
|
 |
1adcb1 |
+++ b/pkg/cgroups/pids.go
|
|
 |
1adcb1 |
@@ -35,9 +35,6 @@ func (c *pidHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) error {
|
|
 |
1adcb1 |
|
|
 |
1adcb1 |
// Create the cgroup
|
|
 |
1adcb1 |
func (c *pidHandler) Create(ctr *CgroupControl) (bool, error) {
|
|
 |
1adcb1 |
- if ctr.cgroup2 {
|
|
 |
1adcb1 |
- return false, fmt.Errorf("pid create not implemented for cgroup v2")
|
|
 |
1adcb1 |
- }
|
|
 |
1adcb1 |
return ctr.createCgroupDirectory(Pids)
|
|
 |
1adcb1 |
}
|
|
 |
1adcb1 |
|