github.com/valexz/goofys@v0.24.0/internal/cgroup.go (about) 1 // Copyright 2019 Ka-Hing Cheung 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package internal 16 17 import ( 18 "errors" 19 "io/ioutil" 20 "os" 21 "path/filepath" 22 "strconv" 23 "strings" 24 ) 25 26 const CGROUP_PATH = "/proc/self/cgroup" 27 const CGROUP_FOLDER_PREFIX = "/sys/fs/cgroup/memory" 28 const MEM_LIMIT_FILE_SUFFIX = "/memory.limit_in_bytes" 29 const MEM_USAGE_FILE_SUFFIX = "/memory.usage_in_bytes" 30 31 func getCgroupAvailableMem() (retVal uint64, err error) { 32 //get the memory cgroup for self and send limit - usage for the cgroup 33 34 data, err := ioutil.ReadFile(CGROUP_PATH) 35 if err != nil { 36 log.Debugf("Unable to read file %s error: %s", CGROUP_PATH, err) 37 return 0, err 38 } 39 40 path, err := getMemoryCgroupPath(string(data)) 41 if err != nil { 42 log.Debugf("Unable to get memory cgroup path") 43 return 0, err 44 } 45 46 // newer version of docker mounts the cgroup memory limit/usage files directly under 47 // /sys/fs/cgroup/memory/ rather than /sys/fs/cgroup/memory/docker/$container_id/ 48 if _, err := os.Stat(filepath.Join(CGROUP_FOLDER_PREFIX, path)); os.IsExist(err) { 49 path = filepath.Join(CGROUP_FOLDER_PREFIX, path) 50 } else { 51 path = filepath.Join(CGROUP_FOLDER_PREFIX) 52 } 53 54 log.Debugf("the memory cgroup path for the current process is %v", path) 55 56 mem_limit, err := readFileAndGetValue(filepath.Join(path, MEM_LIMIT_FILE_SUFFIX)) 57 if err != nil { 58 log.Debugf("Unable to get memory limit from cgroup error: %v", err) 59 return 0, err 60 } 61 62 mem_usage, err := readFileAndGetValue(filepath.Join(path, MEM_USAGE_FILE_SUFFIX)) 63 if err != nil { 64 log.Debugf("Unable to get memory usage from cgroup error: %v", err) 65 return 0, err 66 } 67 68 return (mem_limit - mem_usage), nil 69 } 70 71 func getMemoryCgroupPath(data string) (string, error) { 72 73 /* 74 Content of /proc/self/cgroup 75 76 11:hugetlb:/ 77 10:memory:/user.slice 78 9:cpuset:/ 79 8:blkio:/user.slice 80 7:perf_event:/ 81 6:net_prio,net_cls:/ 82 5:cpuacct,cpu:/user.slice 83 4:devices:/user.slice 84 3:freezer:/ 85 2:pids:/ 86 1:name=systemd:/user.slice/user-1000.slice/session-1759.scope 87 */ 88 89 dataArray := strings.Split(data, "\n") 90 for index := range dataArray { 91 kvArray := strings.Split(dataArray[index], ":") 92 if len(kvArray) == 3 { 93 if kvArray[1] == "memory" { 94 return kvArray[2], nil 95 } 96 } 97 } 98 99 return "", errors.New("Unable to get memory cgroup path") 100 } 101 102 func readFileAndGetValue(path string) (uint64, error) { 103 data, err := ioutil.ReadFile(path) 104 if err != nil { 105 log.Debugf("Unable to read file %v error: %v", path, err) 106 return 0, err 107 } 108 109 return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64) 110 }