cgroupv2: rm legacy Paths from systemd driver

Having map of per-subsystem paths in systemd unified cgroups
driver does not make sense and makes the code less readable.

To get rid of it, move the systemd v1-or-v2 init code to
libcontainer/factory_linux.go which already has a function
to deduce unified path out of paths map.

End result is much cleaner code. Besides, we no longer write pid
to the same cgroup file 7 times in Apply() like we did before.

While at it
 - add `rootless` flag which is passed on to fs2 manager
 - merge getv2Path() into GetUnifiedPath(), don't overwrite
   path if it is set during initialization (on Load).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin 2020-04-04 11:19:05 -07:00
parent 480bca91be
commit 9c80cd672d
3 changed files with 65 additions and 72 deletions

View File

@ -102,26 +102,6 @@ func getDbusConnection() (*systemdDbus.Conn, error) {
return connDbus, connErr return connDbus, connErr
} }
func NewSystemdCgroupsManager() (func(config *configs.Cgroup, paths map[string]string) cgroups.Manager, error) {
if !IsRunningSystemd() {
return nil, fmt.Errorf("systemd not running on this host, can't use systemd as a cgroups.Manager")
}
if cgroups.IsCgroup2UnifiedMode() {
return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
return &UnifiedManager{
Cgroups: config,
Paths: paths,
}
}, nil
}
return func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
return &LegacyManager{
Cgroups: config,
Paths: paths,
}
}, nil
}
func (m *LegacyManager) Apply(pid int) error { func (m *LegacyManager) Apply(pid int) error {
var ( var (
c = m.Cgroups c = m.Cgroups

View File

@ -16,14 +16,23 @@ import (
"github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/cgroups/fs2" "github.com/opencontainers/runc/libcontainer/cgroups/fs2"
"github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs"
"github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
type UnifiedManager struct { type UnifiedManager struct {
mu sync.Mutex mu sync.Mutex
Cgroups *configs.Cgroup Cgroups *configs.Cgroup
Paths map[string]string // path is like "/sys/fs/cgroup/user.slice/user-1001.slice/session-1.scope"
path string
rootless bool
}
func NewUnifiedManager(config *configs.Cgroup, path string, rootless bool) *UnifiedManager {
return &UnifiedManager{
Cgroups: config,
path: path,
rootless: rootless,
}
} }
func (m *UnifiedManager) Apply(pid int) error { func (m *UnifiedManager) Apply(pid int) error {
@ -35,12 +44,7 @@ func (m *UnifiedManager) Apply(pid int) error {
) )
if c.Paths != nil { if c.Paths != nil {
paths := make(map[string]string) return cgroups.WriteCgroupProc(m.path, pid)
for name, path := range c.Paths {
paths[name] = path
}
m.Paths = paths
return cgroups.EnterPid(m.Paths, pid)
} }
if c.Parent != "" { if c.Parent != "" {
@ -144,22 +148,13 @@ func (m *UnifiedManager) Apply(pid int) error {
return err return err
} }
path, err := getv2Path(m.Cgroups) _, err = m.GetUnifiedPath()
if err != nil { if err != nil {
return err return err
} }
if err := createCgroupsv2Path(path); err != nil { if err := createCgroupsv2Path(m.path); err != nil {
return err return err
} }
m.Paths = map[string]string{
"pids": path,
"memory": path,
"io": path,
"cpu": path,
"devices": path,
"cpuset": path,
"freezer": path,
}
return nil return nil
} }
@ -175,39 +170,39 @@ func (m *UnifiedManager) Destroy() error {
return err return err
} }
dbusConnection.StopUnit(getUnitName(m.Cgroups), "replace", nil) dbusConnection.StopUnit(getUnitName(m.Cgroups), "replace", nil)
if err := cgroups.RemovePaths(m.Paths); err != nil {
// XXX this is probably not needed, systemd should handle it
err = os.Remove(m.path)
if err != nil && !os.IsNotExist(err) {
return err return err
} }
m.Paths = make(map[string]string)
return nil return nil
} }
// this method is for v1 backward compatibility and will be removed
func (m *UnifiedManager) GetPaths() map[string]string { func (m *UnifiedManager) GetPaths() map[string]string {
m.mu.Lock() _, _ = m.GetUnifiedPath()
paths := m.Paths paths := map[string]string{
m.mu.Unlock() "pids": m.path,
"memory": m.path,
"io": m.path,
"cpu": m.path,
"devices": m.path,
"cpuset": m.path,
"freezer": m.path,
}
return paths return paths
} }
func (m *UnifiedManager) GetUnifiedPath() (string, error) { func (m *UnifiedManager) GetUnifiedPath() (string, error) {
unifiedPath := ""
m.mu.Lock() m.mu.Lock()
defer m.mu.Unlock() defer m.mu.Unlock()
for k, v := range m.Paths { if m.path != "" {
if unifiedPath == "" { return m.path, nil
unifiedPath = v
} else if v != unifiedPath {
return unifiedPath,
errors.Errorf("expected %q path to be unified path %q, got %q", k, unifiedPath, v)
}
} }
if unifiedPath == "" {
// FIXME: unified path could be detected even when no controller is available
return unifiedPath, errors.New("cannot detect unified path")
}
return unifiedPath, nil
}
func getv2Path(c *configs.Cgroup) (string, error) { c := m.Cgroups
slice := "system.slice" slice := "system.slice"
if c.Parent != "" { if c.Parent != "" {
slice = c.Parent slice = c.Parent
@ -218,7 +213,8 @@ func getv2Path(c *configs.Cgroup) (string, error) {
return "", err return "", err
} }
return filepath.Join(fs2.UnifiedMountpoint, slice, getUnitName(c)), nil m.path = filepath.Join(fs2.UnifiedMountpoint, slice, getUnitName(c))
return m.path, nil
} }
func createCgroupsv2Path(path string) (Err error) { func createCgroupsv2Path(path string) (Err error) {
@ -263,7 +259,7 @@ func (m *UnifiedManager) fsManager() (cgroups.Manager, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
return fs2.NewManager(m.Cgroups, path, false) return fs2.NewManager(m.Cgroups, path, m.rootless)
} }
func (m *UnifiedManager) Freeze(state configs.FreezerState) error { func (m *UnifiedManager) Freeze(state configs.FreezerState) error {

View File

@ -50,17 +50,6 @@ func InitArgs(args ...string) func(*LinuxFactory) error {
} }
} }
// SystemdCgroups is an options func to configure a LinuxFactory to return
// containers that use systemd to create and manage cgroups.
func SystemdCgroups(l *LinuxFactory) error {
systemdCgroupsManager, err := systemd.NewSystemdCgroupsManager()
if err != nil {
return err
}
l.NewCgroupsManager = systemdCgroupsManager
return nil
}
func getUnifiedPath(paths map[string]string) string { func getUnifiedPath(paths map[string]string) string {
unifiedPath := "" unifiedPath := ""
for k, v := range paths { for k, v := range paths {
@ -74,6 +63,34 @@ func getUnifiedPath(paths map[string]string) string {
return unifiedPath return unifiedPath
} }
func systemdCgroupV2(l *LinuxFactory, rootless bool) error {
l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
return systemd.NewUnifiedManager(config, getUnifiedPath(paths), rootless)
}
return nil
}
// SystemdCgroups is an options func to configure a LinuxFactory to return
// containers that use systemd to create and manage cgroups.
func SystemdCgroups(l *LinuxFactory) error {
if !systemd.IsRunningSystemd() {
return fmt.Errorf("systemd not running on this host, can't use systemd as cgroups manager")
}
if cgroups.IsCgroup2UnifiedMode() {
return systemdCgroupV2(l, false)
}
l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
return &systemd.LegacyManager{
Cgroups: config,
Paths: paths,
}
}
return nil
}
func cgroupfs2(l *LinuxFactory, rootless bool) error { func cgroupfs2(l *LinuxFactory, rootless bool) error {
l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager { l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
m, err := fs2.NewManager(config, getUnifiedPath(paths), rootless) m, err := fs2.NewManager(config, getUnifiedPath(paths), rootless)