cgroups.go (2035B)
1 //go:build linux 2 // +build linux 3 4 package memlimit 5 6 import ( 7 "path/filepath" 8 9 "github.com/containerd/cgroups/v3" 10 "github.com/containerd/cgroups/v3/cgroup1" 11 "github.com/containerd/cgroups/v3/cgroup2" 12 ) 13 14 const ( 15 cgroupMountPoint = "/sys/fs/cgroup" 16 ) 17 18 // FromCgroup returns the memory limit based on the cgroups version on this system. 19 func FromCgroup() (uint64, error) { 20 switch cgroups.Mode() { 21 case cgroups.Legacy: 22 return FromCgroupV1() 23 case cgroups.Hybrid: 24 return fromCgroupHybrid() 25 case cgroups.Unified: 26 return FromCgroupV2() 27 } 28 return 0, ErrNoCgroup 29 } 30 31 // FromCgroupV1 returns the memory limit from the cgroup v1. 32 func FromCgroupV1() (uint64, error) { 33 cg, err := cgroup1.Load(cgroup1.RootPath, cgroup1.WithHiearchy( 34 cgroup1.SingleSubsystem(cgroup1.Default, cgroup1.Memory), 35 )) 36 if err != nil { 37 return 0, err 38 } 39 40 metrics, err := cg.Stat(cgroup1.IgnoreNotExist) 41 if err != nil { 42 return 0, err 43 } 44 45 if limit := metrics.GetMemory().GetHierarchicalMemoryLimit(); limit != 0 { 46 return limit, nil 47 } 48 49 return 0, ErrNoLimit 50 } 51 52 // fromCgroupHybrid returns the memory limit from the cgroup v1 or v2. 53 // It checks the cgroup v2 first, and if it fails, it falls back to cgroup v1. 54 // TODO: make this function public in the next minor version. 55 func fromCgroupHybrid() (uint64, error) { 56 limit, err := fromCgroupV2(filepath.Join(cgroupMountPoint, "unified")) 57 if err == nil { 58 return limit, nil 59 } else if err != ErrNoLimit { 60 return 0, err 61 } 62 63 return FromCgroupV1() 64 } 65 66 // FromCgroupV2 returns the memory limit from the cgroup v2. 67 func FromCgroupV2() (uint64, error) { 68 return fromCgroupV2(cgroupMountPoint) 69 } 70 71 func fromCgroupV2(mountPoint string) (uint64, error) { 72 path, err := cgroup2.NestedGroupPath("") 73 if err != nil { 74 return 0, err 75 } 76 77 m, err := cgroup2.Load(path, cgroup2.WithMountpoint(mountPoint)) 78 if err != nil { 79 return 0, err 80 } 81 82 stats, err := m.Stat() 83 if err != nil { 84 return 0, err 85 } 86 87 if limit := stats.GetMemory().GetUsageLimit(); limit != 0 { 88 return limit, nil 89 } 90 91 return 0, ErrNoLimit 92 }