Selaa lähdekoodia

vendor: github.com/containerd/cgroups v1.0.3

full diff: https://github.com/containerd/cgroups/compare/v1.0.1...v1.0.3

- cgroup v1: implement AddProc()
- cgroup v1: reduce duplicated code
- cgroup v2: Fix potential dirfd leak
- cgroup v2: remove unimplemented errors and ErrorHandler, IgnoreNotExist
- cgroup v2: v2: Fix inotify fd leak when cgroup is deleted
- cgroup.go: avoid panic on nil interface
- cgroup: Optionally add process and task to a subsystems subset
- fix Implicit memory aliasing in for loop
- go.mod: coreos/go-systemd/v22 v22.3.2 to prepare for deprecations
- Improvements on cgroup v2 support
- replace pkg/errors from vendor
- Use /proc/partitions to get device names
- utils: export ParseCgroupFile()

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 3 vuotta sitten
vanhempi
commit
461845bfbc

+ 1 - 1
vendor.mod

@@ -17,7 +17,7 @@ require (
 	github.com/aws/aws-sdk-go v1.28.11
 	github.com/bsphere/le_go v0.0.0-20170215134836-7a984a84b549
 	github.com/cloudflare/cfssl v0.0.0-20180323000720-5d63dbd981b5
-	github.com/containerd/cgroups v1.0.1
+	github.com/containerd/cgroups v1.0.3
 	github.com/containerd/containerd v1.5.9
 	github.com/containerd/continuity v0.1.0
 	github.com/containerd/fifo v1.0.0

+ 8 - 1
vendor.sum

@@ -125,8 +125,9 @@ github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1
 github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
 github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
 github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
-github.com/containerd/cgroups v1.0.1 h1:iJnMvco9XGvKUvNQkv88bE4uJXxRQH18efbKo9w5vHQ=
 github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
+github.com/containerd/cgroups v1.0.3 h1:ADZftAkglvCiD44c77s5YmMqaP2pzVCFZvBmAlBdAP4=
+github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
 github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
 github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
 github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
@@ -725,6 +726,7 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
 github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
 github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
@@ -739,6 +741,8 @@ go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
+go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -804,6 +808,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -879,8 +884,10 @@ golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210313202042-bd2e13477e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

+ 4 - 4
vendor/github.com/containerd/cgroups/README.md

@@ -1,7 +1,7 @@
 # cgroups
 
 [![Build Status](https://github.com/containerd/cgroups/workflows/CI/badge.svg)](https://github.com/containerd/cgroups/actions?query=workflow%3ACI)
-[![codecov](https://codecov.io/gh/containerd/cgroups/branch/master/graph/badge.svg)](https://codecov.io/gh/containerd/cgroups)
+[![codecov](https://codecov.io/gh/containerd/cgroups/branch/main/graph/badge.svg)](https://codecov.io/gh/containerd/cgroups)
 [![GoDoc](https://godoc.org/github.com/containerd/cgroups?status.svg)](https://godoc.org/github.com/containerd/cgroups)
 [![Go Report Card](https://goreportcard.com/badge/github.com/containerd/cgroups)](https://goreportcard.com/report/github.com/containerd/cgroups)
 
@@ -142,8 +142,8 @@ All static path should not include `/sys/fs/cgroup/` prefix, it should start wit
 Cgroups is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
 As a containerd sub-project, you will find the:
 
- * [Project governance](https://github.com/containerd/project/blob/master/GOVERNANCE.md),
- * [Maintainers](https://github.com/containerd/project/blob/master/MAINTAINERS),
- * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
+ * [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
+ * [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
+ * and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
 
 information in our [`containerd/project`](https://github.com/containerd/project) repository.

+ 6 - 3
vendor/github.com/containerd/cgroups/blkio.go

@@ -130,7 +130,7 @@ func (b *blkioController) Stat(path string, stats *v1.Metrics) error {
 		}
 	}
 
-	f, err := os.Open(filepath.Join(b.procRoot, "diskstats"))
+	f, err := os.Open(filepath.Join(b.procRoot, "partitions"))
 	if err != nil {
 		return err
 	}
@@ -335,7 +335,10 @@ func getDevices(r io.Reader) (map[deviceKey]string, error) {
 		s       = bufio.NewScanner(r)
 		devices = make(map[deviceKey]string)
 	)
-	for s.Scan() {
+	for i := 0; s.Scan(); i++ {
+		if i < 2 {
+			continue
+		}
 		fields := strings.Fields(s.Text())
 		major, err := strconv.Atoi(fields[0])
 		if err != nil {
@@ -352,7 +355,7 @@ func getDevices(r io.Reader) (map[deviceKey]string, error) {
 		if _, ok := devices[key]; ok {
 			continue
 		}
-		devices[key] = filepath.Join("/dev", fields[2])
+		devices[key] = filepath.Join("/dev", fields[3])
 	}
 	return devices, s.Err()
 }

+ 59 - 78
vendor/github.com/containerd/cgroups/cgroup.go

@@ -17,6 +17,7 @@
 package cgroups
 
 import (
+	"errors"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -25,8 +26,8 @@ import (
 	"sync"
 
 	v1 "github.com/containerd/cgroups/stats/v1"
-	specs "github.com/opencontainers/runtime-spec/specs-go"
-	"github.com/pkg/errors"
+
+	"github.com/opencontainers/runtime-spec/specs-go"
 )
 
 // New returns a new control via the cgroup cgroups interface
@@ -83,7 +84,7 @@ func Load(hierarchy Hierarchy, path Path, opts ...InitOpts) (Cgroup, error) {
 	for _, s := range pathers(subsystems) {
 		p, err := path(s.Name())
 		if err != nil {
-			if os.IsNotExist(errors.Cause(err)) {
+			if  errors.Is(err, os.ErrNotExist) {
 				return nil, ErrCgroupDeleted
 			}
 			if err == ErrControllerNotActive {
@@ -149,38 +150,50 @@ func (c *cgroup) Subsystems() []Subsystem {
 	return c.subsystems
 }
 
-// Add moves the provided process into the new cgroup
-func (c *cgroup) Add(process Process) error {
-	if process.Pid <= 0 {
-		return ErrInvalidPid
+func (c *cgroup) subsystemsFilter(subsystems ...Name) []Subsystem {
+	if len(subsystems) == 0 {
+		return c.subsystems
 	}
-	c.mu.Lock()
-	defer c.mu.Unlock()
-	if c.err != nil {
-		return c.err
-	}
-	return c.add(process)
-}
 
-func (c *cgroup) add(process Process) error {
-	for _, s := range pathers(c.subsystems) {
-		p, err := c.path(s.Name())
-		if err != nil {
-			return err
-		}
-		if err := retryingWriteFile(
-			filepath.Join(s.Path(p), cgroupProcs),
-			[]byte(strconv.Itoa(process.Pid)),
-			defaultFilePerm,
-		); err != nil {
-			return err
+	var filteredSubsystems = []Subsystem{}
+	for _, s := range c.subsystems {
+		for _, f := range subsystems {
+			if s.Name() == f {
+				filteredSubsystems = append(filteredSubsystems, s)
+				break
+			}
 		}
 	}
-	return nil
+
+	return filteredSubsystems
+}
+
+// Add moves the provided process into the new cgroup.
+// Without additional arguments, the process is added to all the cgroup subsystems.
+// When giving Add a list of subsystem names, the process is only added to those
+// subsystems, provided that they are active in the targeted cgroup.
+func (c *cgroup) Add(process Process, subsystems ...Name) error {
+	return c.add(process, cgroupProcs, subsystems...)
+}
+
+// AddProc moves the provided process id into the new cgroup.
+// Without additional arguments, the process with the given id is added to all
+// the cgroup subsystems. When giving AddProc a list of subsystem names, the process
+// id is only added to those subsystems, provided that they are active in the targeted
+// cgroup.
+func (c *cgroup) AddProc(pid uint64, subsystems ...Name) error {
+	return c.add(Process{Pid: int(pid)}, cgroupProcs, subsystems...)
 }
 
-// AddTask moves the provided tasks (threads) into the new cgroup
-func (c *cgroup) AddTask(process Process) error {
+// AddTask moves the provided tasks (threads) into the new cgroup.
+// Without additional arguments, the task is added to all the cgroup subsystems.
+// When giving AddTask a list of subsystem names, the task is only added to those
+// subsystems, provided that they are active in the targeted cgroup.
+func (c *cgroup) AddTask(process Process, subsystems ...Name) error {
+	return c.add(process, cgroupTasks, subsystems...)
+}
+
+func (c *cgroup) add(process Process, pType procType, subsystems ...Name) error {
 	if process.Pid <= 0 {
 		return ErrInvalidPid
 	}
@@ -189,20 +202,17 @@ func (c *cgroup) AddTask(process Process) error {
 	if c.err != nil {
 		return c.err
 	}
-	return c.addTask(process)
-}
-
-func (c *cgroup) addTask(process Process) error {
-	for _, s := range pathers(c.subsystems) {
+	for _, s := range pathers(c.subsystemsFilter(subsystems...)) {
 		p, err := c.path(s.Name())
 		if err != nil {
 			return err
 		}
-		if err := retryingWriteFile(
-			filepath.Join(s.Path(p), cgroupTasks),
+		err = retryingWriteFile(
+			filepath.Join(s.Path(p), pType),
 			[]byte(strconv.Itoa(process.Pid)),
 			defaultFilePerm,
-		); err != nil {
+		)
+		if err != nil {
 			return err
 		}
 	}
@@ -326,39 +336,7 @@ func (c *cgroup) Processes(subsystem Name, recursive bool) ([]Process, error) {
 	if c.err != nil {
 		return nil, c.err
 	}
-	return c.processes(subsystem, recursive)
-}
-
-func (c *cgroup) processes(subsystem Name, recursive bool) ([]Process, error) {
-	s := c.getSubsystem(subsystem)
-	sp, err := c.path(subsystem)
-	if err != nil {
-		return nil, err
-	}
-	path := s.(pather).Path(sp)
-	var processes []Process
-	err = filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
-		if err != nil {
-			return err
-		}
-		if !recursive && info.IsDir() {
-			if p == path {
-				return nil
-			}
-			return filepath.SkipDir
-		}
-		dir, name := filepath.Split(p)
-		if name != cgroupProcs {
-			return nil
-		}
-		procs, err := readPids(dir, subsystem)
-		if err != nil {
-			return err
-		}
-		processes = append(processes, procs...)
-		return nil
-	})
-	return processes, err
+	return c.processes(subsystem, recursive, cgroupProcs)
 }
 
 // Tasks returns the tasks running inside the cgroup along
@@ -369,17 +347,20 @@ func (c *cgroup) Tasks(subsystem Name, recursive bool) ([]Task, error) {
 	if c.err != nil {
 		return nil, c.err
 	}
-	return c.tasks(subsystem, recursive)
+	return c.processes(subsystem, recursive, cgroupTasks)
 }
 
-func (c *cgroup) tasks(subsystem Name, recursive bool) ([]Task, error) {
+func (c *cgroup) processes(subsystem Name, recursive bool, pType procType) ([]Process, error) {
 	s := c.getSubsystem(subsystem)
 	sp, err := c.path(subsystem)
 	if err != nil {
 		return nil, err
 	}
+	if s == nil {
+		return nil, fmt.Errorf("cgroups: %s doesn't exist in %s subsystem", sp, subsystem)
+	}
 	path := s.(pather).Path(sp)
-	var tasks []Task
+	var processes []Process
 	err = filepath.Walk(path, func(p string, info os.FileInfo, err error) error {
 		if err != nil {
 			return err
@@ -391,17 +372,17 @@ func (c *cgroup) tasks(subsystem Name, recursive bool) ([]Task, error) {
 			return filepath.SkipDir
 		}
 		dir, name := filepath.Split(p)
-		if name != cgroupTasks {
+		if name != pType {
 			return nil
 		}
-		procs, err := readTasksPids(dir, subsystem)
+		procs, err := readPids(dir, subsystem, pType)
 		if err != nil {
 			return err
 		}
-		tasks = append(tasks, procs...)
+		processes = append(processes, procs...)
 		return nil
 	})
-	return tasks, err
+	return processes, err
 }
 
 // Freeze freezes the entire cgroup and all the processes inside it
@@ -511,7 +492,7 @@ func (c *cgroup) MoveTo(destination Cgroup) error {
 		return c.err
 	}
 	for _, s := range c.subsystems {
-		processes, err := c.processes(s.Name(), true)
+		processes, err := c.processes(s.Name(), true, cgroupProcs)
 		if err != nil {
 			return err
 		}

+ 25 - 18
vendor/github.com/containerd/cgroups/control.go

@@ -23,10 +23,12 @@ import (
 	specs "github.com/opencontainers/runtime-spec/specs-go"
 )
 
+type procType = string
+
 const (
-	cgroupProcs    = "cgroup.procs"
-	cgroupTasks    = "tasks"
-	defaultDirPerm = 0755
+	cgroupProcs    procType = "cgroup.procs"
+	cgroupTasks    procType = "tasks"
+	defaultDirPerm          = 0755
 )
 
 // defaultFilePerm is a var so that the test framework can change the filemode
@@ -37,32 +39,37 @@ const (
 var defaultFilePerm = os.FileMode(0)
 
 type Process struct {
-	// Subsystem is the name of the subsystem that the process is in
+	// Subsystem is the name of the subsystem that the process / task is in.
 	Subsystem Name
-	// Pid is the process id of the process
+	// Pid is the process id of the process / task.
 	Pid int
-	// Path is the full path of the subsystem and location that the process is in
+	// Path is the full path of the subsystem and location that the process / task is in.
 	Path string
 }
 
-type Task struct {
-	// Subsystem is the name of the subsystem that the task is in
-	Subsystem Name
-	// Pid is the process id of the task
-	Pid int
-	// Path is the full path of the subsystem and location that the task is in
-	Path string
-}
+type Task = Process
 
 // Cgroup handles interactions with the individual groups to perform
 // actions on them as them main interface to this cgroup package
 type Cgroup interface {
 	// New creates a new cgroup under the calling cgroup
 	New(string, *specs.LinuxResources) (Cgroup, error)
-	// Add adds a process to the cgroup (cgroup.procs)
-	Add(Process) error
-	// AddTask adds a process to the cgroup (tasks)
-	AddTask(Process) error
+	// Add adds a process to the cgroup (cgroup.procs). Without additional arguments,
+	// the process is added to all the cgroup subsystems. When giving Add a list of
+	// subsystem names, the process is only added to those subsystems, provided that
+	// they are active in the targeted cgroup.
+	Add(Process, ...Name) error
+	// AddProc adds the process with the given id to the cgroup (cgroup.procs).
+	// Without additional arguments, the process with the given id is added to all
+	// the cgroup subsystems. When giving AddProc a list of subsystem names, the process
+	// id is only added to those subsystems, provided that they are active in the targeted
+	// cgroup.
+	AddProc(uint64, ...Name) error
+	// AddTask adds a process to the cgroup (tasks). Without additional arguments, the
+	// task is added to all the cgroup subsystems. When giving AddTask a list of subsystem
+	// names, the task is only added to those subsystems, provided that they are active in
+	// the targeted cgroup.
+	AddTask(Process, ...Name) error
 	// Delete removes the cgroup as a whole
 	Delete() error
 	// MoveTo moves all the processes under the calling cgroup to the provided one

+ 1 - 1
vendor/github.com/containerd/cgroups/opts.go

@@ -17,7 +17,7 @@
 package cgroups
 
 import (
-	"github.com/pkg/errors"
+	"errors"
 )
 
 var (

+ 4 - 5
vendor/github.com/containerd/cgroups/paths.go

@@ -17,10 +17,9 @@
 package cgroups
 
 import (
+	"errors"
 	"fmt"
 	"path/filepath"
-
-	"github.com/pkg/errors"
 )
 
 type Path func(subsystem Name) (string, error)
@@ -39,7 +38,7 @@ func StaticPath(path string) Path {
 // NestedPath will nest the cgroups based on the calling processes cgroup
 // placing its child processes inside its own path
 func NestedPath(suffix string) Path {
-	paths, err := parseCgroupFile("/proc/self/cgroup")
+	paths, err := ParseCgroupFile("/proc/self/cgroup")
 	if err != nil {
 		return errorPath(err)
 	}
@@ -50,9 +49,9 @@ func NestedPath(suffix string) Path {
 // This is commonly used for the Load function to restore an existing container
 func PidPath(pid int) Path {
 	p := fmt.Sprintf("/proc/%d/cgroup", pid)
-	paths, err := parseCgroupFile(p)
+	paths, err := ParseCgroupFile(p)
 	if err != nil {
-		return errorPath(errors.Wrapf(err, "parse cgroup file %s", p))
+		return errorPath(fmt.Errorf("parse cgroup file %s: %w", p, err))
 	}
 	return existingPath(paths, "")
 }

+ 1 - 0
vendor/github.com/containerd/cgroups/rdma.go

@@ -67,6 +67,7 @@ func (p *rdmaController) Create(path string, resources *specs.LinuxResources) er
 
 	for device, limit := range resources.Rdma {
 		if device != "" && (limit.HcaHandles != nil || limit.HcaObjects != nil) {
+			limit := limit
 			return retryingWriteFile(
 				filepath.Join(p.Path(path), "rdma.max"),
 				[]byte(createCmdString(device, &limit)),

+ 9 - 6
vendor/github.com/containerd/cgroups/systemd.go

@@ -17,6 +17,7 @@
 package cgroups
 
 import (
+	"context"
 	"path/filepath"
 	"strings"
 	"sync"
@@ -78,7 +79,8 @@ func (s *SystemdController) Name() Name {
 }
 
 func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
-	conn, err := systemdDbus.New()
+	ctx := context.TODO()
+	conn, err := systemdDbus.NewWithContext(ctx)
 	if err != nil {
 		return err
 	}
@@ -90,7 +92,7 @@ func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
 	checkDelegate := func() {
 		canDelegate = true
 		dlSlice := newProperty("Delegate", true)
-		if _, err := conn.StartTransientUnit(slice, "testdelegate", []systemdDbus.Property{dlSlice}, nil); err != nil {
+		if _, err := conn.StartTransientUnitContext(ctx, slice, "testdelegate", []systemdDbus.Property{dlSlice}, nil); err != nil {
 			if dbusError, ok := err.(dbus.Error); ok {
 				// Starting with systemd v237, Delegate is not even a property of slices anymore,
 				// so the D-Bus call fails with "InvalidArgs" error.
@@ -100,7 +102,7 @@ func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
 			}
 		}
 
-		conn.StopUnit(slice, "testDelegate", nil)
+		_, _ = conn.StopUnitContext(ctx, slice, "testDelegate", nil)
 	}
 	once.Do(checkDelegate)
 	properties := []systemdDbus.Property{
@@ -118,7 +120,7 @@ func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
 	}
 
 	ch := make(chan string)
-	_, err = conn.StartTransientUnit(name, "replace", properties, ch)
+	_, err = conn.StartTransientUnitContext(ctx, name, "replace", properties, ch)
 	if err != nil {
 		return err
 	}
@@ -127,14 +129,15 @@ func (s *SystemdController) Create(path string, _ *specs.LinuxResources) error {
 }
 
 func (s *SystemdController) Delete(path string) error {
-	conn, err := systemdDbus.New()
+	ctx := context.TODO()
+	conn, err := systemdDbus.NewWithContext(ctx)
 	if err != nil {
 		return err
 	}
 	defer conn.Close()
 	_, name := splitName(path)
 	ch := make(chan string)
-	_, err = conn.StopUnit(name, "replace", ch)
+	_, err = conn.StopUnitContext(ctx, name, "replace", ch)
 	if err != nil {
 		return err
 	}

+ 13 - 34
vendor/github.com/containerd/cgroups/utils.go

@@ -164,9 +164,9 @@ func remove(path string) error {
 	return fmt.Errorf("cgroups: unable to remove path %q", path)
 }
 
-// readPids will read all the pids of processes in a cgroup by the provided path
-func readPids(path string, subsystem Name) ([]Process, error) {
-	f, err := os.Open(filepath.Join(path, cgroupProcs))
+// readPids will read all the pids of processes or tasks in a cgroup by the provided path
+func readPids(path string, subsystem Name, pType procType) ([]Process, error) {
+	f, err := os.Open(filepath.Join(path, pType))
 	if err != nil {
 		return nil, err
 	}
@@ -195,36 +195,6 @@ func readPids(path string, subsystem Name) ([]Process, error) {
 	return out, nil
 }
 
-// readTasksPids will read all the pids of tasks in a cgroup by the provided path
-func readTasksPids(path string, subsystem Name) ([]Task, error) {
-	f, err := os.Open(filepath.Join(path, cgroupTasks))
-	if err != nil {
-		return nil, err
-	}
-	defer f.Close()
-	var (
-		out []Task
-		s   = bufio.NewScanner(f)
-	)
-	for s.Scan() {
-		if t := s.Text(); t != "" {
-			pid, err := strconv.Atoi(t)
-			if err != nil {
-				return nil, err
-			}
-			out = append(out, Task{
-				Pid:       pid,
-				Subsystem: subsystem,
-				Path:      path,
-			})
-		}
-	}
-	if err := s.Err(); err != nil {
-		return nil, err
-	}
-	return out, nil
-}
-
 func hugePageSizes() ([]string, error) {
 	var (
 		pageSizes []string
@@ -285,7 +255,16 @@ func parseKV(raw string) (string, uint64, error) {
 	}
 }
 
-func parseCgroupFile(path string) (map[string]string, error) {
+// ParseCgroupFile parses the given cgroup file, typically /proc/self/cgroup
+// or /proc/<pid>/cgroup, into a map of subsystems to cgroup paths, e.g.
+//   "cpu": "/user.slice/user-1000.slice"
+//   "pids": "/user.slice/user-1000.slice"
+// etc.
+//
+// Note that for cgroup v2 unified hierarchy, there are no per-controller
+// cgroup paths, so the resulting map will have a single element where the key
+// is empty string ("") and the value is the cgroup path the <pid> is in.
+func ParseCgroupFile(path string) (map[string]string, error) {
 	f, err := os.Open(path)
 	if err != nil {
 		return nil, err

+ 6 - 5
vendor/github.com/containerd/cgroups/v2/devicefilter.go

@@ -23,15 +23,16 @@
 //
 // This particular Go implementation based on runc version
 // https://github.com/opencontainers/runc/blob/master/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go
+
 package v2
 
 import (
+	"errors"
 	"fmt"
 	"math"
 
 	"github.com/cilium/ebpf/asm"
 	"github.com/opencontainers/runtime-spec/specs-go"
-	"github.com/pkg/errors"
 	"golang.org/x/sys/unix"
 )
 
@@ -106,13 +107,13 @@ func (p *program) appendDevice(dev specs.LinuxDeviceCgroup) error {
 		hasType = false
 	default:
 		// if not specified in OCI json, typ is set to DeviceTypeAll
-		return errors.Errorf("invalid DeviceType %q", dev.Type)
+		return fmt.Errorf("invalid DeviceType %q", dev.Type)
 	}
 	if *dev.Major > math.MaxUint32 {
-		return errors.Errorf("invalid major %d", *dev.Major)
+		return fmt.Errorf("invalid major %d", *dev.Major)
 	}
 	if *dev.Minor > math.MaxUint32 {
-		return errors.Errorf("invalid minor %d", *dev.Major)
+		return fmt.Errorf("invalid minor %d", *dev.Major)
 	}
 	hasMajor := *dev.Major >= 0 // if not specified in OCI json, major is set to -1
 	hasMinor := *dev.Minor >= 0
@@ -126,7 +127,7 @@ func (p *program) appendDevice(dev specs.LinuxDeviceCgroup) error {
 		case 'm':
 			bpfAccess |= unix.BPF_DEVCG_ACC_MKNOD
 		default:
-			return errors.Errorf("unknown device access %v", r)
+			return fmt.Errorf("unknown device access %v", r)
 		}
 	}
 	// If the access is rwm, skip the check.

+ 4 - 3
vendor/github.com/containerd/cgroups/v2/ebpf.go

@@ -17,11 +17,12 @@
 package v2
 
 import (
+	"fmt"
+
 	"github.com/cilium/ebpf"
 	"github.com/cilium/ebpf/asm"
 	"github.com/cilium/ebpf/link"
 	"github.com/opencontainers/runtime-spec/specs-go"
-	"github.com/pkg/errors"
 	"golang.org/x/sys/unix"
 )
 
@@ -50,7 +51,7 @@ func LoadAttachCgroupDeviceFilter(insts asm.Instructions, license string, dirFD
 		Flags:   unix.BPF_F_ALLOW_MULTI,
 	})
 	if err != nil {
-		return nilCloser, errors.Wrap(err, "failed to call BPF_PROG_ATTACH (BPF_CGROUP_DEVICE, BPF_F_ALLOW_MULTI)")
+		return nilCloser, fmt.Errorf("failed to call BPF_PROG_ATTACH (BPF_CGROUP_DEVICE, BPF_F_ALLOW_MULTI): %w", err)
 	}
 	closer := func() error {
 		err = link.RawDetachProgram(link.RawDetachProgramOptions{
@@ -59,7 +60,7 @@ func LoadAttachCgroupDeviceFilter(insts asm.Instructions, license string, dirFD
 			Attach:  ebpf.AttachCGroupDevice,
 		})
 		if err != nil {
-			return errors.Wrap(err, "failed to call BPF_PROG_DETACH (BPF_CGROUP_DEVICE)")
+			return fmt.Errorf("failed to call BPF_PROG_DETACH (BPF_CGROUP_DEVICE): %w", err)
 		}
 		return nil
 	}

+ 2 - 22
vendor/github.com/containerd/cgroups/v2/errors.go

@@ -18,29 +18,9 @@ package v2
 
 import (
 	"errors"
-	"os"
 )
 
 var (
-	ErrInvalidPid               = errors.New("cgroups: pid must be greater than 0")
-	ErrMountPointNotExist       = errors.New("cgroups: cgroup mountpoint does not exist")
-	ErrInvalidFormat            = errors.New("cgroups: parsing file with invalid format failed")
-	ErrFreezerNotSupported      = errors.New("cgroups: freezer cgroup (v2) not supported on this system")
-	ErrMemoryNotSupported       = errors.New("cgroups: memory cgroup (v2) not supported on this system")
-	ErrPidsNotSupported         = errors.New("cgroups: pids cgroup (v2) not supported on this system")
-	ErrCPUNotSupported          = errors.New("cgroups: cpu cgroup (v2) not supported on this system")
-	ErrCgroupDeleted            = errors.New("cgroups: cgroup deleted")
-	ErrNoCgroupMountDestination = errors.New("cgroups: cannot find cgroup mount destination")
-	ErrInvalidGroupPath         = errors.New("cgroups: invalid group path")
+	ErrInvalidFormat    = errors.New("cgroups: parsing file with invalid format failed")
+	ErrInvalidGroupPath = errors.New("cgroups: invalid group path")
 )
-
-// ErrorHandler is a function that handles and acts on errors
-type ErrorHandler func(err error) error
-
-// IgnoreNotExist ignores any errors that are for not existing files
-func IgnoreNotExist(err error) error {
-	if os.IsNotExist(err) {
-		return nil
-	}
-	return err
-}

+ 105 - 60
vendor/github.com/containerd/cgroups/v2/manager.go

@@ -18,6 +18,9 @@ package v2
 
 import (
 	"bufio"
+	"context"
+	"errors"
+	"fmt"
 	"io/ioutil"
 	"math"
 	"os"
@@ -28,10 +31,10 @@ import (
 	"time"
 
 	"github.com/containerd/cgroups/v2/stats"
+
 	systemdDbus "github.com/coreos/go-systemd/v22/dbus"
 	"github.com/godbus/dbus/v5"
 	"github.com/opencontainers/runtime-spec/specs-go"
-	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/sys/unix"
 )
@@ -270,7 +273,9 @@ func (c *Manager) ToggleControllers(controllers []string, t ControllerToggle) er
 			// When running as rootless, the user may face EPERM on parent groups, but it is neglible when the
 			// controller is already written.
 			// So we only return the last error.
-			lastErr = errors.Wrapf(err, "failed to write subtree controllers %+v to %q", controllers, filePath)
+			lastErr = fmt.Errorf("failed to write subtree controllers %+v to %q: %w", controllers, filePath, err)
+		} else {
+			lastErr = nil
 		}
 	}
 	return lastErr
@@ -300,15 +305,23 @@ func (c *Manager) NewChild(name string, resources *Resources) (*Manager, error)
 	if err := os.MkdirAll(path, defaultDirPerm); err != nil {
 		return nil, err
 	}
+	m := Manager{
+		unifiedMountpoint: c.unifiedMountpoint,
+		path:              path,
+	}
+	if resources != nil {
+		if err := m.ToggleControllers(resources.EnabledControllers(), Enable); err != nil {
+			// clean up cgroup dir on failure
+			os.Remove(path)
+			return nil, err
+		}
+	}
 	if err := setResources(path, resources); err != nil {
 		// clean up cgroup dir on failure
 		os.Remove(path)
 		return nil, err
 	}
-	return &Manager{
-		unifiedMountpoint: c.unifiedMountpoint,
-		path:              path,
-	}, nil
+	return &m, nil
 }
 
 func (c *Manager) AddProc(pid uint64) error {
@@ -515,7 +528,7 @@ func readKVStatsFile(path string, file string, out map[string]interface{}) error
 	for s.Scan() {
 		name, value, err := parseKV(s.Text())
 		if err != nil {
-			return errors.Wrapf(err, "error while parsing %s (line=%q)", filepath.Join(path, file), s.Text())
+			return fmt.Errorf("error while parsing %s (line=%q): %w", filepath.Join(path, file), s.Text(), err)
 		}
 		out[name] = value
 	}
@@ -547,17 +560,39 @@ func (c *Manager) freeze(path string, state State) error {
 	}
 }
 
+func (c *Manager) isCgroupEmpty() bool {
+	// In case of any error we return true so that we exit and don't leak resources
+	out := make(map[string]interface{})
+	if err := readKVStatsFile(c.path, "cgroup.events", out); err != nil {
+		return true
+	}
+	if v, ok := out["populated"]; ok {
+		populated, ok := v.(uint64)
+		if !ok {
+			return true
+		}
+		return populated == 0
+	}
+	return true
+}
+
 // MemoryEventFD returns inotify file descriptor and 'memory.events' inotify watch descriptor
 func (c *Manager) MemoryEventFD() (int, uint32, error) {
 	fpath := filepath.Join(c.path, "memory.events")
 	fd, err := syscall.InotifyInit()
 	if err != nil {
-		return 0, 0, errors.Errorf("Failed to create inotify fd")
+		return 0, 0, errors.New("failed to create inotify fd")
 	}
 	wd, err := syscall.InotifyAddWatch(fd, fpath, unix.IN_MODIFY)
-	if wd < 0 {
+	if err != nil {
+		syscall.Close(fd)
+		return 0, 0, fmt.Errorf("failed to add inotify watch for %q: %w", fpath, err)
+	}
+	// monitor to detect process exit/cgroup deletion
+	evpath := filepath.Join(c.path, "cgroup.events")
+	if _, err = syscall.InotifyAddWatch(fd, evpath, unix.IN_MODIFY); err != nil {
 		syscall.Close(fd)
-		return 0, 0, errors.Errorf("Failed to add inotify watch for %q", fpath)
+		return 0, 0, fmt.Errorf("failed to add inotify watch for %q: %w", evpath, err)
 	}
 
 	return fd, uint32(wd), nil
@@ -565,22 +600,56 @@ func (c *Manager) MemoryEventFD() (int, uint32, error) {
 
 func (c *Manager) EventChan() (<-chan Event, <-chan error) {
 	ec := make(chan Event)
-	errCh := make(chan error)
+	errCh := make(chan error, 1)
 	go c.waitForEvents(ec, errCh)
 
-	return ec, nil
+	return ec, errCh
 }
 
-func (c *Manager) waitForEvents(ec chan<- Event, errCh chan<- error) {
-	fd, wd, err := c.MemoryEventFD()
+func parseMemoryEvents(out map[string]interface{}) (Event, error) {
+	e := Event{}
+	if v, ok := out["high"]; ok {
+		e.High, ok = v.(uint64)
+		if !ok {
+			return Event{}, fmt.Errorf("cannot convert high to uint64: %+v", v)
+		}
+	}
+	if v, ok := out["low"]; ok {
+		e.Low, ok = v.(uint64)
+		if !ok {
+			return Event{}, fmt.Errorf("cannot convert low to uint64: %+v", v)
+		}
+	}
+	if v, ok := out["max"]; ok {
+		e.Max, ok = v.(uint64)
+		if !ok {
+			return Event{}, fmt.Errorf("cannot convert max to uint64: %+v", v)
+		}
+	}
+	if v, ok := out["oom"]; ok {
+		e.OOM, ok = v.(uint64)
+		if !ok {
+			return Event{}, fmt.Errorf("cannot convert oom to uint64: %+v", v)
+		}
+	}
+	if v, ok := out["oom_kill"]; ok {
+		e.OOMKill, ok = v.(uint64)
+		if !ok {
+			return Event{}, fmt.Errorf("cannot convert oom_kill to uint64: %+v", v)
+		}
+	}
+	return e, nil
+}
 
-	defer syscall.InotifyRmWatch(fd, wd)
-	defer syscall.Close(fd)
+func (c *Manager) waitForEvents(ec chan<- Event, errCh chan<- error) {
+	defer close(errCh)
 
+	fd, _, err := c.MemoryEventFD()
 	if err != nil {
 		errCh <- err
 		return
 	}
+	defer syscall.Close(fd)
 
 	for {
 		buffer := make([]byte, syscall.SizeofInotifyEvent*10)
@@ -591,48 +660,22 @@ func (c *Manager) waitForEvents(ec chan<- Event, errCh chan<- error) {
 		}
 		if bytesRead >= syscall.SizeofInotifyEvent {
 			out := make(map[string]interface{})
-			if err := readKVStatsFile(c.path, "memory.events", out); err == nil {
-				e := Event{}
-				if v, ok := out["high"]; ok {
-					e.High, ok = v.(uint64)
-					if !ok {
-						errCh <- errors.Errorf("cannot convert high to uint64: %+v", v)
-						return
-					}
-				}
-				if v, ok := out["low"]; ok {
-					e.Low, ok = v.(uint64)
-					if !ok {
-						errCh <- errors.Errorf("cannot convert low to uint64: %+v", v)
-						return
-					}
-				}
-				if v, ok := out["max"]; ok {
-					e.Max, ok = v.(uint64)
-					if !ok {
-						errCh <- errors.Errorf("cannot convert max to uint64: %+v", v)
-						return
-					}
-				}
-				if v, ok := out["oom"]; ok {
-					e.OOM, ok = v.(uint64)
-					if !ok {
-						errCh <- errors.Errorf("cannot convert oom to uint64: %+v", v)
-						return
-					}
+			if err := readKVStatsFile(c.path, "memory.events", out); err != nil {
+				// When cgroup is deleted read may return -ENODEV instead of -ENOENT from open.
+				if _, statErr := os.Lstat(filepath.Join(c.path, "memory.events")); !os.IsNotExist(statErr) {
+					errCh <- err
 				}
-				if v, ok := out["oom_kill"]; ok {
-					e.OOMKill, ok = v.(uint64)
-					if !ok {
-						errCh <- errors.Errorf("cannot convert oom_kill to uint64: %+v", v)
-						return
-					}
-				}
-				ec <- e
-			} else {
+				return
+			}
+			e, err := parseMemoryEvents(out)
+			if err != nil {
 				errCh <- err
 				return
 			}
+			ec <- e
+			if c.isCgroupEmpty() {
+				return
+			}
 		}
 	}
 }
@@ -645,9 +688,9 @@ func setDevices(path string, devices []specs.LinuxDeviceCgroup) error {
 	if err != nil {
 		return err
 	}
-	dirFD, err := unix.Open(path, unix.O_DIRECTORY|unix.O_RDONLY, 0600)
+	dirFD, err := unix.Open(path, unix.O_DIRECTORY|unix.O_RDONLY|unix.O_CLOEXEC, 0600)
 	if err != nil {
-		return errors.Errorf("cannot get dir FD for %s", path)
+		return fmt.Errorf("cannot get dir FD for %s", path)
 	}
 	defer unix.Close(dirFD)
 	if _, err := LoadAttachCgroupDeviceFilter(insts, license, dirFD); err != nil {
@@ -662,8 +705,9 @@ func NewSystemd(slice, group string, pid int, resources *Resources) (*Manager, e
 	if slice == "" {
 		slice = defaultSlice
 	}
+	ctx := context.TODO()
 	path := filepath.Join(defaultCgroup2Path, slice, group)
-	conn, err := systemdDbus.New()
+	conn, err := systemdDbus.NewWithContext(ctx)
 	if err != nil {
 		return &Manager{}, err
 	}
@@ -733,7 +777,7 @@ func NewSystemd(slice, group string, pid int, resources *Resources) (*Manager, e
 	}
 
 	statusChan := make(chan string, 1)
-	if _, err := conn.StartTransientUnit(group, "replace", properties, statusChan); err == nil {
+	if _, err := conn.StartTransientUnitContext(ctx, group, "replace", properties, statusChan); err == nil {
 		select {
 		case <-statusChan:
 		case <-time.After(time.Second):
@@ -759,14 +803,15 @@ func LoadSystemd(slice, group string) (*Manager, error) {
 }
 
 func (c *Manager) DeleteSystemd() error {
-	conn, err := systemdDbus.New()
+	ctx := context.TODO()
+	conn, err := systemdDbus.NewWithContext(ctx)
 	if err != nil {
 		return err
 	}
 	defer conn.Close()
 	group := systemdUnitFromPath(c.path)
 	ch := make(chan string)
-	_, err = conn.StopUnit(group, "replace", ch)
+	_, err = conn.StopUnitContext(ctx, group, "replace", ch)
 	if err != nil {
 		return err
 	}

+ 2 - 2
vendor/github.com/containerd/cgroups/v2/utils.go

@@ -29,9 +29,9 @@ import (
 	"time"
 
 	"github.com/containerd/cgroups/v2/stats"
+
 	"github.com/godbus/dbus/v5"
 	"github.com/opencontainers/runtime-spec/specs-go"
-	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 )
 
@@ -61,7 +61,7 @@ func remove(path string) error {
 			return nil
 		}
 	}
-	return errors.Wrapf(err, "cgroups: unable to remove path %q", path)
+	return fmt.Errorf("cgroups: unable to remove path %q: %w", path, err)
 }
 
 // parseCgroupProcsFile parses /sys/fs/cgroup/$GROUPPATH/cgroup.procs

+ 2 - 2
vendor/modules.txt

@@ -131,8 +131,8 @@ github.com/cloudflare/cfssl/log
 github.com/cloudflare/cfssl/ocsp/config
 github.com/cloudflare/cfssl/signer
 github.com/cloudflare/cfssl/signer/local
-# github.com/containerd/cgroups v1.0.1
-## explicit; go 1.13
+# github.com/containerd/cgroups v1.0.3
+## explicit; go 1.16
 github.com/containerd/cgroups
 github.com/containerd/cgroups/stats/v1
 github.com/containerd/cgroups/v2