diff --git a/fs/fs.go b/fs/fs.go index 98e1e342..29690dd6 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -218,7 +218,10 @@ func (m *manager) Apply(pid int) (err error) { m.mu.Lock() defer m.mu.Unlock() - var c = m.cgroups + c := m.cgroups + if c.Resources.Unified != nil { + return cgroups.ErrV1NoUnified + } m.paths = make(map[string]string) if c.Paths != nil { @@ -309,6 +312,9 @@ func (m *manager) Set(container *configs.Config) error { if m.cgroups != nil && m.cgroups.Paths != nil { return nil } + if container.Cgroups.Resources.Unified != nil { + return cgroups.ErrV1NoUnified + } m.mu.Lock() defer m.mu.Unlock() diff --git a/fs2/fs2.go b/fs2/fs2.go index 0975064f..268a630e 100644 --- a/fs2/fs2.go +++ b/fs2/fs2.go @@ -3,11 +3,14 @@ package fs2 import ( + "fmt" "io/ioutil" + "os" "path/filepath" "strings" "github.com/opencontainers/runc/libcontainer/cgroups" + "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" "github.com/pkg/errors" ) @@ -206,10 +209,40 @@ func (m *manager) Set(container *configs.Config) error { if err := setFreezer(m.dirPath, container.Cgroups.Freezer); err != nil { return err } + if err := m.setUnified(container.Cgroups.Unified); err != nil { + return err + } m.config = container.Cgroups return nil } +func (m *manager) setUnified(res map[string]string) error { + for k, v := range res { + if strings.Contains(k, "/") { + return fmt.Errorf("unified resource %q must be a file name (no slashes)", k) + } + if err := fscommon.WriteFile(m.dirPath, k, v); err != nil { + errC := errors.Cause(err) + // Check for both EPERM and ENOENT since O_CREAT is used by WriteFile. + if errors.Is(errC, os.ErrPermission) || errors.Is(errC, os.ErrNotExist) { + // Check if a controller is available, + // to give more specific error if not. + sk := strings.SplitN(k, ".", 2) + if len(sk) != 2 { + return fmt.Errorf("unified resource %q must be in the form CONTROLLER.PARAMETER", k) + } + c := sk[0] + if _, ok := m.controllers[c]; !ok && c != "cgroup" { + return fmt.Errorf("unified resource %q can't be set: controller %q not available", k, c) + } + } + return errors.Wrapf(err, "can't set unified resource %q", k) + } + } + + return nil +} + func (m *manager) GetPaths() map[string]string { paths := make(map[string]string, 1) paths[""] = m.dirPath diff --git a/systemd/v1.go b/systemd/v1.go index cc2d19cd..eeda18a9 100644 --- a/systemd/v1.go +++ b/systemd/v1.go @@ -101,6 +101,10 @@ func (m *legacyManager) Apply(pid int) error { properties []systemdDbus.Property ) + if c.Resources.Unified != nil { + return cgroups.ErrV1NoUnified + } + m.mu.Lock() defer m.mu.Unlock() if c.Paths != nil { @@ -342,6 +346,9 @@ func (m *legacyManager) Set(container *configs.Config) error { if m.cgroups.Paths != nil { return nil } + if container.Cgroups.Resources.Unified != nil { + return cgroups.ErrV1NoUnified + } dbusConnection, err := getDbusConnection(false) if err != nil { return err diff --git a/v1_utils.go b/v1_utils.go index a94f2086..8b9275fb 100644 --- a/v1_utils.go +++ b/v1_utils.go @@ -23,7 +23,8 @@ const ( ) var ( - errUnified = errors.New("not implemented for cgroup v2 unified hierarchy") + errUnified = errors.New("not implemented for cgroup v2 unified hierarchy") + ErrV1NoUnified = errors.New("invalid configuration: cannot use unified on cgroup v1") ) type NotFoundError struct {