Skip to content

Commit

Permalink
Revert "CreateCgroupPath: only enable needed controllers"
Browse files Browse the repository at this point in the history
1. Partially revert "CreateCgroupPath: only enable needed controllers"
If we update a resource which did not limited in the beginning,
it will have no effective.
2. Returns err if we use an non enabled controller,
or else the user may feel success, but actually there are no effective.

Signed-off-by: lifubang <[email protected]>
  • Loading branch information
lifubang committed May 19, 2020
1 parent b207d57 commit ba8cd5d
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 66 deletions.
72 changes: 38 additions & 34 deletions libcontainer/cgroups/fs2/create.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fs2

import (
"bytes"
"fmt"
"io/ioutil"
"os"
Expand All @@ -10,57 +11,58 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)

// neededControllers returns the string to write to cgroup.subtree_control,
// containing the list of controllers to enable (for example, "+cpu +pids"),
func supportedControllers(cgroup *configs.Cgroup) ([]byte, error) {
const file = UnifiedMountpoint + "/cgroup.controllers"
return ioutil.ReadFile(file)
}

// needAnyControllers returns whether we enable some supported controllers or not,
// based on (1) controllers available and (2) resources that are being set.
//
// The resulting string does not include "pseudo" controllers such as
// We don't check "pseudo" controllers such as
// "freezer" and "devices".
func neededControllers(cgroup *configs.Cgroup) ([]string, error) {
var list []string

func needAnyControllers(cgroup *configs.Cgroup) (bool, error) {
if cgroup == nil {
return list, nil
return false, nil
}

// list of all available controllers
const file = UnifiedMountpoint + "/cgroup.controllers"
content, err := ioutil.ReadFile(file)
content, err := supportedControllers(cgroup)
if err != nil {
return list, err
return false, err
}
avail := make(map[string]struct{})
for _, ctr := range strings.Fields(string(content)) {
avail[ctr] = struct{}{}
}

// add the controller if available
add := func(controller string) {
// check whether the controller if available or not
have := func(controller string) bool {
if _, ok := avail[controller]; ok {
list = append(list, "+"+controller)
return true
}
return false
}

if isPidsSet(cgroup) {
add("pids")
if isPidsSet(cgroup) && have("pids") {
return true, nil
}
if isMemorySet(cgroup) {
add("memory")
if isMemorySet(cgroup) && have("memory") {
return true, nil
}
if isIoSet(cgroup) {
add("io")
if isIoSet(cgroup) && have("io") {
return true, nil
}
if isCpuSet(cgroup) {
add("cpu")
if isCpuSet(cgroup) && have("cpu") {
return true, nil
}
if isCpusetSet(cgroup) {
add("cpuset")
if isCpusetSet(cgroup) && have("cpuset") {
return true, nil
}
if isHugeTlbSet(cgroup) {
add("hugetlb")
if isHugeTlbSet(cgroup) && have("hugetlb") {
return true, nil
}

return list, nil
return false, nil
}

// containsDomainController returns whether the current config contains domain controller or not.
Expand All @@ -70,18 +72,19 @@ func containsDomainController(cg *configs.Cgroup) bool {
return isMemorySet(cg) || isIoSet(cg) || isCpuSet(cg) || isHugeTlbSet(cg)
}

// CreateCgroupPath creates cgroupv2 path, enabling all the
// needed controllers in the process.
// CreateCgroupPath creates cgroupv2 path, enabling all the supported controllers.
func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
if !strings.HasPrefix(path, UnifiedMountpoint) {
return fmt.Errorf("invalid cgroup path %s", path)
}

ctrs, err := neededControllers(c)
content, err := supportedControllers(c)
if err != nil {
return err
}
allCtrs := strings.Join(ctrs, " ")

ctrs := bytes.Fields(content)
res := append([]byte("+"), bytes.Join(ctrs, []byte(" +"))...)

elements := strings.Split(path, "/")
elements = elements[3:]
Expand Down Expand Up @@ -134,10 +137,11 @@ func CreateCgroupPath(path string, c *configs.Cgroup) (Err error) {
// enable needed controllers
if i < len(elements)-1 {
file := filepath.Join(current, "cgroup.subtree_control")
if err := ioutil.WriteFile(file, []byte(allCtrs), 0644); err != nil {
if err := ioutil.WriteFile(file, res, 0644); err != nil {
// try write one by one
for _, ctr := range ctrs {
_ = ioutil.WriteFile(file, []byte(ctr), 0644)
allCtrs := bytes.Split(res, []byte(" "))
for _, ctr := range allCtrs {
_ = ioutil.WriteFile(file, ctr, 0644)
}
}
// Some controllers might not be enabled when rootless or containerized,
Expand Down
48 changes: 16 additions & 32 deletions libcontainer/cgroups/fs2/fs2.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ func (m *manager) Apply(pid int) error {
// - "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error"
if m.rootless {
if m.config.Path == "" {
cl, clErr := neededControllers(m.config)
if clErr == nil && len(cl) == 0 {
cl, clErr := needAnyControllers(m.config)
if clErr == nil && !cl {
return nil
}
return errors.Wrap(err, "rootless needs no limits + no cgrouppath when no permission is granted for cgroups")
Expand Down Expand Up @@ -175,57 +175,41 @@ func (m *manager) Set(container *configs.Config) error {
if err := m.getControllers(); err != nil {
return err
}
var errs []error
// pids (since kernel 4.5)
if _, ok := m.controllers["pids"]; ok {
if err := setPids(m.dirPath, container.Cgroups); err != nil {
errs = append(errs, err)
}
if err := setPids(m.dirPath, container.Cgroups); err != nil {
return err
}
// memory (since kernel 4.5)
if _, ok := m.controllers["memory"]; ok {
if err := setMemory(m.dirPath, container.Cgroups); err != nil {
errs = append(errs, err)
}
if err := setMemory(m.dirPath, container.Cgroups); err != nil {
return err
}
// io (since kernel 4.5)
if _, ok := m.controllers["io"]; ok {
if err := setIo(m.dirPath, container.Cgroups); err != nil {
errs = append(errs, err)
}
if err := setIo(m.dirPath, container.Cgroups); err != nil {
return err
}
// cpu (since kernel 4.15)
if _, ok := m.controllers["cpu"]; ok {
if err := setCpu(m.dirPath, container.Cgroups); err != nil {
errs = append(errs, err)
}
if err := setCpu(m.dirPath, container.Cgroups); err != nil {
return err
}
// devices (since kernel 4.15, pseudo-controller)
//
// When m.Rootless is true, errors from the device subsystem are ignored because it is really not expected to work.
// However, errors from other subsystems are not ignored.
// see @test "runc create (rootless + limits + no cgrouppath + no permission) fails with informative error"
if err := setDevices(m.dirPath, container.Cgroups); err != nil && !m.rootless {
errs = append(errs, err)
return err
}
// cpuset (since kernel 5.0)
if _, ok := m.controllers["cpuset"]; ok {
if err := setCpuset(m.dirPath, container.Cgroups); err != nil {
errs = append(errs, err)
}
if err := setCpuset(m.dirPath, container.Cgroups); err != nil {
return err
}
// hugetlb (since kernel 5.6)
if _, ok := m.controllers["hugetlb"]; ok {
if err := setHugeTlb(m.dirPath, container.Cgroups); err != nil {
errs = append(errs, err)
}
if err := setHugeTlb(m.dirPath, container.Cgroups); err != nil {
return err
}
// freezer (since kernel 5.2, pseudo-controller)
if err := setFreezer(m.dirPath, container.Cgroups.Freezer); err != nil {
errs = append(errs, err)
}
if len(errs) > 0 {
return errors.Errorf("error while setting cgroup v2: %+v", errs)
return err
}
m.config = container.Cgroups
return nil
Expand Down

0 comments on commit ba8cd5d

Please sign in to comment.