[lxc-devel] [lxd/master] lxd/cgroups: enable cgroup2 limit support

brauner on Github lxc-bot at linuxcontainers.org
Tue Dec 17 11:41:06 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191217/dfff6793/attachment.bin>
-------------- next part --------------
From 437c13f9a17aa98d902d65c4347bc0917c8f62fc Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Tue, 17 Dec 2019 00:30:25 +0100
Subject: [PATCH] lxd/cgroups: enable cgroup2 limit support

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 lxd/cgroup/init.go     | 226 ++++++++++++++++++++++++++++++++++++++++-
 lxd/container_lxc.go   |  88 ++++++++--------
 lxd/container_state.go |   5 +-
 lxd/daemon.go          |   5 +-
 lxd/device/disk.go     |   5 +-
 lxd/devices.go         |  10 +-
 lxd/sys/cgroup.go      |  58 -----------
 lxd/sys/os.go          |  15 +--
 8 files changed, 288 insertions(+), 124 deletions(-)
 delete mode 100644 lxd/sys/cgroup.go

diff --git a/lxd/cgroup/init.go b/lxd/cgroup/init.go
index 97bf705bbf..7239905c86 100644
--- a/lxd/cgroup/init.go
+++ b/lxd/cgroup/init.go
@@ -6,6 +6,9 @@ import (
 	"path/filepath"
 	"strings"
 
+	lxc "gopkg.in/lxc/go-lxc.v2"
+
+	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/logger"
 )
 
@@ -13,13 +16,14 @@ var cgCgroup2SuperMagic int64 = 0x63677270
 
 var cgControllers = map[string]Backend{}
 var cgNamespace bool
+var lxcCgroup2Support bool
 
 // Layout determines the cgroup layout on this system
 type Layout int
 
 const (
 	// CgroupsDisabled indicates that cgroups are not supported
-	CgroupsDisabled = iota
+	CgroupsDisabled Layout = iota
 	// CgroupsUnified indicates that this is a pure cgroup2 layout
 	CgroupsUnified
 	// CgroupsHybrid indicates that this is a mixed cgroup1 and cgroup2 layout
@@ -44,7 +48,6 @@ func GetInfo() Info {
 	info := Info{}
 	info.Namespacing = cgNamespace
 	info.Layout = cgLayout
-
 	return info
 }
 
@@ -64,6 +67,201 @@ func (info *Info) Mode() string {
 	return "unknown"
 }
 
+// Resources is a generic type used to abstract resource control features
+// support for the legacy and unified hierarchy.
+type Resources int
+
+const (
+	// Blkio resource control
+	Blkio Resources = iota
+	// BlkioWeight resource control
+	BlkioWeight
+	// CPU resource control
+	CPU
+	// CPUAcct resource control
+	CPUAcct
+	// CPUSet resource control
+	CPUSet
+	// Devices resource control
+	Devices
+	// Freezer resource control
+	Freezer
+	// Memory resource control
+	Memory
+	// MemoryMaxUsage resource control
+	MemoryMaxUsage
+	// MemorySwap resource control
+	MemorySwap
+	// MemorySwapMaxUsage resource control
+	MemorySwapMaxUsage
+	// MemorySwapUsage resource control
+	MemorySwapUsage
+	// MemorySwappiness resource control
+	MemorySwappiness
+	// NetPrio resource control
+	NetPrio
+	// Pids resource control
+	Pids
+)
+
+// Supports indicates whether or not a given cgroup control knob is available.
+// Note, we use "knob" instead of "controller" because this map holds
+// controllers as well as new features for a given controller, i.e. you can
+// have "blkio" which is a controller and "blkio.weight" which is a feature of
+// the blkio controller.
+func (info *Info) Supports(resource Resources) bool {
+	switch resource {
+	case Blkio:
+		val, ok := cgControllers["blkio"]
+		if ok && val == V1 {
+			return ok
+		}
+		return false
+	case BlkioWeight:
+		val, ok := cgControllers["blkio.weight"]
+		if ok && val == V1 {
+			return ok
+		}
+		return false
+	case CPU:
+		val, ok := cgControllers["cpu"]
+		if ok && val == V1 {
+			return ok
+		}
+
+		return false
+	case CPUAcct:
+		val, ok := cgControllers["cpuacct"]
+		if ok && val == V1 {
+			return ok
+		}
+
+		return false
+	case CPUSet:
+		val, ok := cgControllers["cpuset"]
+		if ok && val == V1 {
+			return ok
+		}
+
+		return false
+	case Devices:
+		_, ok := cgControllers["devices"]
+		return ok
+	case Freezer:
+		_, ok := cgControllers["freezer"]
+		return ok
+	case Memory:
+		_, ok := cgControllers["memory"]
+		return ok
+	case MemoryMaxUsage:
+		_, ok := cgControllers["memory.max_usage_in_bytes"]
+		return ok
+	case MemorySwap:
+		_, ok := cgControllers["memory.memsw.limit_in_bytes"]
+		if ok {
+			return ok
+		}
+
+		_, ok = cgControllers["memory.swap.max"]
+		if ok {
+			return ok
+		}
+
+		return ok
+	case MemorySwapMaxUsage:
+		val, ok := cgControllers["memory.memsw.max_usage_in_bytes"]
+		if ok && val == V1 {
+			return ok
+		}
+
+		return false
+	case MemorySwapUsage:
+		_, ok := cgControllers["memory.memsw.usage_in_bytes"]
+		if ok {
+			return ok
+		}
+
+		_, ok = cgControllers["memory.swap.current"]
+		if ok {
+			return ok
+		}
+
+		return false
+	case MemorySwappiness:
+		val, ok := cgControllers["memory.swappiness"]
+		if ok && val == V1 {
+			return ok
+		}
+
+		return false
+	case NetPrio:
+		val, ok := cgControllers["net_prio"]
+		if ok && val == V1 {
+			return ok
+		}
+
+		return false
+	case Pids:
+		val, ok := cgControllers["pids"]
+		if ok && val == V1 {
+			return ok
+		}
+
+		return false
+	}
+
+	return false
+}
+
+// Log logs cgroup info
+func (info *Info) Log() {
+	logger.Infof(" - cgroup layout: %s", info.Mode())
+
+	if !info.Supports(Blkio) {
+		logger.Warnf(" - Couldn't find the CGroup blkio, I/O limits will be ignored")
+	}
+
+	if !info.Supports(BlkioWeight) {
+		logger.Warnf(" - Couldn't find the CGroup blkio.weight, I/O weight limits will be ignored")
+	}
+
+	if !info.Supports(CPU) {
+		logger.Warnf(" - Couldn't find the CGroup CPU controller, CPU time limits will be ignored")
+	}
+
+	if !info.Supports(CPUAcct) {
+		logger.Warnf(" - Couldn't find the CGroup CPUacct controller, CPU accounting will not be available")
+	}
+
+	if !info.Supports(CPUSet) {
+		logger.Warnf(" - Couldn't find the CGroup CPUset controller, CPU pinning will be ignored")
+	}
+
+	if !info.Supports(Devices) {
+		logger.Warnf(" - Couldn't find the CGroup devices controller, device access control won't work")
+	}
+
+	if !info.Supports(Freezer) {
+		logger.Warnf(" - Couldn't find the CGroup freezer controller, pausing/resuming containers won't work")
+	}
+
+	if !info.Supports(Memory) {
+		logger.Warnf(" - Couldn't find the CGroup memory controller, memory limits will be ignored")
+	}
+
+	if !info.Supports(NetPrio) {
+		logger.Warnf(" - Couldn't find the CGroup network class controller, network limits will be ignored")
+	}
+
+	if !info.Supports(Pids) {
+		logger.Warnf(" - Couldn't find the CGroup pids controller, process limits will be ignored")
+	}
+
+	if !info.Supports(MemorySwap) {
+		logger.Warnf(" - Couldn't find the CGroup memory swap accounting, swap limits will be ignored")
+	}
+}
+
 func init() {
 	_, err := os.Stat("/proc/self/ns/cgroup")
 	if err == nil {
@@ -135,11 +333,35 @@ func init() {
 		}
 	}
 
+	// Check for additional legacy cgroup features
+	val, ok := cgControllers["blkio"]
+	if ok && val == V1 && shared.PathExists("/sys/fs/cgroup/blkio/blkio.weight") {
+		cgControllers["blkio.weight"] = V1
+	}
+
+	val, ok = cgControllers["memory"]
+	if ok && val == V1 && shared.PathExists("/sys/fs/cgroup/memory/memory.memsw.limit_in_bytes") {
+		cgControllers["memory.memsw.limit_in_bytes"] = V2
+	}
+
+	val, ok = cgControllers["memory"]
+	if ok && val == V2 {
+		if shared.PathExists("/sys/fs/cgroup/memory/memory.swap.max") {
+			cgControllers["memory.swap.max"] = V2
+		}
+
+		if shared.PathExists("/sys/fs/cgroup/memory/memory.swap.current") {
+			cgControllers["memory.swap.current"] = V2
+		}
+	}
+
 	if hasV1 && hasV2 {
 		cgLayout = CgroupsHybrid
+		lxcCgroup2Support = lxc.HasApiExtension("cgroup2")
 	} else if hasV1 {
 		cgLayout = CgroupsLegacy
 	} else if hasV2 {
 		cgLayout = CgroupsUnified
+		lxcCgroup2Support = lxc.HasApiExtension("cgroup2")
 	}
 }
diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index 726c852ae2..8cacdb003c 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -856,7 +856,7 @@ func (c *containerLXC) initLXC(config bool) error {
 	}
 
 	// Configure devices cgroup
-	if c.IsPrivileged() && !c.state.OS.RunningInUserNS && c.state.OS.CGroupDevicesController {
+	if c.IsPrivileged() && !c.state.OS.RunningInUserNS && c.state.OS.CGInfo.Supports(cgroup.Devices) {
 		err = lxcSetConfigItem(cc, "lxc.cgroup.devices.deny", "a")
 		if err != nil {
 			return err
@@ -1091,7 +1091,7 @@ func (c *containerLXC) initLXC(config bool) error {
 	}
 
 	// Memory limits
-	if c.state.OS.CGroupMemoryController {
+	if c.state.OS.CGInfo.Supports(cgroup.Memory) {
 		memory := c.expandedConfig["limits.memory"]
 		memoryEnforce := c.expandedConfig["limits.memory.enforce"]
 		memorySwap := c.expandedConfig["limits.memory.swap"]
@@ -1125,7 +1125,7 @@ func (c *containerLXC) initLXC(config bool) error {
 					return err
 				}
 			} else {
-				if c.state.OS.CGroupSwapAccounting && (memorySwap == "" || shared.IsTrue(memorySwap)) {
+				if c.state.OS.CGInfo.Supports(cgroup.MemorySwap) && (memorySwap == "" || shared.IsTrue(memorySwap)) {
 					err = cg.SetMemoryMaxUsage(fmt.Sprintf("%d", valueInt))
 					if err != nil {
 						return err
@@ -1148,20 +1148,22 @@ func (c *containerLXC) initLXC(config bool) error {
 			}
 		}
 
-		// Configure the swappiness
-		if memorySwap != "" && !shared.IsTrue(memorySwap) {
-			err = cg.SetMemorySwappiness("0")
-			if err != nil {
-				return err
-			}
-		} else if memorySwapPriority != "" {
-			priority, err := strconv.Atoi(memorySwapPriority)
-			if err != nil {
-				return err
-			}
-			err = cg.SetMemorySwappiness(fmt.Sprintf("%d", 60-10+priority))
-			if err != nil {
-				return err
+		if c.state.OS.CGInfo.Supports(cgroup.MemorySwappiness) {
+			// Configure the swappiness
+			if memorySwap != "" && !shared.IsTrue(memorySwap) {
+				err = cg.SetMemorySwappiness("0")
+				if err != nil {
+					return err
+				}
+			} else if memorySwapPriority != "" {
+				priority, err := strconv.Atoi(memorySwapPriority)
+				if err != nil {
+					return err
+				}
+				err = cg.SetMemorySwappiness(fmt.Sprintf("%d", 60-10+priority))
+				if err != nil {
+					return err
+				}
 			}
 		}
 	}
@@ -1170,7 +1172,7 @@ func (c *containerLXC) initLXC(config bool) error {
 	cpuPriority := c.expandedConfig["limits.cpu.priority"]
 	cpuAllowance := c.expandedConfig["limits.cpu.allowance"]
 
-	if (cpuPriority != "" || cpuAllowance != "") && c.state.OS.CGroupCPUController {
+	if (cpuPriority != "" || cpuAllowance != "") && c.state.OS.CGInfo.Supports(cgroup.CPU) {
 		cpuShares, cpuCfsQuota, cpuCfsPeriod, err := cgroup.ParseCPU(cpuAllowance, cpuPriority)
 		if err != nil {
 			return err
@@ -1199,7 +1201,7 @@ func (c *containerLXC) initLXC(config bool) error {
 	}
 
 	// Processes
-	if c.state.OS.CGroupPidsController {
+	if c.state.OS.CGInfo.Supports(cgroup.Pids) {
 		processes := c.expandedConfig["limits.processes"]
 		if processes != "" {
 			valueInt, err := strconv.ParseInt(processes, 10, 64)
@@ -1410,7 +1412,7 @@ func (c *containerLXC) deviceStaticShiftMounts(mounts []deviceConfig.MountEntryI
 func (c *containerLXC) deviceAddCgroupRules(cgroups []deviceConfig.RunConfigItem) error {
 	for _, rule := range cgroups {
 		// Only apply devices cgroup rules if container is running privileged and host has devices cgroup controller.
-		if strings.HasPrefix(rule.Key, "devices.") && (!c.isCurrentlyPrivileged() || c.state.OS.RunningInUserNS || !c.state.OS.CGroupDevicesController) {
+		if strings.HasPrefix(rule.Key, "devices.") && (!c.isCurrentlyPrivileged() || c.state.OS.RunningInUserNS || !c.state.OS.CGInfo.Supports(cgroup.Devices)) {
 			continue
 		}
 
@@ -2606,10 +2608,10 @@ func (c *containerLXC) Stop(stateful bool) error {
 	}
 
 	// Fork-bomb mitigation, prevent forking from this point on
-	if c.state.OS.CGroupPidsController {
+	if c.state.OS.CGInfo.Supports(cgroup.Pids) {
 		// Attempt to disable forking new processes
 		cg.SetMaxProcesses(0)
-	} else if c.state.OS.CGroupFreezerController {
+	} else if c.state.OS.CGInfo.Supports(cgroup.Freezer) {
 		// Attempt to freeze the container
 		freezer := make(chan bool, 1)
 		go func() {
@@ -2863,7 +2865,7 @@ func (c *containerLXC) Freeze() error {
 	}
 
 	// Check if the CGroup is available
-	if !c.state.OS.CGroupFreezerController {
+	if !c.state.OS.CGInfo.Supports(cgroup.Freezer) {
 		logger.Info("Unable to freeze container (lack of kernel support)", ctxMap)
 		return nil
 	}
@@ -2911,7 +2913,7 @@ func (c *containerLXC) Unfreeze() error {
 	}
 
 	// Check if the CGroup is available
-	if !c.state.OS.CGroupFreezerController {
+	if !c.state.OS.CGInfo.Supports(cgroup.Freezer) {
 		logger.Info("Unable to unfreeze container (lack of kernel support)", ctxMap)
 		return nil
 	}
@@ -4203,7 +4205,7 @@ func (c *containerLXC) Update(args db.InstanceArgs, userRequested bool) error {
 					}
 				}
 			} else if key == "limits.disk.priority" {
-				if !c.state.OS.CGroupBlkioController {
+				if !c.state.OS.CGInfo.Supports(cgroup.Blkio) {
 					continue
 				}
 
@@ -4228,7 +4230,7 @@ func (c *containerLXC) Update(args db.InstanceArgs, userRequested bool) error {
 				}
 			} else if key == "limits.memory" || strings.HasPrefix(key, "limits.memory.") {
 				// Skip if no memory CGroup
-				if !c.state.OS.CGroupMemoryController {
+				if !c.state.OS.CGInfo.Supports(cgroup.Memory) {
 					continue
 				}
 
@@ -4262,7 +4264,7 @@ func (c *containerLXC) Update(args db.InstanceArgs, userRequested bool) error {
 
 				// Store the old values for revert
 				oldMemswLimit := ""
-				if c.state.OS.CGroupSwapAccounting {
+				if c.state.OS.CGInfo.Supports(cgroup.MemorySwap) {
 					oldMemswLimit, err = cg.GetMemorySwapLimit()
 					if err != nil {
 						oldMemswLimit = ""
@@ -4292,7 +4294,7 @@ func (c *containerLXC) Update(args db.InstanceArgs, userRequested bool) error {
 				}
 
 				// Reset everything
-				if c.state.OS.CGroupSwapAccounting {
+				if c.state.OS.CGInfo.Supports(cgroup.MemorySwap) {
 					err = cg.SetMemorySwapMax("-1")
 					if err != nil {
 						revertMemory()
@@ -4319,7 +4321,7 @@ func (c *containerLXC) Update(args db.InstanceArgs, userRequested bool) error {
 						return err
 					}
 				} else {
-					if c.state.OS.CGroupSwapAccounting && (memorySwap == "" || shared.IsTrue(memorySwap)) {
+					if c.state.OS.CGInfo.Supports(cgroup.MemorySwap) && (memorySwap == "" || shared.IsTrue(memorySwap)) {
 						err = cg.SetMemoryMaxUsage(memory)
 						if err != nil {
 							revertMemory()
@@ -4351,6 +4353,10 @@ func (c *containerLXC) Update(args db.InstanceArgs, userRequested bool) error {
 					}
 				}
 
+				if !c.state.OS.CGInfo.Supports(cgroup.MemorySwappiness) {
+					continue
+				}
+
 				// Configure the swappiness
 				if key == "limits.memory.swap" || key == "limits.memory.swap.priority" {
 					memorySwap := c.expandedConfig["limits.memory.swap"]
@@ -4384,7 +4390,7 @@ func (c *containerLXC) Update(args db.InstanceArgs, userRequested bool) error {
 				cgroup.TaskSchedulerTrigger("container", c.name, "changed")
 			} else if key == "limits.cpu.priority" || key == "limits.cpu.allowance" {
 				// Skip if no cpu CGroup
-				if !c.state.OS.CGroupCPUController {
+				if !c.state.OS.CGInfo.Supports(cgroup.CPU) {
 					continue
 				}
 
@@ -4407,7 +4413,7 @@ func (c *containerLXC) Update(args db.InstanceArgs, userRequested bool) error {
 					return err
 				}
 			} else if key == "limits.processes" {
-				if !c.state.OS.CGroupPidsController {
+				if !c.state.OS.CGInfo.Supports(cgroup.Pids) {
 					continue
 				}
 
@@ -5732,7 +5738,7 @@ func (c *containerLXC) Exec(command []string, env map[string]string, stdin *os.F
 func (c *containerLXC) cpuState() api.InstanceStateCPU {
 	cpu := api.InstanceStateCPU{}
 
-	if !c.state.OS.CGroupCPUacctController {
+	if !c.state.OS.CGInfo.Supports(cgroup.CPUAcct) {
 		return cpu
 	}
 
@@ -5813,7 +5819,7 @@ func (c *containerLXC) memoryState() api.InstanceStateMemory {
 		return memory
 	}
 
-	if !c.state.OS.CGroupMemoryController {
+	if !c.state.OS.CGInfo.Supports(cgroup.Memory) {
 		return memory
 	}
 
@@ -5825,13 +5831,15 @@ func (c *containerLXC) memoryState() api.InstanceStateMemory {
 	}
 
 	// Memory peak in bytes
-	value, err = cg.GetMemoryMaxUsage()
-	valueInt, err1 = strconv.ParseInt(value, 10, 64)
-	if err == nil && err1 == nil {
-		memory.UsagePeak = valueInt
+	if c.state.OS.CGInfo.Supports(cgroup.MemoryMaxUsage) {
+		value, err = cg.GetMemoryMaxUsage()
+		valueInt, err1 = strconv.ParseInt(value, 10, 64)
+		if err == nil && err1 == nil {
+			memory.UsagePeak = valueInt
+		}
 	}
 
-	if c.state.OS.CGroupSwapAccounting {
+	if c.state.OS.CGInfo.Supports(cgroup.MemorySwapUsage) {
 		// Swap in bytes
 		if memory.Usage > 0 {
 			value, err := cg.GetMemorySwapUsage()
@@ -5919,7 +5927,7 @@ func (c *containerLXC) processesState() int64 {
 		return 0
 	}
 
-	if c.state.OS.CGroupPidsController {
+	if c.state.OS.CGInfo.Supports(cgroup.Pids) {
 		cg, err := c.cgroup(nil)
 		if err != nil {
 			return 0
@@ -6509,7 +6517,7 @@ func (c *containerLXC) setNetworkPriority() error {
 	}
 
 	// Don't bother if the cgroup controller doesn't exist
-	if !c.state.OS.CGroupNetPrioController {
+	if !c.state.OS.CGInfo.Supports(cgroup.NetPrio) {
 		return nil
 	}
 
diff --git a/lxd/container_state.go b/lxd/container_state.go
index 2c55c022ad..31586d8bc7 100644
--- a/lxd/container_state.go
+++ b/lxd/container_state.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/gorilla/mux"
 
+	"github.com/lxc/lxd/lxd/cgroup"
 	"github.com/lxc/lxd/lxd/db"
 	"github.com/lxc/lxd/lxd/instance"
 	"github.com/lxc/lxd/lxd/operations"
@@ -190,7 +191,7 @@ func containerStatePut(d *Daemon, r *http.Request) response.Response {
 			return nil
 		}
 	case shared.Freeze:
-		if !d.os.CGroupFreezerController {
+		if !d.os.CGInfo.Supports(cgroup.Freezer) {
 			return response.BadRequest(fmt.Errorf("This system doesn't support freezing containers"))
 		}
 
@@ -200,7 +201,7 @@ func containerStatePut(d *Daemon, r *http.Request) response.Response {
 			return c.Freeze()
 		}
 	case shared.Unfreeze:
-		if !d.os.CGroupFreezerController {
+		if !d.os.CGInfo.Supports(cgroup.Freezer) {
 			return response.BadRequest(fmt.Errorf("This system doesn't support unfreezing containers"))
 		}
 
diff --git a/lxd/daemon.go b/lxd/daemon.go
index 13ae45493a..fdbb60735f 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -28,7 +28,6 @@ import (
 	"gopkg.in/macaroon-bakery.v2/bakery/identchecker"
 	"gopkg.in/macaroon-bakery.v2/httpbakery"
 
-	"github.com/lxc/lxd/lxd/cgroup"
 	"github.com/lxc/lxd/lxd/cluster"
 	"github.com/lxc/lxd/lxd/daemon"
 	"github.com/lxc/lxd/lxd/db"
@@ -623,8 +622,7 @@ func (d *Daemon) init() error {
 		logger.Infof(" - unprivileged file capabilities: no")
 	}
 
-	cgroups := cgroup.GetInfo()
-	logger.Infof(" - cgroup layout: %s", cgroups.Mode())
+	d.os.CGInfo.Log()
 
 	// Detect shiftfs support.
 	if shared.IsTrue(os.Getenv("LXD_SHIFTFS_DISABLE")) {
@@ -648,6 +646,7 @@ func (d *Daemon) init() error {
 		"network_gateway_device_route",
 		"network_phys_macvlan_mtu",
 		"network_veth_router",
+		"cgroup2",
 	}
 	for _, extension := range lxcExtensions {
 		d.os.LXCFeatures[extension] = lxc.HasApiExtension(extension)
diff --git a/lxd/device/disk.go b/lxd/device/disk.go
index 1f10f2055c..431a39ff94 100644
--- a/lxd/device/disk.go
+++ b/lxd/device/disk.go
@@ -12,6 +12,7 @@ import (
 	"github.com/pkg/errors"
 	"golang.org/x/sys/unix"
 
+	"github.com/lxc/lxd/lxd/cgroup"
 	"github.com/lxc/lxd/lxd/db"
 	deviceConfig "github.com/lxc/lxd/lxd/device/config"
 	"github.com/lxc/lxd/lxd/instance/instancetype"
@@ -468,7 +469,7 @@ func (d *disk) generateLimits(runConf *deviceConfig.RunConfig) error {
 	// Disk priority limits.
 	diskPriority := d.instance.ExpandedConfig()["limits.disk.priority"]
 	if diskPriority != "" {
-		if d.state.OS.CGroupBlkioWeightController {
+		if d.state.OS.CGInfo.Supports(cgroup.BlkioWeight) {
 			priorityInt, err := strconv.Atoi(diskPriority)
 			if err != nil {
 				return err
@@ -503,7 +504,7 @@ func (d *disk) generateLimits(runConf *deviceConfig.RunConfig) error {
 	}
 
 	if hasDiskLimits {
-		if !d.state.OS.CGroupBlkioController {
+		if !d.state.OS.CGInfo.Supports(cgroup.Blkio) {
 			return fmt.Errorf("Cannot apply disk limits as blkio cgroup controller is missing")
 		}
 
diff --git a/lxd/devices.go b/lxd/devices.go
index fb8a84f733..d2cd2b00fd 100644
--- a/lxd/devices.go
+++ b/lxd/devices.go
@@ -229,7 +229,7 @@ func deviceTaskBalance(s *state.State) {
 	}
 
 	// Don't bother running when CGroup support isn't there
-	if !s.OS.CGroupCPUsetController {
+	if !s.OS.CGInfo.Supports(cgroup.CPUSet) {
 		return
 	}
 
@@ -409,7 +409,7 @@ func deviceTaskBalance(s *state.State) {
 
 func deviceNetworkPriority(s *state.State, netif string) {
 	// Don't bother running when CGroup support isn't there
-	if !s.OS.CGroupNetPrioController {
+	if !s.OS.CGInfo.Supports(cgroup.NetPrio) {
 		return
 	}
 
@@ -452,7 +452,7 @@ func deviceEventListener(s *state.State) {
 				continue
 			}
 
-			if !s.OS.CGroupCPUsetController {
+			if !s.OS.CGInfo.Supports(cgroup.CPUSet) {
 				continue
 			}
 
@@ -464,7 +464,7 @@ func deviceEventListener(s *state.State) {
 				continue
 			}
 
-			if !s.OS.CGroupNetPrioController {
+			if !s.OS.CGInfo.Supports(cgroup.NetPrio) {
 				continue
 			}
 
@@ -479,7 +479,7 @@ func deviceEventListener(s *state.State) {
 				continue
 			}
 
-			if !s.OS.CGroupCPUsetController {
+			if !s.OS.CGInfo.Supports(cgroup.CPUSet) {
 				continue
 			}
 
diff --git a/lxd/sys/cgroup.go b/lxd/sys/cgroup.go
deleted file mode 100644
index 9faaf7b775..0000000000
--- a/lxd/sys/cgroup.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// +build linux,cgo,!agent
-
-package sys
-
-import (
-	"fmt"
-
-	"github.com/lxc/lxd/shared"
-	"github.com/lxc/lxd/shared/logger"
-)
-
-// Detect CGroup support.
-func (s *OS) initCGroup() {
-	flags := []*bool{
-		&s.CGroupBlkioController,
-		&s.CGroupBlkioWeightController,
-		&s.CGroupCPUController,
-		&s.CGroupCPUacctController,
-		&s.CGroupCPUsetController,
-		&s.CGroupDevicesController,
-		&s.CGroupFreezerController,
-		&s.CGroupMemoryController,
-		&s.CGroupNetPrioController,
-		&s.CGroupPidsController,
-		&s.CGroupSwapAccounting,
-	}
-	for i, flag := range flags {
-		*flag = shared.PathExists("/sys/fs/cgroup/" + cGroups[i].path)
-		if !*flag {
-			logger.Warnf(cGroups[i].warn)
-		}
-	}
-}
-
-func cGroupMissing(name, message string) string {
-	return fmt.Sprintf("Couldn't find the CGroup %s, %s.", name, message)
-}
-
-func cGroupDisabled(name, message string) string {
-	return fmt.Sprintf("CGroup %s is disabled, %s.", name, message)
-}
-
-var cGroups = []struct {
-	path string
-	warn string
-}{
-	{"blkio", cGroupMissing("blkio", "I/O limits will be ignored")},
-	{"blkio/blkio.weight", cGroupMissing("blkio.weight", "I/O weight limits will be ignored")},
-	{"cpu", cGroupMissing("CPU controller", "CPU time limits will be ignored")},
-	{"cpuacct", cGroupMissing("CPUacct controller", "CPU accounting will not be available")},
-	{"cpuset", cGroupMissing("CPUset controller", "CPU pinning will be ignored")},
-	{"devices", cGroupMissing("devices controller", "device access control won't work")},
-	{"freezer", cGroupMissing("freezer controller", "pausing/resuming containers won't work")},
-	{"memory", cGroupMissing("memory controller", "memory limits will be ignored")},
-	{"net_prio", cGroupMissing("network class controller", "network limits will be ignored")},
-	{"pids", cGroupMissing("pids controller", "process limits will be ignored")},
-	{"memory/memory.memsw.limit_in_bytes", cGroupDisabled("memory swap accounting", "swap limits will be ignored")},
-}
diff --git a/lxd/sys/os.go b/lxd/sys/os.go
index feb5c8d184..4c7af7b6c8 100644
--- a/lxd/sys/os.go
+++ b/lxd/sys/os.go
@@ -8,6 +8,7 @@ import (
 
 	log "github.com/lxc/lxd/shared/log15"
 
+	"github.com/lxc/lxd/lxd/cgroup"
 	"github.com/lxc/lxd/lxd/util"
 	"github.com/lxc/lxd/shared"
 	"github.com/lxc/lxd/shared/idmap"
@@ -58,17 +59,7 @@ type OS struct {
 	AppArmorStacking  bool
 
 	// Cgroup features
-	CGroupBlkioController       bool
-	CGroupBlkioWeightController bool
-	CGroupCPUacctController     bool
-	CGroupCPUController         bool
-	CGroupCPUsetController      bool
-	CGroupDevicesController     bool
-	CGroupFreezerController     bool
-	CGroupMemoryController      bool
-	CGroupNetPrioController     bool
-	CGroupPidsController        bool
-	CGroupSwapAccounting        bool
+	CGInfo cgroup.Info
 
 	// Kernel features
 	NetnsGetifaddrs         bool
@@ -130,7 +121,7 @@ func (s *OS) Init() error {
 	s.RunningInUserNS = shared.RunningInUserNS()
 
 	s.initAppArmor()
-	s.initCGroup()
+	s.CGInfo = cgroup.GetInfo()
 
 	return nil
 }


More information about the lxc-devel mailing list