vendor containerd/cgroups dbea6f2bd41658b84b00417ceefa416b979cbf10

Relevant changes:

- containerd/containerd#51 Fix empty device type
- containerd/containerd#52 Remove call to unitName
  - Calling unitName incorrectly appends -slice onto the end of the slice cgroup we are looking for
  - addresses containerd/containerd#47 cgroups: cgroup deleted
- containerd/containerd#53 systemd-239+ no longer allows delegate slice
- containerd/containerd#54 Bugfix: can't write to cpuset cgroup
- containerd/containerd#63 Makes Load function more lenient on subsystems' checking
  - addresses containerd/containerd#58 Very strict checking of subsystems' existence while loading cgroup
- containerd/containerd#67 Add functionality for retrieving all tasks of a cgroup
- containerd/containerd#68 Fix net_prio typo
- containerd/containerd#69 Blkio weight/leafWeight pointer value
- containerd/containerd#77 Check for non-active/supported cgroups
  - addresses containerd/containerd#76 unable to find * in controller set: unknown
  - addresses docker/for-linux#545 Raspbian: Error response from daemon: unable to find "net_prio" in controller set: unknown
  - addresses docker/for-linux#552 Error response from daemon: unable to find "cpuacct" in controller set: unknown
  - addresses docker/for-linux#545 Raspbian: Error response from daemon: unable to find "net_prio" in controller set: unknown

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 386b06eacd689bb98fb4117087614466c6e130f3)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
diff --git a/vendor.conf b/vendor.conf
index 45c9deb..6d3c458 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -121,7 +121,7 @@
 github.com/containerd/containerd 9754871865f7fe2f4e74d43e2fc7ccd237edcbce # v1.2.2
 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
 github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d
-github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
+github.com/containerd/cgroups dbea6f2bd41658b84b00417ceefa416b979cbf10
 github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23
 github.com/containerd/cri 0d5cabd006cb5319dc965046067b8432d9fa5ef8 # release/1.2 branch
 github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3
diff --git a/vendor/github.com/containerd/cgroups/README.md b/vendor/github.com/containerd/cgroups/README.md
index 69e932a..81ad11c 100644
--- a/vendor/github.com/containerd/cgroups/README.md
+++ b/vendor/github.com/containerd/cgroups/README.md
@@ -1,8 +1,9 @@
 # cgroups
 
 [![Build Status](https://travis-ci.org/containerd/cgroups.svg?branch=master)](https://travis-ci.org/containerd/cgroups)
-
 [![codecov](https://codecov.io/gh/containerd/cgroups/branch/master/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)
 
 Go package for creating, managing, inspecting, and destroying cgroups.
 The resources format for settings on the cgroup uses the OCI runtime-spec found
@@ -110,3 +111,14 @@
 ```go
 subCgroup, err := control.New("child", resources)
 ```
+
+## Project details
+
+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)
+
+information in our [`containerd/project`](https://github.com/containerd/project) repository.
diff --git a/vendor/github.com/containerd/cgroups/blkio.go b/vendor/github.com/containerd/cgroups/blkio.go
index fc1e689..875fb55 100644
--- a/vendor/github.com/containerd/cgroups/blkio.go
+++ b/vendor/github.com/containerd/cgroups/blkio.go
@@ -191,31 +191,42 @@
 }
 
 func createBlkioSettings(blkio *specs.LinuxBlockIO) []blkioSettings {
-	settings := []blkioSettings{
-		{
-			name:   "weight",
-			value:  blkio.Weight,
-			format: uintf,
-		},
-		{
-			name:   "leaf_weight",
-			value:  blkio.LeafWeight,
-			format: uintf,
-		},
-	}
-	for _, wd := range blkio.WeightDevice {
+	settings := []blkioSettings{}
+
+	if blkio.Weight != nil {
 		settings = append(settings,
 			blkioSettings{
-				name:   "weight_device",
-				value:  wd,
-				format: weightdev,
-			},
-			blkioSettings{
-				name:   "leaf_weight_device",
-				value:  wd,
-				format: weightleafdev,
+				name:   "weight",
+				value:  blkio.Weight,
+				format: uintf,
 			})
 	}
+	if blkio.LeafWeight != nil {
+		settings = append(settings,
+			blkioSettings{
+				name:   "leaf_weight",
+				value:  blkio.LeafWeight,
+				format: uintf,
+			})
+	}
+	for _, wd := range blkio.WeightDevice {
+		if wd.Weight != nil {
+			settings = append(settings,
+				blkioSettings{
+					name:   "weight_device",
+					value:  wd,
+					format: weightdev,
+				})
+		}
+		if wd.LeafWeight != nil {
+			settings = append(settings,
+				blkioSettings{
+					name:   "leaf_weight_device",
+					value:  wd,
+					format: weightleafdev,
+				})
+		}
+	}
 	for _, t := range []struct {
 		name string
 		list []specs.LinuxThrottleDevice
@@ -265,12 +276,12 @@
 
 func weightdev(v interface{}) []byte {
 	wd := v.(specs.LinuxWeightDevice)
-	return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, wd.Weight))
+	return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, *wd.Weight))
 }
 
 func weightleafdev(v interface{}) []byte {
 	wd := v.(specs.LinuxWeightDevice)
-	return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, wd.LeafWeight))
+	return []byte(fmt.Sprintf("%d:%d %d", wd.Major, wd.Minor, *wd.LeafWeight))
 }
 
 func throttleddev(v interface{}) []byte {
diff --git a/vendor/github.com/containerd/cgroups/cgroup.go b/vendor/github.com/containerd/cgroups/cgroup.go
index 7959feb..9fbea82 100644
--- a/vendor/github.com/containerd/cgroups/cgroup.go
+++ b/vendor/github.com/containerd/cgroups/cgroup.go
@@ -30,47 +30,84 @@
 )
 
 // New returns a new control via the cgroup cgroups interface
-func New(hierarchy Hierarchy, path Path, resources *specs.LinuxResources) (Cgroup, error) {
+func New(hierarchy Hierarchy, path Path, resources *specs.LinuxResources, opts ...InitOpts) (Cgroup, error) {
+	config := newInitConfig()
+	for _, o := range opts {
+		if err := o(config); err != nil {
+			return nil, err
+		}
+	}
 	subsystems, err := hierarchy()
 	if err != nil {
 		return nil, err
 	}
+	var active []Subsystem
 	for _, s := range subsystems {
+		// check if subsystem exists
 		if err := initializeSubsystem(s, path, resources); err != nil {
+			if err == ErrControllerNotActive {
+				if config.InitCheck != nil {
+					if skerr := config.InitCheck(s, path, err); skerr != nil {
+						if skerr != ErrIgnoreSubsystem {
+							return nil, skerr
+						}
+					}
+				}
+				continue
+			}
 			return nil, err
 		}
+		active = append(active, s)
 	}
 	return &cgroup{
 		path:       path,
-		subsystems: subsystems,
+		subsystems: active,
 	}, nil
 }
 
 // Load will load an existing cgroup and allow it to be controlled
-func Load(hierarchy Hierarchy, path Path) (Cgroup, error) {
+func Load(hierarchy Hierarchy, path Path, opts ...InitOpts) (Cgroup, error) {
+	config := newInitConfig()
+	for _, o := range opts {
+		if err := o(config); err != nil {
+			return nil, err
+		}
+	}
+	var activeSubsystems []Subsystem
 	subsystems, err := hierarchy()
 	if err != nil {
 		return nil, err
 	}
-	// check the the subsystems still exist
+	// check that the subsystems still exist, and keep only those that actually exist
 	for _, s := range pathers(subsystems) {
 		p, err := path(s.Name())
 		if err != nil {
 			if os.IsNotExist(errors.Cause(err)) {
 				return nil, ErrCgroupDeleted
 			}
+			if err == ErrControllerNotActive {
+				if config.InitCheck != nil {
+					if skerr := config.InitCheck(s, path, err); skerr != nil {
+						if skerr != ErrIgnoreSubsystem {
+							return nil, skerr
+						}
+					}
+				}
+				continue
+			}
 			return nil, err
 		}
 		if _, err := os.Lstat(s.Path(p)); err != nil {
 			if os.IsNotExist(err) {
-				return nil, ErrCgroupDeleted
+				continue
 			}
 			return nil, err
 		}
+		activeSubsystems = append(activeSubsystems, s)
 	}
 	return &cgroup{
 		path:       path,
-		subsystems: subsystems,
+		subsystems: activeSubsystems,
 	}, nil
 }
 
@@ -319,6 +356,49 @@
 	return processes, err
 }
 
+// Tasks returns the tasks running inside the cgroup along
+// with the subsystem used, pid, and path
+func (c *cgroup) Tasks(subsystem Name, recursive bool) ([]Task, error) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	if c.err != nil {
+		return nil, c.err
+	}
+	return c.tasks(subsystem, recursive)
+}
+
+func (c *cgroup) tasks(subsystem Name, recursive bool) ([]Task, error) {
+	s := c.getSubsystem(subsystem)
+	sp, err := c.path(subsystem)
+	if err != nil {
+		return nil, err
+	}
+	path := s.(pather).Path(sp)
+	var tasks []Task
+	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 != cgroupTasks {
+			return nil
+		}
+		procs, err := readTasksPids(dir, subsystem)
+		if err != nil {
+			return err
+		}
+		tasks = append(tasks, procs...)
+		return nil
+	})
+	return tasks, err
+}
+
 // Freeze freezes the entire cgroup and all the processes inside it
 func (c *cgroup) Freeze() error {
 	c.mu.Lock()
diff --git a/vendor/github.com/containerd/cgroups/control.go b/vendor/github.com/containerd/cgroups/control.go
index 63e2df9..1f62c54 100644
--- a/vendor/github.com/containerd/cgroups/control.go
+++ b/vendor/github.com/containerd/cgroups/control.go
@@ -44,6 +44,15 @@
 	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
+}
+
 // Cgroup handles interactions with the individual groups to perform
 // actions on them as them main interface to this cgroup package
 type Cgroup interface {
@@ -64,6 +73,8 @@
 	Update(resources *specs.LinuxResources) error
 	// Processes returns all the processes in a select subsystem for the cgroup
 	Processes(Name, bool) ([]Process, error)
+	// Tasks returns all the tasks in a select subsystem for the cgroup
+	Tasks(Name, bool) ([]Task, error)
 	// Freeze freezes or pauses all processes inside the cgroup
 	Freeze() error
 	// Thaw thaw or resumes all processes inside the cgroup
diff --git a/vendor/github.com/containerd/cgroups/cpuset.go b/vendor/github.com/containerd/cgroups/cpuset.go
index f182aa6..3020851 100644
--- a/vendor/github.com/containerd/cgroups/cpuset.go
+++ b/vendor/github.com/containerd/cgroups/cpuset.go
@@ -57,21 +57,21 @@
 	if resources.CPU != nil {
 		for _, t := range []struct {
 			name  string
-			value *string
+			value string
 		}{
 			{
 				name:  "cpus",
-				value: &resources.CPU.Cpus,
+				value: resources.CPU.Cpus,
 			},
 			{
 				name:  "mems",
-				value: &resources.CPU.Mems,
+				value: resources.CPU.Mems,
 			},
 		} {
-			if t.value != nil {
+			if t.value != "" {
 				if err := ioutil.WriteFile(
 					filepath.Join(c.Path(path), fmt.Sprintf("cpuset.%s", t.name)),
-					[]byte(*t.value),
+					[]byte(t.value),
 					defaultFilePerm,
 				); err != nil {
 					return err
diff --git a/vendor/github.com/containerd/cgroups/devices.go b/vendor/github.com/containerd/cgroups/devices.go
index f9a118b..f6a3b19 100644
--- a/vendor/github.com/containerd/cgroups/devices.go
+++ b/vendor/github.com/containerd/cgroups/devices.go
@@ -58,6 +58,9 @@
 		if device.Allow {
 			file = allowDeviceFile
 		}
+		if device.Type == "" {
+			device.Type = "a"
+		}
 		if err := ioutil.WriteFile(
 			filepath.Join(d.Path(path), file),
 			[]byte(deviceString(device)),
diff --git a/vendor/github.com/containerd/cgroups/net_prio.go b/vendor/github.com/containerd/cgroups/net_prio.go
index c771692..612e1bc 100644
--- a/vendor/github.com/containerd/cgroups/net_prio.go
+++ b/vendor/github.com/containerd/cgroups/net_prio.go
@@ -50,7 +50,7 @@
 	if resources.Network != nil {
 		for _, prio := range resources.Network.Priorities {
 			if err := ioutil.WriteFile(
-				filepath.Join(n.Path(path), "net_prio_ifpriomap"),
+				filepath.Join(n.Path(path), "net_prio.ifpriomap"),
 				formatPrio(prio.Name, prio.Priority),
 				defaultFilePerm,
 			); err != nil {
diff --git a/vendor/github.com/containerd/cgroups/opts.go b/vendor/github.com/containerd/cgroups/opts.go
new file mode 100644
index 0000000..7c5d9fb
--- /dev/null
+++ b/vendor/github.com/containerd/cgroups/opts.go
@@ -0,0 +1,61 @@
+/*
+   Copyright The containerd Authors.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package cgroups
+
+import (
+	"github.com/pkg/errors"
+)
+
+var (
+	// ErrIgnoreSubsystem allows the specific subsystem to be skipped
+	ErrIgnoreSubsystem = errors.New("skip subsystem")
+	// ErrDevicesRequired is returned when the devices subsystem is required but
+	// does not exist or is not active
+	ErrDevicesRequired = errors.New("devices subsystem is required")
+)
+
+// InitOpts allows configuration for the creation or loading of a cgroup
+type InitOpts func(*InitConfig) error
+
+// InitConfig provides configuration options for the creation
+// or loading of a cgroup and its subsystems
+type InitConfig struct {
+	// InitCheck can be used to check initialization errors from the subsystem
+	InitCheck InitCheck
+}
+
+func newInitConfig() *InitConfig {
+	return &InitConfig{
+		InitCheck: RequireDevices,
+	}
+}
+
+// InitCheck allows subsystems errors to be checked when initialized or loaded
+type InitCheck func(Subsystem, Path, error) error
+
+// AllowAny allows any subsystem errors to be skipped
+func AllowAny(s Subsystem, p Path, err error) error {
+	return ErrIgnoreSubsystem
+}
+
+// RequireDevices requires the device subsystem but no others
+func RequireDevices(s Subsystem, p Path, err error) error {
+	if s.Name() == Devices {
+		return ErrDevicesRequired
+	}
+	return ErrIgnoreSubsystem
+}
diff --git a/vendor/github.com/containerd/cgroups/paths.go b/vendor/github.com/containerd/cgroups/paths.go
index 455ce85..f45fd42 100644
--- a/vendor/github.com/containerd/cgroups/paths.go
+++ b/vendor/github.com/containerd/cgroups/paths.go
@@ -57,6 +57,9 @@
 	return existingPath(paths, "")
 }
 
+// ErrControllerNotActive is returned when a controller is not supported or enabled
+var ErrControllerNotActive = errors.New("controller is not supported")
+
 func existingPath(paths map[string]string, suffix string) Path {
 	// localize the paths based on the root mount dest for nested cgroups
 	for n, p := range paths {
@@ -77,7 +80,7 @@
 		root, ok := paths[string(name)]
 		if !ok {
 			if root, ok = paths[fmt.Sprintf("name=%s", name)]; !ok {
-				return "", fmt.Errorf("unable to find %q in controller set", name)
+				return "", ErrControllerNotActive
 			}
 		}
 		if suffix != "" {
diff --git a/vendor/github.com/containerd/cgroups/subsystem.go b/vendor/github.com/containerd/cgroups/subsystem.go
index 933a6c3..23de04d 100644
--- a/vendor/github.com/containerd/cgroups/subsystem.go
+++ b/vendor/github.com/containerd/cgroups/subsystem.go
@@ -42,7 +42,7 @@
 )
 
 // Subsystems returns a complete list of the default cgroups
-// avaliable on most linux systems
+// available on most linux systems
 func Subsystems() []Name {
 	n := []Name{
 		Hugetlb,
diff --git a/vendor/github.com/containerd/cgroups/systemd.go b/vendor/github.com/containerd/cgroups/systemd.go
index 8153d74..c5d4e30 100644
--- a/vendor/github.com/containerd/cgroups/systemd.go
+++ b/vendor/github.com/containerd/cgroups/systemd.go
@@ -32,6 +32,11 @@
 	defaultSlice      = "system.slice"
 )
 
+var (
+	canDelegate bool
+	once        sync.Once
+)
+
 func Systemd() ([]Subsystem, error) {
 	root, err := v1MountPoint()
 	if err != nil {
@@ -54,7 +59,7 @@
 		slice = defaultSlice
 	}
 	return func(subsystem Name) (string, error) {
-		return filepath.Join(slice, unitName(name)), nil
+		return filepath.Join(slice, name), nil
 	}
 }
 
@@ -80,15 +85,39 @@
 	}
 	defer conn.Close()
 	slice, name := splitName(path)
+	// We need to see if systemd can handle the delegate property
+	// Systemd will return an error if it cannot handle delegate regardless
+	// of its bool setting.
+	checkDelegate := func() {
+		canDelegate = true
+		dlSlice := newProperty("Delegate", true)
+		if _, err := conn.StartTransientUnit(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.
+				if strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.PropertyReadOnly") || strings.Contains(dbusError.Name, "org.freedesktop.DBus.Error.InvalidArgs") {
+					canDelegate = false
+				}
+			}
+		}
+
+		conn.StopUnit(slice, "testDelegate", nil)
+	}
+	once.Do(checkDelegate)
 	properties := []systemdDbus.Property{
 		systemdDbus.PropDescription(fmt.Sprintf("cgroup %s", name)),
 		systemdDbus.PropWants(slice),
 		newProperty("DefaultDependencies", false),
-		newProperty("Delegate", true),
 		newProperty("MemoryAccounting", true),
 		newProperty("CPUAccounting", true),
 		newProperty("BlockIOAccounting", true),
 	}
+
+	// If we can delegate, we add the property back in
+	if canDelegate {
+		properties = append(properties, newProperty("Delegate", true))
+	}
+
 	ch := make(chan string)
 	_, err = conn.StartTransientUnit(name, "replace", properties, ch)
 	if err != nil {
diff --git a/vendor/github.com/containerd/cgroups/utils.go b/vendor/github.com/containerd/cgroups/utils.go
index 345be4e..f3129b1 100644
--- a/vendor/github.com/containerd/cgroups/utils.go
+++ b/vendor/github.com/containerd/cgroups/utils.go
@@ -111,7 +111,7 @@
 	return fmt.Errorf("cgroups: unable to remove path %q", path)
 }
 
-// readPids will read all the pids in a cgroup by the provided 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))
 	if err != nil {
@@ -138,6 +138,33 @@
 	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,
+			})
+		}
+	}
+	return out, nil
+}
+
 func hugePageSizes() ([]string, error) {
 	var (
 		pageSizes []string