@@ -103,8 +103,8 @@ func getMemoryLimitV2(chs []cgroupHierarchy, mis []mountInfo) (uint64, error) {
103103 return 0 , err
104104 }
105105
106- // retrieve the memory limit from the memory.max file
107- return readMemoryLimitV2FromPath ( filepath . Join ( cgroupPath , "memory.max" ) )
106+ // retrieve the memory limit from the memory.max recursively.
107+ return walkCgroupV2Hierarchy ( cgroupPath , mountPoint )
108108}
109109
110110// readMemoryLimitV2FromPath reads the memory limit for cgroup v2 from the given path.
@@ -131,6 +131,39 @@ func readMemoryLimitV2FromPath(path string) (uint64, error) {
131131 return limit , nil
132132}
133133
134+ // walkCgroupV2Hierarchy walks up the cgroup v2 hierarchy to find the most restrictive memory limit.
135+ func walkCgroupV2Hierarchy (cgroupPath , mountPoint string ) (uint64 , error ) {
136+ var (
137+ found = false
138+ minLimit uint64 = math .MaxUint64
139+ currentPath = cgroupPath
140+ )
141+ for {
142+ limit , err := readMemoryLimitV2FromPath (filepath .Join (currentPath , "memory.max" ))
143+ if err != nil && ! errors .Is (err , ErrNoLimit ) {
144+ return 0 , err
145+ } else if err == nil {
146+ found = true
147+ minLimit = min (minLimit , limit )
148+ }
149+
150+ if currentPath == mountPoint {
151+ break
152+ }
153+
154+ parent := filepath .Dir (currentPath )
155+ if parent == currentPath {
156+ break
157+ }
158+ currentPath = parent
159+ }
160+ if ! found {
161+ return 0 , ErrNoLimit
162+ }
163+
164+ return minLimit , nil
165+ }
166+
134167// getMemoryLimitV1 retrieves the memory limit from the cgroup v1 controller.
135168func getMemoryLimitV1 (chs []cgroupHierarchy , mis []mountInfo ) (uint64 , error ) {
136169 // find the cgroup v1 path for the memory controller.
0 commit comments