Repository: opencontainers/runc
Pull request #2387 (2020-05-08 02:44:39)

cgroup refactoring
This is a set of patches aiming to prepare the codebase for #2386 

Please review commits one by one.

mrunalp: Looks fine but needs rebase.
kolyshkin: Rebased
mrunalp: LGTM
kolyshkin: rebased again :)
AkihiroSuda: Looks good but a couple of nits

Patch:
diff --git a/go.mod b/go.mod
index 56beebfc..a7472228 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.14
 
 require (
 	github.com/checkpoint-restore/go-criu v0.0.0-20191125063657-fcdcd07065c5
-	github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3
+	github.com/cilium/ebpf v0.0.0-20200319110858-a7172c01168f
 	github.com/containerd/console v1.0.0
 	github.com/coreos/go-systemd/v22 v22.0.0
 	github.com/cyphar/filepath-securejoin v0.2.2
diff --git a/go.sum b/go.sum
index 3e71b19d..55f649cf 100644
--- a/go.sum
+++ b/go.sum
@@ -3,8 +3,6 @@ github.com/checkpoint-restore/go-criu v0.0.0-20191125063657-fcdcd07065c5 h1:950d
 github.com/checkpoint-restore/go-criu v0.0.0-20191125063657-fcdcd07065c5/go.mod h1:TrMrLQfeENAPYPRsJuq3jsqdlRh3lvi6trTZJG8+tho=
 github.com/cilium/ebpf v0.0.0-20200319110858-a7172c01168f h1:W1RQPz3nR8RxUw/Uqk71GU3JlZ7pNa1pXrHs98h0o9U=
 github.com/cilium/ebpf v0.0.0-20200319110858-a7172c01168f/go.mod h1:XT+cAw5wfvsodedcijoh1l9cf7v1x9FlFB/3VmF/O8s=
-github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3 h1:qcqzLJa2xCo9sgdCzpT/SJSYxROTEstuhf7ZBHMirms=
-github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3/go.mod h1:XT+cAw5wfvsodedcijoh1l9cf7v1x9FlFB/3VmF/O8s=
 github.com/containerd/console v1.0.0 h1:fU3UuQapBs+zLJu82NhR11Rif1ny2zfMMAyPJzSN5tQ=
 github.com/containerd/console v1.0.0/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
 github.com/coreos/go-systemd/v22 v22.0.0 h1:XJIw/+VlJ+87J+doOxznsAWIdmWuViOVhkQamW5YV28=
diff --git a/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go b/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go
index 5a1cdd91..847ce8ef 100644
--- a/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go
+++ b/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go
@@ -49,8 +49,7 @@ func (p *program) init() {
 	*/
 	// R2 <- type (lower 16 bit of u32 access_type at R1[0])
 	p.insts = append(p.insts,
-		asm.LoadMem(asm.R2, asm.R1, 0, asm.Word),
-		asm.And.Imm32(asm.R2, 0xFFFF))
+		asm.LoadMem(asm.R2, asm.R1, 0, asm.Half))
 
 	// R3 <- access (upper 16 bit of u32 access_type at R1[0])
 	p.insts = append(p.insts,
diff --git a/libcontainer/cgroups/fs/apply_raw.go b/libcontainer/cgroups/fs/apply_raw.go
index 59ce5ea6..760d4e6e 100644
--- a/libcontainer/cgroups/fs/apply_raw.go
+++ b/libcontainer/cgroups/fs/apply_raw.go
@@ -61,11 +61,19 @@ type subsystem interface {
 	Set(path string, cgroup *configs.Cgroup) error
 }
 
-type Manager struct {
+type manager struct {
 	mu       sync.Mutex
-	Cgroups  *configs.Cgroup
-	Rootless bool // ignore permission-related errors
-	Paths    map[string]string
+	cgroups  *configs.Cgroup
+	rootless bool // ignore permission-related errors
+	paths    map[string]string
+}
+
+func NewManager(cg *configs.Cgroup, paths map[string]string, rootless bool) cgroups.Manager {
+	return &manager{
+		cgroups:  cg,
+		paths:    paths,
+		rootless: rootless,
+	}
 }
 
 // The absolute path to the root of the cgroup hierarchies.
@@ -124,25 +132,25 @@ func isIgnorableError(rootless bool, err error) bool {
 	return false
 }
 
-func (m *Manager) getSubsystems() subsystemSet {
+func (m *manager) getSubsystems() subsystemSet {
 	return subsystemsLegacy
 }
 
-func (m *Manager) Apply(pid int) (err error) {
-	if m.Cgroups == nil {
+func (m *manager) Apply(pid int) (err error) {
+	if m.cgroups == nil {
 		return nil
 	}
 	m.mu.Lock()
 	defer m.mu.Unlock()
 
-	var c = m.Cgroups
+	var c = m.cgroups
 
-	d, err := getCgroupData(m.Cgroups, pid)
+	d, err := getCgroupData(m.cgroups, pid)
 	if err != nil {
 		return err
 	}
 
-	m.Paths = make(map[string]string)
+	m.paths = make(map[string]string)
 	if c.Paths != nil {
 		for name, path := range c.Paths {
 			_, err := d.path(name)
@@ -152,9 +160,9 @@ func (m *Manager) Apply(pid int) (err error) {
 				}
 				return err
 			}
-			m.Paths[name] = path
+			m.paths[name] = path
 		}
-		return cgroups.EnterPid(m.Paths, pid)
+		return cgroups.EnterPid(m.paths, pid)
 	}
 
 	for _, sys := range m.getSubsystems() {
@@ -170,15 +178,15 @@ func (m *Manager) Apply(pid int) (err error) {
 			}
 			return err
 		}
-		m.Paths[sys.Name()] = p
+		m.paths[sys.Name()] = p
 
 		if err := sys.Apply(d); err != nil {
 			// In the case of rootless (including euid=0 in userns), where an explicit cgroup path hasn't
 			// been set, we don't bail on error in case of permission problems.
 			// Cases where limits have been set (and we couldn't create our own
 			// cgroup) are handled by Set.
-			if isIgnorableError(m.Rootless, err) && m.Cgroups.Path == "" {
-				delete(m.Paths, sys.Name())
+			if isIgnorableError(m.rootless, err) && m.cgroups.Path == "" {
+				delete(m.paths, sys.Name())
 				continue
 			}
 			return err
@@ -188,35 +196,35 @@ func (m *Manager) Apply(pid int) (err error) {
 	return nil
 }
 
-func (m *Manager) Destroy() error {
-	if m.Cgroups == nil || m.Cgroups.Paths != nil {
+func (m *manager) Destroy() error {
+	if m.cgroups == nil || m.cgroups.Paths != nil {
 		return nil
 	}
 	m.mu.Lock()
 	defer m.mu.Unlock()
-	if err := cgroups.RemovePaths(m.Paths); err != nil {
+	if err := cgroups.RemovePaths(m.paths); err != nil {
 		return err
 	}
-	m.Paths = make(map[string]string)
+	m.paths = make(map[string]string)
 	return nil
 }
 
-func (m *Manager) GetPaths() map[string]string {
+func (m *manager) GetPaths() map[string]string {
 	m.mu.Lock()
-	paths := m.Paths
+	paths := m.paths
 	m.mu.Unlock()
 	return paths
 }
 
-func (m *Manager) GetUnifiedPath() (string, error) {
+func (m *manager) GetUnifiedPath() (string, error) {
 	return "", errors.New("unified path is only supported when running in unified mode")
 }
 
-func (m *Manager) GetStats() (*cgroups.Stats, error) {
+func (m *manager) GetStats() (*cgroups.Stats, error) {
 	m.mu.Lock()
 	defer m.mu.Unlock()
 	stats := cgroups.NewStats()
-	for name, path := range m.Paths {
+	for name, path := range m.paths {
 		sys, err := m.getSubsystems().Get(name)
 		if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
 			continue
@@ -228,22 +236,23 @@ func (m *Manager) GetStats() (*cgroups.Stats, error) {
 	return stats, nil
 }
 
-func (m *Manager) Set(container *configs.Config) error {
+func (m *manager) Set(container *configs.Config) error {
 	if container.Cgroups == nil {
 		return nil
 	}
 
 	// If Paths are set, then we are just joining cgroups paths
 	// and there is no need to set any values.
-	if m.Cgroups != nil && m.Cgroups.Paths != nil {
+	if m.cgroups != nil && m.cgroups.Paths != nil {
 		return nil
 	}
 
-	paths := m.GetPaths()
+	m.mu.Lock()
+	defer m.mu.Unlock()
 	for _, sys := range m.getSubsystems() {
-		path := paths[sys.Name()]
+		path := m.paths[sys.Name()]
 		if err := sys.Set(path, container.Cgroups); err != nil {
-			if m.Rootless && sys.Name() == "devices" {
+			if m.rootless && sys.Name() == "devices" {
 				continue
 			}
 			// When m.Rootless is true, errors from the device subsystem are ignored because it is really not expected to work.
@@ -258,8 +267,8 @@ func (m *Manager) Set(container *configs.Config) error {
 		}
 	}
 
-	if m.Paths["cpu"] != "" {
-		if err := CheckCpushares(m.Paths["cpu"], container.Cgroups.Resources.CpuShares); err != nil {
+	if m.paths["cpu"] != "" {
+		if err := CheckCpushares(m.paths["cpu"], container.Cgroups.Resources.CpuShares); err != nil {
 			return err
 		}
 	}
@@ -268,33 +277,33 @@ func (m *Manager) Set(container *configs.Config) error {
 
 // Freeze toggles the container's freezer cgroup depending on the state
 // provided
-func (m *Manager) Freeze(state configs.FreezerState) error {
-	if m.Cgroups == nil {
+func (m *manager) Freeze(state configs.FreezerState) error {
+	if m.cgroups == nil {
 		return errors.New("cannot toggle freezer: cgroups not configured for container")
 	}
 
 	paths := m.GetPaths()
 	dir := paths["freezer"]
-	prevState := m.Cgroups.Resources.Freezer
-	m.Cgroups.Resources.Freezer = state
+	prevState := m.cgroups.Resources.Freezer
+	m.cgroups.Resources.Freezer = state
 	freezer, err := m.getSubsystems().Get("freezer")
 	if err != nil {
 		return err
 	}
-	err = freezer.Set(dir, m.Cgroups)
+	err = freezer.Set(dir, m.cgroups)
 	if err != nil {
-		m.Cgroups.Resources.Freezer = prevState
+		m.cgroups.Resources.Freezer = prevState
 		return err
 	}
 	return nil
 }
 
-func (m *Manager) GetPids() ([]int, error) {
+func (m *manager) GetPids() ([]int, error) {
 	paths := m.GetPaths()
 	return cgroups.GetPids(paths["devices"])
 }
 
-func (m *Manager) GetAllPids() ([]int, error) {
+func (m *manager) GetAllPids() ([]int, error) {
 	paths := m.GetPaths()
 	return cgroups.GetAllPids(paths["devices"])
 }
@@ -402,6 +411,6 @@ func CheckCpushares(path string, c uint64) error {
 	return nil
 }
 
-func (m *Manager) GetCgroups() (*configs.Cgroup, error) {
-	return m.Cgroups, nil
+func (m *manager) GetCgroups() (*configs.Cgroup, error) {
+	return m.cgroups, nil
 }
diff --git a/libcontainer/cgroups/systemd/v1.go b/libcontainer/cgroups/systemd/v1.go
index e66db22a..26858517 100644
--- a/libcontainer/cgroups/systemd/v1.go
+++ b/libcontainer/cgroups/systemd/v1.go
@@ -17,10 +17,17 @@ import (
 	"github.com/opencontainers/runc/libcontainer/configs"
 )
 
-type LegacyManager struct {
+type legacyManager struct {
 	mu      sync.Mutex
-	Cgroups *configs.Cgroup
-	Paths   map[string]string
+	cgroups *configs.Cgroup
+	paths   map[string]string
+}
+
+func NewLegacyManager(cg *configs.Cgroup, paths map[string]string) cgroups.Manager {
+	return &legacyManager{
+		cgroups: cg,
+		paths:   paths,
+	}
 }
 
 type subsystem interface {
@@ -114,9 +121,9 @@ func genV1ResourcesProperties(c *configs.Cgroup) ([]systemdDbus.Property, error)
 	return properties, nil
 }
 
-func (m *LegacyManager) Apply(pid int) error {
+func (m *legacyManager) Apply(pid int) error {
 	var (
-		c          = m.Cgroups
+		c          = m.cgroups
 		unitName   = getUnitName(c)
 		slice      = "system.slice"
 		properties []systemdDbus.Property
@@ -125,7 +132,7 @@ func (m *LegacyManager) Apply(pid int) error {
 	if c.Paths != nil {
 		paths := make(map[string]string)
 		for name, path := range c.Paths {
-			_, err := getSubsystemPath(m.Cgroups, name)
+			_, err := getSubsystemPath(m.cgroups, name)
 			if err != nil {
 				// Don't fail if a cgroup hierarchy was not found, just skip this subsystem
 				if cgroups.IsNotFound(err) {
@@ -135,8 +142,8 @@ func (m *LegacyManager) Apply(pid int) error {
 			}
 			paths[name] = path
 		}
-		m.Paths = paths
-		return cgroups.EnterPid(m.Paths, pid)
+		m.paths = paths
+		return cgroups.EnterPid(m.paths, pid)
 	}
 
 	if c.Parent != "" {
@@ -196,7 +203,7 @@ func (m *LegacyManager) Apply(pid int) error {
 
 	paths := make(map[string]string)
 	for _, s := range legacySubsystems {
-		subsystemPath, err := getSubsystemPath(m.Cgroups, s.Name())
+		subsystemPath, err := getSubsystemPath(m.cgroups, s.Name())
 		if err != nil {
 			// Don't fail if a cgroup hierarchy was not found, just skip this subsystem
 			if cgroups.IsNotFound(err) {
@@ -206,12 +213,12 @@ func (m *LegacyManager) Apply(pid int) error {
 		}
 		paths[s.Name()] = subsystemPath
 	}
-	m.Paths = paths
+	m.paths = paths
 	return nil
 }
 
-func (m *LegacyManager) Destroy() error {
-	if m.Cgroups.Paths != nil {
+func (m *legacyManager) Destroy() error {
+	if m.cgroups.Paths != nil {
 		return nil
 	}
 	m.mu.Lock()
@@ -221,22 +228,22 @@ func (m *LegacyManager) Destroy() error {
 	if err != nil {
 		return err
 	}
-	unitName := getUnitName(m.Cgroups)
+	unitName := getUnitName(m.cgroups)
 	if err := stopUnit(dbusConnection, unitName); err != nil {
 		return err
 	}
-	m.Paths = make(map[string]string)
+	m.paths = make(map[string]string)
 	return nil
 }
 
-func (m *LegacyManager) GetPaths() map[string]string {
+func (m *legacyManager) GetPaths() map[string]string {
 	m.mu.Lock()
-	paths := m.Paths
+	paths := m.paths
 	m.mu.Unlock()
 	return paths
 }
 
-func (m *LegacyManager) GetUnifiedPath() (string, error) {
+func (m *legacyManager) GetUnifiedPath() (string, error) {
 	return "", errors.New("unified path is only supported when running in unified mode")
 }
 
@@ -317,46 +324,46 @@ func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
 	return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil
 }
 
-func (m *LegacyManager) Freeze(state configs.FreezerState) error {
-	path, err := getSubsystemPath(m.Cgroups, "freezer")
+func (m *legacyManager) Freeze(state configs.FreezerState) error {
+	path, err := getSubsystemPath(m.cgroups, "freezer")
 	if err != nil {
 		return err
 	}
-	prevState := m.Cgroups.Resources.Freezer
-	m.Cgroups.Resources.Freezer = state
+	prevState := m.cgroups.Resources.Freezer
+	m.cgroups.Resources.Freezer = state
 	freezer, err := legacySubsystems.Get("freezer")
 	if err != nil {
 		return err
 	}
-	err = freezer.Set(path, m.Cgroups)
+	err = freezer.Set(path, m.cgroups)
 	if err != nil {
-		m.Cgroups.Resources.Freezer = prevState
+		m.cgroups.Resources.Freezer = prevState
 		return err
 	}
 	return nil
 }
 
-func (m *LegacyManager) GetPids() ([]int, error) {
-	path, err := getSubsystemPath(m.Cgroups, "devices")
+func (m *legacyManager) GetPids() ([]int, error) {
+	path, err := getSubsystemPath(m.cgroups, "devices")
 	if err != nil {
 		return nil, err
 	}
 	return cgroups.GetPids(path)
 }
 
-func (m *LegacyManager) GetAllPids() ([]int, error) {
-	path, err := getSubsystemPath(m.Cgroups, "devices")
+func (m *legacyManager) GetAllPids() ([]int, error) {
+	path, err := getSubsystemPath(m.cgroups, "devices")
 	if err != nil {
 		return nil, err
 	}
 	return cgroups.GetAllPids(path)
 }
 
-func (m *LegacyManager) GetStats() (*cgroups.Stats, error) {
+func (m *legacyManager) GetStats() (*cgroups.Stats, error) {
 	m.mu.Lock()
 	defer m.mu.Unlock()
 	stats := cgroups.NewStats()
-	for name, path := range m.Paths {
+	for name, path := range m.paths {
 		sys, err := legacySubsystems.Get(name)
 		if err == errSubsystemDoesNotExist || !cgroups.PathExists(path) {
 			continue
@@ -369,10 +376,10 @@ func (m *LegacyManager) GetStats() (*cgroups.Stats, error) {
 	return stats, nil
 }
 
-func (m *LegacyManager) Set(container *configs.Config) error {
+func (m *legacyManager) Set(container *configs.Config) error {
 	// If Paths are set, then we are just joining cgroups paths
 	// and there is no need to set any values.
-	if m.Cgroups.Paths != nil {
+	if m.cgroups.Paths != nil {
 		return nil
 	}
 	properties, err := genV1ResourcesProperties(container.Cgroups)
@@ -399,8 +406,8 @@ func (m *LegacyManager) Set(container *configs.Config) error {
 		}
 	}
 
-	if m.Paths["cpu"] != "" {
-		if err := fs.CheckCpushares(m.Paths["cpu"], container.Cgroups.Resources.CpuShares); err != nil {
+	if m.paths["cpu"] != "" {
+		if err := fs.CheckCpushares(m.paths["cpu"], container.Cgroups.Resources.CpuShares); err != nil {
 			return err
 		}
 	}
@@ -427,6 +434,6 @@ func setKernelMemory(c *configs.Cgroup) error {
 	}
 	return fs.EnableKernelMemoryAccounting(path)
 }
-func (m *LegacyManager) GetCgroups() (*configs.Cgroup, error) {
-	return m.Cgroups, nil
+func (m *legacyManager) GetCgroups() (*configs.Cgroup, error) {
+	return m.cgroups, nil
 }
diff --git a/libcontainer/cgroups/systemd/v2.go b/libcontainer/cgroups/systemd/v2.go
index 46bbd567..4bce0465 100644
--- a/libcontainer/cgroups/systemd/v2.go
+++ b/libcontainer/cgroups/systemd/v2.go
@@ -26,7 +26,7 @@ type unifiedManager struct {
 	rootless bool
 }
 
-func NewUnifiedManager(config *configs.Cgroup, path string, rootless bool) *unifiedManager {
+func NewUnifiedManager(config *configs.Cgroup, path string, rootless bool) cgroups.Manager {
 	return &unifiedManager{
 		cgroups:  config,
 		path:     path,
diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index ab2fbe14..d4cc35d4 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -553,7 +553,7 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, messageSockP
 	}
 	return &setnsProcess{
 		cmd:             cmd,
-		cgroupPaths:     c.cgroupManager.GetPaths(),
+		cgroupPaths:     state.CgroupPaths,
 		rootlessCgroups: c.config.RootlessCgroups,
 		intelRdtPath:    state.IntelRdtPath,
 		messageSockPair: messageSockPair,
@@ -655,7 +655,7 @@ func (c *linuxContainer) NotifyOOM() (<-chan struct{}, error) {
 		}
 		return notifyOnOOMV2(path)
 	}
-	return notifyOnOOM(c.cgroupManager.GetPaths())
+	return notifyOnOOM(c.cgroupManager.GetPaths()["memory"])
 }
 
 func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struct{}, error) {
@@ -663,7 +663,7 @@ func (c *linuxContainer) NotifyMemoryPressure(level PressureLevel) (<-chan struc
 	if c.config.RootlessCgroups {
 		logrus.Warn("getting memory pressure notifications may fail if you don't have the full access to cgroups")
 	}
-	return notifyMemoryPressure(c.cgroupManager.GetPaths(), level)
+	return notifyMemoryPressure(c.cgroupManager.GetPaths()["memory"], level)
 }
 
 var criuFeatures *criurpc.CriuFeatures
diff --git a/libcontainer/factory_linux.go b/libcontainer/factory_linux.go
index 373d987f..59548ef8 100644
--- a/libcontainer/factory_linux.go
+++ b/libcontainer/factory_linux.go
@@ -88,10 +88,7 @@ func SystemdCgroups(l *LinuxFactory) error {
 	}
 
 	l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
-		return &systemd.LegacyManager{
-			Cgroups: config,
-			Paths:   paths,
-		}
+		return systemd.NewLegacyManager(config, paths)
 	}
 
 	return nil
@@ -120,22 +117,23 @@ func cgroupfs2(l *LinuxFactory, rootless bool) error {
 	return nil
 }
 
-// Cgroupfs is an options func to configure a LinuxFactory to return containers
-// that use the native cgroups filesystem implementation to create and manage
-// cgroups.
-func Cgroupfs(l *LinuxFactory) error {
+func cgroupfs(l *LinuxFactory, rootless bool) error {
 	if cgroups.IsCgroup2UnifiedMode() {
-		return cgroupfs2(l, false)
+		return cgroupfs2(l, rootless)
 	}
 	l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
-		return &fs.Manager{
-			Cgroups: config,
-			Paths:   paths,
-		}
+		return fs.NewManager(config, paths, rootless)
 	}
 	return nil
 }
 
+// Cgroupfs is an options func to configure a LinuxFactory to return containers
+// that use the native cgroups filesystem implementation to create and manage
+// cgroups.
+func Cgroupfs(l *LinuxFactory) error {
+	return cgroupfs(l, false)
+}
+
 // RootlessCgroupfs is an options func to configure a LinuxFactory to return
 // containers that use the native cgroups filesystem implementation to create
 // and manage cgroups. The difference between RootlessCgroupfs and Cgroupfs is
@@ -143,17 +141,7 @@ func Cgroupfs(l *LinuxFactory) error {
 // during rootless container (including euid=0 in userns) setup (while still allowing cgroup usage if
 // they've been set up properly).
 func RootlessCgroupfs(l *LinuxFactory) error {
-	if cgroups.IsCgroup2UnifiedMode() {
-		return cgroupfs2(l, true)
-	}
-	l.NewCgroupsManager = func(config *configs.Cgroup, paths map[string]string) cgroups.Manager {
-		return &fs.Manager{
-			Cgroups:  config,
-			Rootless: true,
-			Paths:    paths,
-		}
-	}
-	return nil
+	return cgroupfs(l, true)
 }
 
 // IntelRdtfs is an options func to configure a LinuxFactory to return
diff --git a/libcontainer/notify_linux.go b/libcontainer/notify_linux.go
index 47a06783..d7d1de1b 100644
--- a/libcontainer/notify_linux.go
+++ b/libcontainer/notify_linux.go
@@ -3,6 +3,7 @@
 package libcontainer
 
 import (
+	"errors"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -11,8 +12,6 @@ import (
 	"golang.org/x/sys/unix"
 )
 
-const oomCgroupName = "memory"
-
 type PressureLevel uint
 
 const (
@@ -66,19 +65,17 @@ func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct
 
 // notifyOnOOM returns channel on which you can expect event about OOM,
 // if process died without OOM this channel will be closed.
-func notifyOnOOM(paths map[string]string) (<-chan struct{}, error) {
-	dir := paths[oomCgroupName]
+func notifyOnOOM(dir string) (<-chan struct{}, error) {
 	if dir == "" {
-		return nil, fmt.Errorf("path %q missing", oomCgroupName)
+		return nil, errors.New("memory controller missing")
 	}
 
 	return registerMemoryEvent(dir, "memory.oom_control", "")
 }
 
-func notifyMemoryPressure(paths map[string]string, level PressureLevel) (<-chan struct{}, error) {
-	dir := paths[oomCgroupName]
+func notifyMemoryPressure(dir string, level PressureLevel) (<-chan struct{}, error) {
 	if dir == "" {
-		return nil, fmt.Errorf("path %q missing", oomCgroupName)
+		return nil, errors.New("memory controller missing")
 	}
 
 	if level > CriticalPressure {
diff --git a/vendor/github.com/cilium/ebpf/asm/instruction.go b/vendor/github.com/cilium/ebpf/asm/instruction.go
index 8058c157..644de428 100644
--- a/vendor/github.com/cilium/ebpf/asm/instruction.go
+++ b/vendor/github.com/cilium/ebpf/asm/instruction.go
@@ -3,7 +3,6 @@ package asm
 import (
 	"encoding/binary"
 	"fmt"
-	"github.com/cilium/ebpf/internal"
 	"io"
 	"math"
 	"strings"
@@ -434,27 +433,15 @@ type bpfInstruction struct {
 type bpfRegisters uint8
 
 func newBPFRegisters(dst, src Register) bpfRegisters {
-	if internal.NativeEndian == binary.LittleEndian {
-		return bpfRegisters((src << 4) | (dst & 0xF))
-	} else {
-		return bpfRegisters((dst << 4) | (src & 0xF))
-	}
+	return bpfRegisters((src << 4) | (dst & 0xF))
 }
 
 func (r bpfRegisters) Dst() Register {
-	if internal.NativeEndian == binary.LittleEndian {
-		return Register(r & 0xF)
-	}else {
-		return Register(r >> 4)
-	}
+	return Register(r & 0xF)
 }
 
 func (r bpfRegisters) Src() Register {
-	if internal.NativeEndian == binary.LittleEndian {
-		return Register(r >> 4)
-	} else {
-		return Register(r & 0xf)
-	}
+	return Register(r >> 4)
 }
 
 type unreferencedSymbolError struct {
diff --git a/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go b/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
index 89baae2b..7efbbd72 100644
--- a/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
+++ b/vendor/github.com/cilium/ebpf/internal/unix/types_linux.go
@@ -36,7 +36,6 @@ const (
 	PERF_SAMPLE_RAW          = linux.PERF_SAMPLE_RAW
 	PERF_FLAG_FD_CLOEXEC     = linux.PERF_FLAG_FD_CLOEXEC
 	RLIM_INFINITY            = linux.RLIM_INFINITY
-	RLIMIT_MEMLOCK           = linux.RLIMIT_MEMLOCK
 )
 
 // Statfs_t is a wrapper
diff --git a/vendor/github.com/cilium/ebpf/internal/unix/types_other.go b/vendor/github.com/cilium/ebpf/internal/unix/types_other.go
index 8fc8e77a..7961b356 100644
--- a/vendor/github.com/cilium/ebpf/internal/unix/types_other.go
+++ b/vendor/github.com/cilium/ebpf/internal/unix/types_other.go
@@ -38,7 +38,6 @@ const (
 	PERF_SAMPLE_RAW          = 0x400
 	PERF_FLAG_FD_CLOEXEC     = 0x8
 	RLIM_INFINITY            = 0x7fffffffffffffff
-	RLIMIT_MEMLOCK           = 8
 )
 
 // Statfs_t is a wrapper
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 457f6644..15358296 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,7 +1,7 @@
 # github.com/checkpoint-restore/go-criu v0.0.0-20191125063657-fcdcd07065c5
 ## explicit
 github.com/checkpoint-restore/go-criu/rpc
-# github.com/cilium/ebpf v0.0.0-20200507155900-a9f01edf17e3
+# github.com/cilium/ebpf v0.0.0-20200319110858-a7172c01168f
 ## explicit
 github.com/cilium/ebpf
 github.com/cilium/ebpf/asm


Test patch:
diff --git a/libcontainer/cgroups/ebpf/devicefilter/devicefilter_test.go b/libcontainer/cgroups/ebpf/devicefilter/devicefilter_test.go
index dfe56a37..59ff4b49 100644
--- a/libcontainer/cgroups/ebpf/devicefilter/devicefilter_test.go
+++ b/libcontainer/cgroups/ebpf/devicefilter/devicefilter_test.go
@@ -39,16 +39,15 @@ func testDeviceFilter(t testing.TB, devices []*configs.Device, expectedStr strin
 func TestDeviceFilter_Nil(t *testing.T) {
 	expected := `
 // load parameters into registers
-        0: LdXMemW dst: r2 src: r1 off: 0 imm: 0
-        1: And32Imm dst: r2 imm: 65535
-        2: LdXMemW dst: r3 src: r1 off: 0 imm: 0
-        3: RSh32Imm dst: r3 imm: 16
-        4: LdXMemW dst: r4 src: r1 off: 4 imm: 0
-        5: LdXMemW dst: r5 src: r1 off: 8 imm: 0
+        0: LdXMemH dst: r2 src: r1 off: 0 imm: 0
+        1: LdXMemW dst: r3 src: r1 off: 0 imm: 0
+        2: RSh32Imm dst: r3 imm: 16
+        3: LdXMemW dst: r4 src: r1 off: 4 imm: 0
+        4: LdXMemW dst: r5 src: r1 off: 8 imm: 0
 block-0:
 // return 0 (reject)
-        6: Mov32Imm dst: r0 imm: 0
-        7: Exit
+        5: Mov32Imm dst: r0 imm: 0
+        6: Exit
 	`
 	testDeviceFilter(t, nil, expected)
 }
@@ -56,92 +55,91 @@ block-0:
 func TestDeviceFilter_BuiltInAllowList(t *testing.T) {
 	expected := `
 // load parameters into registers
-         0: LdXMemW dst: r2 src: r1 off: 0 imm: 0
-         1: And32Imm dst: r2 imm: 65535
-         2: LdXMemW dst: r3 src: r1 off: 0 imm: 0
-         3: RSh32Imm dst: r3 imm: 16
-         4: LdXMemW dst: r4 src: r1 off: 4 imm: 0
-         5: LdXMemW dst: r5 src: r1 off: 8 imm: 0
+         0: LdXMemH dst: r2 src: r1 off: 0 imm: 0
+         1: LdXMemW dst: r3 src: r1 off: 0 imm: 0
+         2: RSh32Imm dst: r3 imm: 16
+         3: LdXMemW dst: r4 src: r1 off: 4 imm: 0
+         4: LdXMemW dst: r5 src: r1 off: 8 imm: 0
 block-0:
 // tuntap (c, 10, 200, rwm, allow)
-         6: JNEImm dst: r2 off: -1 imm: 2 <block-1>
-         7: JNEImm dst: r4 off: -1 imm: 10 <block-1>
-         8: JNEImm dst: r5 off: -1 imm: 200 <block-1>
-         9: Mov32Imm dst: r0 imm: 1
-        10: Exit
+         5: JNEImm dst: r2 off: -1 imm: 2 <block-1>
+         6: JNEImm dst: r4 off: -1 imm: 10 <block-1>
+         7: JNEImm dst: r5 off: -1 imm: 200 <block-1>
+         8: Mov32Imm dst: r0 imm: 1
+         9: Exit
 block-1:
-        11: JNEImm dst: r2 off: -1 imm: 2 <block-2>
-        12: JNEImm dst: r4 off: -1 imm: 5 <block-2>
-        13: JNEImm dst: r5 off: -1 imm: 2 <block-2>
-        14: Mov32Imm dst: r0 imm: 1
-        15: Exit
+        10: JNEImm dst: r2 off: -1 imm: 2 <block-2>
+        11: JNEImm dst: r4 off: -1 imm: 5 <block-2>
+        12: JNEImm dst: r5 off: -1 imm: 2 <block-2>
+        13: Mov32Imm dst: r0 imm: 1
+        14: Exit
 block-2:
 // /dev/pts (c, 136, wildcard, rwm, true)
-        16: JNEImm dst: r2 off: -1 imm: 2 <block-3>
-        17: JNEImm dst: r4 off: -1 imm: 136 <block-3>
-        18: Mov32Imm dst: r0 imm: 1
-        19: Exit
+        15: JNEImm dst: r2 off: -1 imm: 2 <block-3>
+        16: JNEImm dst: r4 off: -1 imm: 136 <block-3>
+        17: Mov32Imm dst: r0 imm: 1
+        18: Exit
 block-3:
-        20: JNEImm dst: r2 off: -1 imm: 2 <block-4>
-        21: JNEImm dst: r4 off: -1 imm: 5 <block-4>
-        22: JNEImm dst: r5 off: -1 imm: 1 <block-4>
-        23: Mov32Imm dst: r0 imm: 1
-        24: Exit
+        19: JNEImm dst: r2 off: -1 imm: 2 <block-4>
+        20: JNEImm dst: r4 off: -1 imm: 5 <block-4>
+        21: JNEImm dst: r5 off: -1 imm: 1 <block-4>
+        22: Mov32Imm dst: r0 imm: 1
+        23: Exit
 block-4:
-        25: JNEImm dst: r2 off: -1 imm: 2 <block-5>
-        26: JNEImm dst: r4 off: -1 imm: 1 <block-5>
-        27: JNEImm dst: r5 off: -1 imm: 9 <block-5>
-        28: Mov32Imm dst: r0 imm: 1
-        29: Exit
+        24: JNEImm dst: r2 off: -1 imm: 2 <block-5>
+        25: JNEImm dst: r4 off: -1 imm: 1 <block-5>
+        26: JNEImm dst: r5 off: -1 imm: 9 <block-5>
+        27: Mov32Imm dst: r0 imm: 1
+        28: Exit
 block-5:
-        30: JNEImm dst: r2 off: -1 imm: 2 <block-6>
-        31: JNEImm dst: r4 off: -1 imm: 1 <block-6>
-        32: JNEImm dst: r5 off: -1 imm: 5 <block-6>
-        33: Mov32Imm dst: r0 imm: 1
-        34: Exit
+        29: JNEImm dst: r2 off: -1 imm: 2 <block-6>
+        30: JNEImm dst: r4 off: -1 imm: 1 <block-6>
+        31: JNEImm dst: r5 off: -1 imm: 5 <block-6>
+        32: Mov32Imm dst: r0 imm: 1
+        33: Exit
 block-6:
-        35: JNEImm dst: r2 off: -1 imm: 2 <block-7>
-        36: JNEImm dst: r4 off: -1 imm: 5 <block-7>
-        37: JNEImm dst: r5 off: -1 imm: 0 <block-7>
-        38: Mov32Imm dst: r0 imm: 1
-        39: Exit
+        34: JNEImm dst: r2 off: -1 imm: 2 <block-7>
+        35: JNEImm dst: r4 off: -1 imm: 5 <block-7>
+        36: JNEImm dst: r5 off: -1 imm: 0 <block-7>
+        37: Mov32Imm dst: r0 imm: 1
+        38: Exit
 block-7:
-        40: JNEImm dst: r2 off: -1 imm: 2 <block-8>
-        41: JNEImm dst: r4 off: -1 imm: 1 <block-8>
-        42: JNEImm dst: r5 off: -1 imm: 7 <block-8>
-        43: Mov32Imm dst: r0 imm: 1
-        44: Exit
+        39: JNEImm dst: r2 off: -1 imm: 2 <block-8>
+        40: JNEImm dst: r4 off: -1 imm: 1 <block-8>
+        41: JNEImm dst: r5 off: -1 imm: 7 <block-8>
+        42: Mov32Imm dst: r0 imm: 1
+        43: Exit
 block-8:
-        45: JNEImm dst: r2 off: -1 imm: 2 <block-9>
-        46: JNEImm dst: r4 off: -1 imm: 1 <block-9>
-        47: JNEImm dst: r5 off: -1 imm: 8 <block-9>
-        48: Mov32Imm dst: r0 imm: 1
-        49: Exit
+        44: JNEImm dst: r2 off: -1 imm: 2 <block-9>
+        45: JNEImm dst: r4 off: -1 imm: 1 <block-9>
+        46: JNEImm dst: r5 off: -1 imm: 8 <block-9>
+        47: Mov32Imm dst: r0 imm: 1
+        48: Exit
 block-9:
-        50: JNEImm dst: r2 off: -1 imm: 2 <block-10>
-        51: JNEImm dst: r4 off: -1 imm: 1 <block-10>
-        52: JNEImm dst: r5 off: -1 imm: 3 <block-10>
-        53: Mov32Imm dst: r0 imm: 1
-        54: Exit
+        49: JNEImm dst: r2 off: -1 imm: 2 <block-10>
+        50: JNEImm dst: r4 off: -1 imm: 1 <block-10>
+        51: JNEImm dst: r5 off: -1 imm: 3 <block-10>
+        52: Mov32Imm dst: r0 imm: 1
+        53: Exit
 block-10:
 // (b, wildcard, wildcard, m, true)
-        55: JNEImm dst: r2 off: -1 imm: 1 <block-11>
-        56: Mov32Reg dst: r1 src: r3
-        57: And32Imm dst: r1 imm: 1
-        58: JEqImm dst: r1 off: -1 imm: 0 <block-11>
-        59: Mov32Imm dst: r0 imm: 1
-        60: Exit
+        54: JNEImm dst: r2 off: -1 imm: 1 <block-11>
+        55: Mov32Reg dst: r1 src: r3
+        56: And32Imm dst: r1 imm: 1
+        57: JEqImm dst: r1 off: -1 imm: 0 <block-11>
+        58: Mov32Imm dst: r0 imm: 1
+        59: Exit
 block-11:
 // (c, wildcard, wildcard, m, true)
-        61: JNEImm dst: r2 off: -1 imm: 2 <block-12>
-        62: Mov32Reg dst: r1 src: r3
-        63: And32Imm dst: r1 imm: 1
-        64: JEqImm dst: r1 off: -1 imm: 0 <block-12>
-        65: Mov32Imm dst: r0 imm: 1
-        66: Exit
+        60: JNEImm dst: r2 off: -1 imm: 2 <block-12>
+        61: Mov32Reg dst: r1 src: r3
+        62: And32Imm dst: r1 imm: 1
+        63: JEqImm dst: r1 off: -1 imm: 0 <block-12>
+        64: Mov32Imm dst: r0 imm: 1
+        65: Exit
 block-12:
-        67: Mov32Imm dst: r0 imm: 0
-        68: Exit
+        66: Mov32Imm dst: r0 imm: 0
+        67: Exit
 `
 	testDeviceFilter(t, specconv.AllowedDevices, expected)
 }
@@ -159,16 +157,15 @@ func TestDeviceFilter_Privileged(t *testing.T) {
 	expected :=
 		`
 // load parameters into registers
-        0: LdXMemW dst: r2 src: r1 off: 0 imm: 0
-        1: And32Imm dst: r2 imm: 65535
-        2: LdXMemW dst: r3 src: r1 off: 0 imm: 0
-        3: RSh32Imm dst: r3 imm: 16
-        4: LdXMemW dst: r4 src: r1 off: 4 imm: 0
-        5: LdXMemW dst: r5 src: r1 off: 8 imm: 0
+        0: LdXMemH dst: r2 src: r1 off: 0 imm: 0
+        1: LdXMemW dst: r3 src: r1 off: 0 imm: 0
+        2: RSh32Imm dst: r3 imm: 16
+        3: LdXMemW dst: r4 src: r1 off: 4 imm: 0
+        4: LdXMemW dst: r5 src: r1 off: 8 imm: 0
 block-0:
 // return 1 (accept)
-        6: Mov32Imm dst: r0 imm: 1
-        7: Exit
+        5: Mov32Imm dst: r0 imm: 1
+        6: Exit
 	`
 	testDeviceFilter(t, devices, expected)
 }
@@ -192,23 +189,22 @@ func TestDeviceFilter_PrivilegedExceptSingleDevice(t *testing.T) {
 	}
 	expected := `
 // load parameters into registers
-         0: LdXMemW dst: r2 src: r1 off: 0 imm: 0
-         1: And32Imm dst: r2 imm: 65535
-         2: LdXMemW dst: r3 src: r1 off: 0 imm: 0
-         3: RSh32Imm dst: r3 imm: 16
-         4: LdXMemW dst: r4 src: r1 off: 4 imm: 0
-         5: LdXMemW dst: r5 src: r1 off: 8 imm: 0
+         0: LdXMemH dst: r2 src: r1 off: 0 imm: 0
+         1: LdXMemW dst: r3 src: r1 off: 0 imm: 0
+         2: RSh32Imm dst: r3 imm: 16
+         3: LdXMemW dst: r4 src: r1 off: 4 imm: 0
+         4: LdXMemW dst: r5 src: r1 off: 8 imm: 0
 block-0:
 // return 0 (reject) if type==b && major == 8 && minor == 0
-         6: JNEImm dst: r2 off: -1 imm: 1 <block-1>
-         7: JNEImm dst: r4 off: -1 imm: 8 <block-1>
-         8: JNEImm dst: r5 off: -1 imm: 0 <block-1>
-         9: Mov32Imm dst: r0 imm: 0
-        10: Exit
+         5: JNEImm dst: r2 off: -1 imm: 1 <block-1>
+         6: JNEImm dst: r4 off: -1 imm: 8 <block-1>
+         7: JNEImm dst: r5 off: -1 imm: 0 <block-1>
+         8: Mov32Imm dst: r0 imm: 0
+         9: Exit
 block-1:
 // return 1 (accept)
-        11: Mov32Imm dst: r0 imm: 1
-        12: Exit
+        10: Mov32Imm dst: r0 imm: 1
+        11: Exit
 `
 	testDeviceFilter(t, devices, expected)
 }
@@ -241,23 +237,22 @@ func TestDeviceFilter_Weird(t *testing.T) {
 	// This conforms to runc v1.0.0-rc.9 (cgroup1) behavior.
 	expected := `
 // load parameters into registers
-         0: LdXMemW dst: r2 src: r1 off: 0 imm: 0
-         1: And32Imm dst: r2 imm: 65535
-         2: LdXMemW dst: r3 src: r1 off: 0 imm: 0
-         3: RSh32Imm dst: r3 imm: 16
-         4: LdXMemW dst: r4 src: r1 off: 4 imm: 0
-         5: LdXMemW dst: r5 src: r1 off: 8 imm: 0
+         0: LdXMemH dst: r2 src: r1 off: 0 imm: 0
+         1: LdXMemW dst: r3 src: r1 off: 0 imm: 0
+         2: RSh32Imm dst: r3 imm: 16
+         3: LdXMemW dst: r4 src: r1 off: 4 imm: 0
+         4: LdXMemW dst: r5 src: r1 off: 8 imm: 0
 block-0:
 // return 0 (reject) if type==b && major == 8 && minor == 2
-         6: JNEImm dst: r2 off: -1 imm: 1 <block-1>
-         7: JNEImm dst: r4 off: -1 imm: 8 <block-1>
-         8: JNEImm dst: r5 off: -1 imm: 2 <block-1>
-         9: Mov32Imm dst: r0 imm: 0
-        10: Exit
+         5: JNEImm dst: r2 off: -1 imm: 1 <block-1>
+         6: JNEImm dst: r4 off: -1 imm: 8 <block-1>
+         7: JNEImm dst: r5 off: -1 imm: 2 <block-1>
+         8: Mov32Imm dst: r0 imm: 0
+         9: Exit
 block-1:
 // return 1 (accept)
-        11: Mov32Imm dst: r0 imm: 1
-        12: Exit
+        10: Mov32Imm dst: r0 imm: 1
+        11: Exit
 `
 	testDeviceFilter(t, devices, expected)
 }
diff --git a/libcontainer/notify_linux_test.go b/libcontainer/notify_linux_test.go
index 1e15ae2c..6f8b6d30 100644
--- a/libcontainer/notify_linux_test.go
+++ b/libcontainer/notify_linux_test.go
@@ -14,7 +14,7 @@ import (
 	"golang.org/x/sys/unix"
 )
 
-type notifyFunc func(paths map[string]string) (<-chan struct{}, error)
+type notifyFunc func(path string) (<-chan struct{}, error)
 
 func testMemoryNotification(t *testing.T, evName string, notify notifyFunc, targ string) {
 	memoryPath, err := ioutil.TempDir("", "testmemnotification-"+evName)
@@ -29,10 +29,7 @@ func testMemoryNotification(t *testing.T, evName string, notify notifyFunc, targ
 	if err := ioutil.WriteFile(eventPath, []byte{}, 0700); err != nil {
 		t.Fatal(err)
 	}
-	paths := map[string]string{
-		"memory": memoryPath,
-	}
-	ch, err := notify(paths)
+	ch, err := notify(memoryPath)
 	if err != nil {
 		t.Fatal("expected no error, got:", err)
 	}
@@ -102,8 +99,8 @@ func testMemoryNotification(t *testing.T, evName string, notify notifyFunc, targ
 }
 
 func TestNotifyOnOOM(t *testing.T) {
-	f := func(paths map[string]string) (<-chan struct{}, error) {
-		return notifyOnOOM(paths)
+	f := func(path string) (<-chan struct{}, error) {
+		return notifyOnOOM(path)
 	}
 
 	testMemoryNotification(t, "memory.oom_control", f, "")
@@ -117,8 +114,8 @@ func TestNotifyMemoryPressure(t *testing.T) {
 	}
 
 	for level, arg := range tests {
-		f := func(paths map[string]string) (<-chan struct{}, error) {
-			return notifyMemoryPressure(paths, level)
+		f := func(path string) (<-chan struct{}, error) {
+			return notifyMemoryPressure(path, level)
 		}
 
 		testMemoryNotification(t, "memory.pressure_level", f, arg)
diff --git a/vendor/github.com/cilium/ebpf/run-tests.sh b/vendor/github.com/cilium/ebpf/run-tests.sh
index e60c35e2..daac404c 100644
--- a/vendor/github.com/cilium/ebpf/run-tests.sh
+++ b/vendor/github.com/cilium/ebpf/run-tests.sh
@@ -44,7 +44,7 @@ readonly tmp_dir="${TMPDIR:-$(mktemp -d)}"
 
 test -e "${tmp_dir}/${kernel}" || {
   echo Fetching "${kernel}"
-  curl --fail -L "https://github.com/cilium/ci-kernels/blob/master/${kernel}?raw=true" -o "${tmp_dir}/${kernel}"
+  curl --fail -L "https://github.com/newtools/ci-kernels/blob/master/${kernel}?raw=true" -o "${tmp_dir}/${kernel}"
 }
 
 echo Testing on "${kernel_version}"