コード例 #1
0
ファイル: sysinfo.go プロジェクト: pbx0/docker
// New returns a new SysInfo, using the filesystem to detect which features the kernel supports.
func New(quiet bool) *SysInfo {
	sysInfo := &SysInfo{}
	if cgroupMemoryMountpoint, err := cgroups.FindCgroupMountpoint("memory"); err != nil {
		if !quiet {
			logrus.Warnf("Your kernel does not support cgroup memory limit: %v", err)
		}
	} else {
		// If memory cgroup is mounted, MemoryLimit is always enabled.
		sysInfo.MemoryLimit = true

		_, err1 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes"))
		sysInfo.SwapLimit = err1 == nil
		if !sysInfo.SwapLimit && !quiet {
			logrus.Warn("Your kernel does not support swap memory limit.")
		}

		_, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.oom_control"))
		sysInfo.OomKillDisable = err == nil
		if !sysInfo.OomKillDisable && !quiet {
			logrus.Warnf("Your kernel does not support oom control.")
		}
	}

	if cgroupCpuMountpoint, err := cgroups.FindCgroupMountpoint("cpu"); err != nil {
		if !quiet {
			logrus.Warnf("%v", err)
		}
	} else {
		_, err1 := ioutil.ReadFile(path.Join(cgroupCpuMountpoint, "cpu.cfs_quota_us"))
		sysInfo.CpuCfsQuota = err1 == nil
		if !sysInfo.CpuCfsQuota && !quiet {
			logrus.Warn("Your kernel does not support cgroup cfs quotas")
		}
	}

	// Checek if ipv4_forward is disabled.
	if data, err := ioutil.ReadFile("/proc/sys/net/ipv4/ip_forward"); os.IsNotExist(err) {
		sysInfo.IPv4ForwardingDisabled = true
	} else {
		if enabled, _ := strconv.Atoi(strings.TrimSpace(string(data))); enabled == 0 {
			sysInfo.IPv4ForwardingDisabled = true
		} else {
			sysInfo.IPv4ForwardingDisabled = false
		}
	}

	// Check if AppArmor is supported.
	if _, err := os.Stat("/sys/kernel/security/apparmor"); os.IsNotExist(err) {
		sysInfo.AppArmor = false
	} else {
		sysInfo.AppArmor = true
	}

	// Check if Devices cgroup is mounted, it is hard requirement for container security.
	if _, err := cgroups.FindCgroupMountpoint("devices"); err != nil {
		logrus.Fatalf("Error mounting devices cgroup: %v", err)
	}

	return sysInfo
}
コード例 #2
0
ファイル: sysinfo.go プロジェクト: yckrasnodar/docker
// New returns a new SysInfo, using the filesystem to detect which features the kernel supports.
func New(quiet bool) *SysInfo {
	sysInfo := &SysInfo{}
	if cgroupMemoryMountpoint, err := cgroups.FindCgroupMountpoint("memory"); err != nil {
		if !quiet {
			logrus.Warnf("%s", err)
		}
	} else {
		_, err1 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.limit_in_bytes"))
		_, err2 := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.soft_limit_in_bytes"))
		sysInfo.MemoryLimit = err1 == nil && err2 == nil
		if !sysInfo.MemoryLimit && !quiet {
			logrus.Warnf("Your kernel does not support cgroup memory limit.")
		}

		_, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes"))
		sysInfo.SwapLimit = err == nil
		if !sysInfo.SwapLimit && !quiet {
			logrus.Warnf("Your kernel does not support cgroup swap limit.")
		}
	}

	// Check if AppArmor is supported.
	if _, err := os.Stat("/sys/kernel/security/apparmor"); os.IsNotExist(err) {
		sysInfo.AppArmor = false
	} else {
		sysInfo.AppArmor = true
	}
	return sysInfo
}
コード例 #3
0
ファイル: access.go プロジェクト: TencentSA/docker-1.3
func getPath(id, driver, subsystem string) (string, error) {
	cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu")
	if err != nil {
		return "", err
	}

	cgroupRoot = filepath.Dir(cgroupRoot)
	if _, err := os.Stat(cgroupRoot); err != nil {
		return "", fmt.Errorf("cgroups fs not found")
	}

	group, err := findGroup(subsystem)
	if err != nil {
		return "", err
	}

	initPath, err := cgroups.GetInitCgroupDir(group)
	if err != nil {
		return "", err
	}

	path := path.Join(cgroupRoot, group, initPath, driver, id, subsystem)
	if _, err := os.Stat(path); err != nil {
		return "", fmt.Errorf("%s not found", path)
	}
	return path, nil
}
コード例 #4
0
ファイル: apply_raw.go プロジェクト: hgschmie/docker
// TODO(vmarmol): Report error here, we'll probably need to wait for the new API.
func init() {
	// we can pick any subsystem to find the root
	cpuRoot, err := cgroups.FindCgroupMountpoint("cpu")
	if err != nil {
		return
	}
	cgroupRoot = filepath.Dir(cpuRoot)

	if _, err := os.Stat(cgroupRoot); err != nil {
		return
	}
}
コード例 #5
0
ファイル: driver.go プロジェクト: nicholaskh/docker
func findCgroupRootAndDir(subsystem string) (string, string, error) {
	cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem)
	if err != nil {
		return "", "", err
	}

	cgroupDir, err := cgroups.GetThisCgroupDir(subsystem)
	if err != nil {
		return "", "", err
	}
	return cgroupRoot, cgroupDir, nil
}
コード例 #6
0
ファイル: factory.go プロジェクト: vrosnet/kubernetes
func init() {
	useSystemd = systemd.UseSystemd()
	if !useSystemd {
		// Second attempt at checking for systemd, check for a "name=systemd" cgroup.
		mnt, err := cgroups.FindCgroupMountpoint("cpu")
		if err == nil {
			// systemd presence does not mean systemd controls cgroups.
			// If system.slice cgroup exists, then systemd is taking control.
			// This breaks if user creates system.slice manually :)
			useSystemd = utils.FileExists(mnt + "/system.slice")
		}
	}
}
コード例 #7
0
ファイル: apply_systemd.go プロジェクト: 98pm/docker
func getFreezerPath(c *cgroups.Cgroup) (string, error) {
	mountpoint, err := cgroups.FindCgroupMountpoint("freezer")
	if err != nil {
		return "", err
	}

	initPath, err := cgroups.GetInitCgroupDir("freezer")
	if err != nil {
		return "", err
	}

	return filepath.Join(mountpoint, initPath, fmt.Sprintf("%s-%s", c.Parent, c.Name)), nil

}
コード例 #8
0
ファイル: apply_systemd.go プロジェクト: JacsonPaz/docker
func GetPids(c *cgroups.Cgroup) ([]int, error) {
	unitName := getUnitName(c)

	mountpoint, err := cgroups.FindCgroupMountpoint("cpu")
	if err != nil {
		return nil, err
	}

	props, err := theConn.GetUnitTypeProperties(unitName, getIfaceForUnit(unitName))
	if err != nil {
		return nil, err
	}
	cgroup := props["ControlGroup"].(string)

	return cgroups.ReadProcsFile(filepath.Join(mountpoint, cgroup))
}
コード例 #9
0
ファイル: validate.go プロジェクト: alena1108/kubernetes
func validateCgroupMounts() (string, string) {
	const recommendedMount = "/sys/fs/cgroup"
	desc := fmt.Sprintf("\tAny cgroup mount point that is detectible and accessible is supported. %s is recommended as a standard location.\n", recommendedMount)
	mnt, err := cgroups.FindCgroupMountpoint("cpu")
	if err != nil {
		out := "Could not locate cgroup mount point.\n"
		out += desc
		return Unknown, out
	}
	mnt = path.Dir(mnt)
	if !utils.FileExists(mnt) {
		out := fmt.Sprintf("Cgroup mount directory %s inaccessible.\n", mnt)
		out += desc
		return Unsupported, out
	}
	mounts, err := ioutil.ReadDir(mnt)
	if err != nil {
		out := fmt.Sprintf("Could not read cgroup mount directory %s.\n", mnt)
		out += desc
		return Unsupported, out
	}
	mountNames := "\tCgroup mount directories: "
	for _, mount := range mounts {
		mountNames += mount.Name() + " "
	}
	mountNames += "\n"
	out := fmt.Sprintf("Cgroups are mounted at %s.\n", mnt)
	out += mountNames
	out += desc
	info, err := ioutil.ReadFile("/proc/mounts")
	if err != nil {
		out := fmt.Sprintf("Could not read /proc/mounts.\n")
		out += desc
		return Unsupported, out
	}
	out += "\tCgroup mounts:\n"
	for _, line := range strings.Split(string(info), "\n") {
		if strings.Contains(line, " cgroup ") {
			out += "\t" + line + "\n"
		}
	}
	if mnt == recommendedMount {
		return Recommended, out
	}
	return Supported, out
}
コード例 #10
0
ファイル: apply_systemd.go プロジェクト: CNDonny/scope
func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
	mountpoint, err := cgroups.FindCgroupMountpoint(subsystem)
	if err != nil {
		return "", err
	}

	initPath, err := cgroups.GetInitCgroupDir(subsystem)
	if err != nil {
		return "", err
	}

	slice := "system.slice"
	if c.Slice != "" {
		slice = c.Slice
	}

	return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil
}
コード例 #11
0
ファイル: sysinfo_linux.go プロジェクト: fengbaicanhe/docker
// New returns a new SysInfo, using the filesystem to detect which features the kernel supports.
func New(quiet bool) *SysInfo {
	sysInfo := &SysInfo{}
	sysInfo.cgroupMemInfo = checkCgroupMem(quiet)
	sysInfo.cgroupCpuInfo = checkCgroupCpu(quiet)

	_, err := cgroups.FindCgroupMountpoint("devices")
	sysInfo.CgroupDevicesEnabled = err == nil

	sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward")
	sysInfo.BridgeNfCallIptablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables")
	sysInfo.BridgeNfCallIp6tablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables")

	// Check if AppArmor is supported.
	if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
		sysInfo.AppArmor = true
	}

	return sysInfo
}
コード例 #12
0
ファイル: apply_raw.go プロジェクト: jaegerpicker/docker
func (raw *data) path(subsystem string) (string, error) {
	_, err := cgroups.FindCgroupMountpoint(subsystem)
	// If we didn't mount the subsystem, there is no point we make the path.
	if err != nil {
		return "", err
	}

	// If the cgroup name/path is absolute do not look relative to the cgroup of the init process.
	if filepath.IsAbs(raw.cgroup) {
		return filepath.Join(raw.root, subsystem, raw.cgroup), nil
	}

	parent, err := raw.parent(subsystem)
	if err != nil {
		return "", err
	}

	return filepath.Join(parent, raw.cgroup), nil
}
コード例 #13
0
ファイル: factory.go プロジェクト: chenzhen411/kubernetes
func UseSystemd() bool {
	check.Do(func() {
		useSystemd = false

		// Check for system.slice in systemd and cpu cgroup.
		for _, cgroupType := range []string{"name=systemd", "cpu"} {
			mnt, err := cgroups.FindCgroupMountpoint(cgroupType)
			if err == nil {
				// systemd presence does not mean systemd controls cgroups.
				// If system.slice cgroup exists, then systemd is taking control.
				// This breaks if user creates system.slice manually :)
				if utils.FileExists(path.Join(mnt, "system.slice")) {
					useSystemd = true
					break
				}
			}
		}
	})
	return useSystemd
}
コード例 #14
0
ファイル: sysinfo_linux.go プロジェクト: fengbaicanhe/docker
func checkCgroupCpu(quiet bool) *cgroupCpuInfo {
	info := &cgroupCpuInfo{}
	mountPoint, err := cgroups.FindCgroupMountpoint("cpu")
	if err != nil {
		if !quiet {
			logrus.Warn(err)
		}
		return info
	}

	info.CpuCfsPeriod = cgroupEnabled(mountPoint, "cpu.cfs_period_us")
	if !quiet && !info.CpuCfsPeriod {
		logrus.Warn("Your kernel does not support cgroup cfs period")
	}

	info.CpuCfsQuota = cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
	if !quiet && !info.CpuCfsQuota {
		logrus.Warn("Your kernel does not support cgroup cfs quotas")
	}
	return info
}
コード例 #15
0
ファイル: apply_raw.go プロジェクト: bmanas/amazon-ecs-agent
// Gets the cgroupRoot.
func getCgroupRoot() (string, error) {
	cgroupRootLock.Lock()
	defer cgroupRootLock.Unlock()

	if cgroupRoot != "" {
		return cgroupRoot, nil
	}

	// we can pick any subsystem to find the root
	cpuRoot, err := cgroups.FindCgroupMountpoint("cpu")
	if err != nil {
		return "", err
	}
	root := filepath.Dir(cpuRoot)

	if _, err := os.Stat(root); err != nil {
		return "", err
	}

	cgroupRoot = root
	return cgroupRoot, nil
}
コード例 #16
0
ファイル: sysinfo_linux.go プロジェクト: fengbaicanhe/docker
func checkCgroupMem(quiet bool) *cgroupMemInfo {
	info := &cgroupMemInfo{}
	mountPoint, err := cgroups.FindCgroupMountpoint("memory")
	if err != nil {
		if !quiet {
			logrus.Warnf("Your kernel does not support cgroup memory limit: %v", err)
		}
		return info
	}
	info.MemoryLimit = true

	info.SwapLimit = cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
	if !quiet && !info.SwapLimit {
		logrus.Warn("Your kernel does not support swap memory limit.")
	}
	info.OomKillDisable = cgroupEnabled(mountPoint, "memory.oom_control")
	if !quiet && !info.OomKillDisable {
		logrus.Warnf("Your kernel does not support oom control.")
	}

	return info
}
コード例 #17
0
ファイル: driver.go プロジェクト: TencentSA/docker-1.3
func (d *driver) GetPidsForContainer(id string) ([]int, error) {
	pids := []int{}

	// cpu is chosen because it is the only non optional subsystem in cgroups
	subsystem := "cpu"
	cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem)
	if err != nil {
		return pids, err
	}

	cgroupDir, err := cgroups.GetThisCgroupDir(subsystem)
	if err != nil {
		return pids, err
	}

	filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks")
	if _, err := os.Stat(filename); os.IsNotExist(err) {
		// With more recent lxc versions use, cgroup will be in lxc/
		filename = filepath.Join(cgroupRoot, cgroupDir, "lxc", id, "tasks")
	}

	output, err := ioutil.ReadFile(filename)
	if err != nil {
		return pids, err
	}
	for _, p := range strings.Split(string(output), "\n") {
		if len(p) == 0 {
			continue
		}
		pid, err := strconv.Atoi(p)
		if err != nil {
			return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
		}
		pids = append(pids, pid)
	}
	return pids, nil
}
コード例 #18
0
ファイル: validate.go プロジェクト: alena1108/kubernetes
func validateMemoryAccounting(available_cgroups map[string]int) string {
	ok, _ := areCgroupsPresent(available_cgroups, []string{"memory"})
	if !ok {
		return "\tHierarchical memory accounting status unknown: memory cgroup not enabled.\n"
	}
	mnt, err := cgroups.FindCgroupMountpoint("memory")
	if err != nil {
		return "\tHierarchical memory accounting status unknown: memory cgroup not mounted.\n"
	}
	hier, err := ioutil.ReadFile(path.Join(mnt, "memory.use_hierarchy"))
	if err != nil {
		return "\tHierarchical memory accounting status unknown: hierarchy interface unavailable.\n"
	}
	var enabled int
	n, err := fmt.Sscanf(string(hier), "%d", &enabled)
	if err != nil || n != 1 {
		return "\tHierarchical memory accounting status unknown: hierarchy interface unreadable.\n"
	}
	if enabled == 1 {
		return "\tHierarchical memory accounting enabled. Reported memory usage includes memory used by child containers.\n"
	}
	return "\tHierarchical memory accounting disabled. Memory usage does not include usage from child containers.\n"

}
コード例 #19
0
ファイル: apply_raw.go プロジェクト: Gandi/docker
func getCgroupData(c *cgroups.Cgroup, pid int) (*data, error) {
	// we can pick any subsystem to find the root
	cgroupRoot, err := cgroups.FindCgroupMountpoint("cpu")
	if err != nil {
		return nil, err
	}
	cgroupRoot = filepath.Dir(cgroupRoot)

	if _, err := os.Stat(cgroupRoot); err != nil {
		return nil, fmt.Errorf("cgroups fs not found")
	}

	cgroup := c.Name
	if c.Parent != "" {
		cgroup = filepath.Join(c.Parent, cgroup)
	}

	return &data{
		root:   cgroupRoot,
		cgroup: cgroup,
		c:      c,
		pid:    pid,
	}, nil
}
コード例 #20
0
ファイル: requirements.go プロジェクト: swak/docker
		"Test requires underlying root filesystem not be backed by overlay.",
	}
	IPv6 = TestRequirement{
		func() bool {
			cmd := exec.Command("test", "-f", "/proc/net/if_inet6")

			if err := cmd.Run(); err != nil {
				return true
			}
			return false
		},
		"Test requires support for IPv6",
	}
	OomControl = TestRequirement{
		func() bool {
			cgroupMemoryMountpoint, err := cgroups.FindCgroupMountpoint("memory")
			if err != nil {
				return false
			}
			if _, err := ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.memsw.limit_in_bytes")); err != nil {
				return false
			}

			if _, err = ioutil.ReadFile(path.Join(cgroupMemoryMountpoint, "memory.oom_control")); err != nil {
				return false
			}
			return true

		},
		"Test requires Oom control enabled.",
	}
コード例 #21
0
ファイル: requirements.go プロジェクト: rajdeepd/docker
		},
		"Test requires the native (libcontainer) exec driver.",
	}
	NotOverlay = TestRequirement{
		func() bool {
			cmd := exec.Command("grep", "^overlay / overlay", "/proc/mounts")
			if err := cmd.Run(); err != nil {
				return true
			}
			return false
		},
		"Test requires underlying root filesystem not be backed by overlay.",
	}
	CpuCfsPeriod = TestRequirement{
		func() bool {
			cgroupCpuMountpoint, err := cgroups.FindCgroupMountpoint("cpu")
			if err != nil {
				return false
			}
			if _, err := ioutil.ReadFile(path.Join(cgroupCpuMountpoint, "cpu.cfs_period_us")); err != nil {
				return false
			}
			return true
		},
		"Test requires an environment that supports cgroup cfs period.",
	}
	CpuCfsQuota = TestRequirement{
		func() bool {
			cgroupCpuMountpoint, err := cgroups.FindCgroupMountpoint("cpu")
			if err != nil {
				return false
コード例 #22
0
// +build !windows

package main

import (
	"io/ioutil"
	"path"

	"github.com/docker/libcontainer/cgroups"
)

var (
	CpuCfsPeriod = TestRequirement{
		func() bool {
			cgroupCpuMountpoint, err := cgroups.FindCgroupMountpoint("cpu")
			if err != nil {
				return false
			}
			if _, err := ioutil.ReadFile(path.Join(cgroupCpuMountpoint, "cpu.cfs_period_us")); err != nil {
				return false
			}
			return true
		},
		"Test requires an environment that supports cgroup cfs period.",
	}
	CpuCfsQuota = TestRequirement{
		func() bool {
			cgroupCpuMountpoint, err := cgroups.FindCgroupMountpoint("cpu")
			if err != nil {
				return false
			}
コード例 #23
0
ファイル: apply_systemd.go プロジェクト: JacsonPaz/docker
func Apply(c *cgroups.Cgroup, pid int) (cgroups.ActiveCgroup, error) {
	var (
		unitName   = getUnitName(c)
		slice      = "system.slice"
		properties []systemd1.Property
		cpuArgs    []cgroupArg
		cpusetArgs []cgroupArg
		memoryArgs []cgroupArg
		res        systemdCgroup
	)

	// First set up things not supported by systemd

	// -1 disables memorySwap
	if c.MemorySwap >= 0 && (c.Memory != 0 || c.MemorySwap > 0) {
		memorySwap := c.MemorySwap

		if memorySwap == 0 {
			// By default, MemorySwap is set to twice the size of RAM.
			memorySwap = c.Memory * 2
		}

		memoryArgs = append(memoryArgs, cgroupArg{"memory.memsw.limit_in_bytes", strconv.FormatInt(memorySwap, 10)})
	}

	if c.CpusetCpus != "" {
		cpusetArgs = append(cpusetArgs, cgroupArg{"cpuset.cpus", c.CpusetCpus})
	}

	if c.Slice != "" {
		slice = c.Slice
	}

	properties = append(properties,
		systemd1.Property{"Slice", dbus.MakeVariant(slice)},
		systemd1.Property{"Description", dbus.MakeVariant("docker container " + c.Name)},
		systemd1.Property{"PIDs", dbus.MakeVariant([]uint32{uint32(pid)})},
	)

	// Always enable accounting, this gets us the same behaviour as the fs implementation,
	// plus the kernel has some problems with joining the memory cgroup at a later time.
	properties = append(properties,
		systemd1.Property{"MemoryAccounting", dbus.MakeVariant(true)},
		systemd1.Property{"CPUAccounting", dbus.MakeVariant(true)},
		systemd1.Property{"BlockIOAccounting", dbus.MakeVariant(true)})

	if c.Memory != 0 {
		properties = append(properties,
			systemd1.Property{"MemoryLimit", dbus.MakeVariant(uint64(c.Memory))})
	}
	// TODO: MemoryReservation and MemorySwap not available in systemd

	if c.CpuShares != 0 {
		properties = append(properties,
			systemd1.Property{"CPUShares", dbus.MakeVariant(uint64(c.CpuShares))})
	}

	if _, err := theConn.StartTransientUnit(unitName, "replace", properties...); err != nil {
		return nil, err
	}

	// To work around the lack of /dev/pts/* support above we need to manually add these
	// so, ask systemd for the cgroup used
	props, err := theConn.GetUnitTypeProperties(unitName, getIfaceForUnit(unitName))
	if err != nil {
		return nil, err
	}

	cgroup := props["ControlGroup"].(string)

	if !c.AllowAllDevices {
		// Atm we can't use the systemd device support because of two missing things:
		// * Support for wildcards to allow mknod on any device
		// * Support for wildcards to allow /dev/pts support
		//
		// The second is available in more recent systemd as "char-pts", but not in e.g. v208 which is
		// in wide use. When both these are availalable we will be able to switch, but need to keep the old
		// implementation for backwards compat.
		//
		// Note: we can't use systemd to set up the initial limits, and then change the cgroup
		// because systemd will re-write the device settings if it needs to re-apply the cgroup context.
		// This happens at least for v208 when any sibling unit is started.

		mountpoint, err := cgroups.FindCgroupMountpoint("devices")
		if err != nil {
			return nil, err
		}

		initPath, err := cgroups.GetInitCgroupDir("devices")
		if err != nil {
			return nil, err
		}

		dir := filepath.Join(mountpoint, initPath, c.Parent, c.Name)

		res.cleanupDirs = append(res.cleanupDirs, dir)

		if err := os.MkdirAll(dir, 0755); err != nil && !os.IsExist(err) {
			return nil, err
		}

		if err := ioutil.WriteFile(filepath.Join(dir, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
			return nil, err
		}

		if err := writeFile(dir, "devices.deny", "a"); err != nil {
			return nil, err
		}

		for _, dev := range c.AllowedDevices {
			if err := writeFile(dir, "devices.allow", dev.GetCgroupAllowString()); err != nil {
				return nil, err
			}
		}
	}

	if len(cpuArgs) != 0 {
		mountpoint, err := cgroups.FindCgroupMountpoint("cpu")
		if err != nil {
			return nil, err
		}

		path := filepath.Join(mountpoint, cgroup)

		for _, arg := range cpuArgs {
			if err := ioutil.WriteFile(filepath.Join(path, arg.File), []byte(arg.Value), 0700); err != nil {
				return nil, err
			}
		}
	}

	if len(memoryArgs) != 0 {
		mountpoint, err := cgroups.FindCgroupMountpoint("memory")
		if err != nil {
			return nil, err
		}

		path := filepath.Join(mountpoint, cgroup)

		for _, arg := range memoryArgs {
			if err := ioutil.WriteFile(filepath.Join(path, arg.File), []byte(arg.Value), 0700); err != nil {
				return nil, err
			}
		}
	}

	// we need to manually join the freezer cgroup in systemd because it does not currently support it
	// via the dbus api
	freezerPath, err := joinFreezer(c, pid)
	if err != nil {
		return nil, err
	}
	res.cleanupDirs = append(res.cleanupDirs, freezerPath)

	if len(cpusetArgs) != 0 {
		// systemd does not atm set up the cpuset controller, so we must manually
		// join it. Additionally that is a very finicky controller where each
		// level must have a full setup as the default for a new directory is "no cpus",
		// so we avoid using any hierarchies here, creating a toplevel directory.
		mountpoint, err := cgroups.FindCgroupMountpoint("cpuset")
		if err != nil {
			return nil, err
		}

		initPath, err := cgroups.GetInitCgroupDir("cpuset")
		if err != nil {
			return nil, err
		}

		var (
			foundCpus bool
			foundMems bool

			rootPath = filepath.Join(mountpoint, initPath)
			path     = filepath.Join(mountpoint, initPath, c.Parent+"-"+c.Name)
		)

		res.cleanupDirs = append(res.cleanupDirs, path)

		if err := os.MkdirAll(path, 0755); err != nil && !os.IsExist(err) {
			return nil, err
		}

		for _, arg := range cpusetArgs {
			if arg.File == "cpuset.cpus" {
				foundCpus = true
			}
			if arg.File == "cpuset.mems" {
				foundMems = true
			}
			if err := ioutil.WriteFile(filepath.Join(path, arg.File), []byte(arg.Value), 0700); err != nil {
				return nil, err
			}
		}

		// These are required, if not specified inherit from parent
		if !foundCpus {
			s, err := ioutil.ReadFile(filepath.Join(rootPath, "cpuset.cpus"))
			if err != nil {
				return nil, err
			}

			if err := ioutil.WriteFile(filepath.Join(path, "cpuset.cpus"), s, 0700); err != nil {
				return nil, err
			}
		}

		// These are required, if not specified inherit from parent
		if !foundMems {
			s, err := ioutil.ReadFile(filepath.Join(rootPath, "cpuset.mems"))
			if err != nil {
				return nil, err
			}

			if err := ioutil.WriteFile(filepath.Join(path, "cpuset.mems"), s, 0700); err != nil {
				return nil, err
			}
		}

		if err := ioutil.WriteFile(filepath.Join(path, "cgroup.procs"), []byte(strconv.Itoa(pid)), 0700); err != nil {
			return nil, err
		}
	}

	return &res, nil
}