Merge pull request #43649 from AkihiroSuda/fix-43646

Fix constant `WARNING: No swap limit support` on cgroup v2 hosts
This commit is contained in:
Sebastiaan van Stijn 2022-05-27 13:25:25 +02:00 committed by GitHub
commit 69adaa894d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 83 additions and 31 deletions

View file

@ -56,12 +56,11 @@ func newV2(options ...Opt) *SysInfo {
}
func getSwapLimitV2() bool {
groups, err := cgroups.ParseCgroupFile("/proc/self/cgroup")
_, g, err := cgroups.ParseCgroupFileUnified("/proc/self/cgroup")
if err != nil {
return false
}
g := groups[""]
if g == "" {
return false
}

View file

@ -17,7 +17,7 @@ require (
github.com/aws/aws-sdk-go v1.31.6
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.3
github.com/containerd/cgroups v1.0.4
github.com/containerd/containerd v1.6.4
github.com/containerd/continuity v0.3.0
github.com/containerd/fifo v1.0.0

View file

@ -209,8 +209,9 @@ github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4S
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/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/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA=
github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA=
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=

View file

@ -26,7 +26,7 @@ uses the v1 implementation of cgroups.
```go
shares := uint64(100)
control, err := cgroups.New(cgroups.V1, cgroups.StaticPath("/test"), &specs.LinuxResources{
CPU: &specs.CPU{
CPU: &specs.LinuxCPU{
Shares: &shares,
},
})

View file

@ -3,19 +3,19 @@
Vagrant.configure("2") do |config|
# Fedora box is used for testing cgroup v2 support
config.vm.box = "fedora/32-cloud-base"
config.vm.box = "fedora/35-cloud-base"
config.vm.provider :virtualbox do |v|
v.memory = 2048
v.memory = 4096
v.cpus = 2
end
config.vm.provider :libvirt do |v|
v.memory = 2048
v.memory = 4096
v.cpus = 2
end
config.vm.provision "shell", inline: <<-SHELL
set -eux -o pipefail
# configuration
GO_VERSION="1.15"
GO_VERSION="1.17.7"
# install gcc and Golang
dnf -y install gcc

View file

@ -261,21 +261,28 @@ func parseKV(raw string) (string, uint64, error) {
// "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.
// The resulting map does not have an element for cgroup v2 unified hierarchy.
// Use ParseCgroupFileUnified to get the unified path.
func ParseCgroupFile(path string) (map[string]string, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
return parseCgroupFromReader(f)
x, _, err := ParseCgroupFileUnified(path)
return x, err
}
func parseCgroupFromReader(r io.Reader) (map[string]string, error) {
// ParseCgroupFileUnified returns legacy subsystem paths as the first value,
// and returns the unified path as the second value.
func ParseCgroupFileUnified(path string) (map[string]string, string, error) {
f, err := os.Open(path)
if err != nil {
return nil, "", err
}
defer f.Close()
return parseCgroupFromReaderUnified(f)
}
func parseCgroupFromReaderUnified(r io.Reader) (map[string]string, string, error) {
var (
cgroups = make(map[string]string)
unified = ""
s = bufio.NewScanner(r)
)
for s.Scan() {
@ -284,18 +291,20 @@ func parseCgroupFromReader(r io.Reader) (map[string]string, error) {
parts = strings.SplitN(text, ":", 3)
)
if len(parts) < 3 {
return nil, fmt.Errorf("invalid cgroup entry: %q", text)
return nil, unified, fmt.Errorf("invalid cgroup entry: %q", text)
}
for _, subs := range strings.Split(parts[1], ",") {
if subs != "" {
if subs == "" {
unified = parts[2]
} else {
cgroups[subs] = parts[2]
}
}
}
if err := s.Err(); err != nil {
return nil, err
return nil, unified, err
}
return cgroups, nil
return cgroups, unified, nil
}
func getCgroupDestination(subsystem string) (string, error) {

View file

@ -240,6 +240,10 @@ func (c *Manager) Controllers() ([]string, error) {
return strings.Fields(string(b)), nil
}
func (c *Manager) Update(resources *Resources) error {
return setResources(c.path, resources)
}
type ControllerToggle int
const (
@ -701,12 +705,39 @@ func setDevices(path string, devices []specs.LinuxDeviceCgroup) error {
return nil
}
// getSystemdFullPath returns the full systemd path when creating a systemd slice group.
// the reason this is necessary is because the "-" character has a special meaning in
// systemd slice. For example, when creating a slice called "my-group-112233.slice",
// systemd will create a hierarchy like this:
// /sys/fs/cgroup/my.slice/my-group.slice/my-group-112233.slice
func getSystemdFullPath(slice, group string) string {
return filepath.Join(defaultCgroup2Path, dashesToPath(slice), dashesToPath(group))
}
// dashesToPath converts a slice name with dashes to it's corresponding systemd filesystem path.
func dashesToPath(in string) string {
path := ""
if strings.HasSuffix(in, ".slice") && strings.Contains(in, "-") {
parts := strings.Split(in, "-")
for i := range parts {
s := strings.Join(parts[0:i+1], "-")
if !strings.HasSuffix(s, ".slice") {
s += ".slice"
}
path = filepath.Join(path, s)
}
} else {
path = filepath.Join(path, in)
}
return path
}
func NewSystemd(slice, group string, pid int, resources *Resources) (*Manager, error) {
if slice == "" {
slice = defaultSlice
}
ctx := context.TODO()
path := filepath.Join(defaultCgroup2Path, slice, group)
path := getSystemdFullPath(slice, group)
conn, err := systemdDbus.NewWithContext(ctx)
if err != nil {
return &Manager{}, err
@ -734,12 +765,17 @@ func NewSystemd(slice, group string, pid int, resources *Resources) (*Manager, e
properties = append(properties, newSystemdProperty("PIDs", []uint32{uint32(pid)}))
}
if resources.Memory != nil && *resources.Memory.Max != 0 {
if resources.Memory != nil && resources.Memory.Min != nil && *resources.Memory.Min != 0 {
properties = append(properties,
newSystemdProperty("MemoryMin", uint64(*resources.Memory.Min)))
}
if resources.Memory != nil && resources.Memory.Max != nil && *resources.Memory.Max != 0 {
properties = append(properties,
newSystemdProperty("MemoryMax", uint64(*resources.Memory.Max)))
}
if resources.CPU != nil && *resources.CPU.Weight != 0 {
if resources.CPU != nil && resources.CPU.Weight != nil && *resources.CPU.Weight != 0 {
properties = append(properties,
newSystemdProperty("CPUWeight", *resources.CPU.Weight))
}
@ -796,9 +832,9 @@ func LoadSystemd(slice, group string) (*Manager, error) {
if slice == "" {
slice = defaultSlice
}
group = filepath.Join(defaultCgroup2Path, slice, group)
path := getSystemdFullPath(slice, group)
return &Manager{
path: group,
path: path,
}, nil
}

View file

@ -18,6 +18,7 @@ package v2
type Memory struct {
Swap *int64
Min *int64
Max *int64
Low *int64
High *int64
@ -30,6 +31,12 @@ func (r *Memory) Values() (o []Value) {
value: *r.Swap,
})
}
if r.Min != nil {
o = append(o, Value{
filename: "memory.min",
value: *r.Min,
})
}
if r.Max != nil {
o = append(o, Value{
filename: "memory.max",

View file

@ -227,7 +227,7 @@ func ToResources(spec *specs.LinuxResources) *Resources {
if i := spec.Rdma; i != nil {
resources.RDMA = &RDMA{}
for device, value := range spec.Rdma {
if device != "" && (value.HcaHandles != nil || value.HcaObjects != nil) {
if device != "" && (value.HcaHandles != nil && value.HcaObjects != nil) {
resources.RDMA.Limit = append(resources.RDMA.Limit, RDMAEntry{
Device: device,
HcaHandles: *value.HcaHandles,

4
vendor/modules.txt vendored
View file

@ -144,8 +144,8 @@ github.com/cloudflare/cfssl/signer/local
# github.com/container-storage-interface/spec v1.5.0
## explicit; go 1.16
github.com/container-storage-interface/spec/lib/go/csi
# github.com/containerd/cgroups v1.0.3
## explicit; go 1.16
# github.com/containerd/cgroups v1.0.4
## explicit; go 1.17
github.com/containerd/cgroups
github.com/containerd/cgroups/stats/v1
github.com/containerd/cgroups/v2