1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include <string.h> 26 #include <math.h> 27 #include <errno.h> 28 #include "cgroupV1Subsystem_linux.hpp" 29 #include "logging/log.hpp" 30 #include "memory/allocation.hpp" 31 #include "runtime/globals.hpp" 32 #include "runtime/os.hpp" 33 #include "utilities/globalDefinitions.hpp" 34 35 /* 36 * Set directory to subsystem specific files based 37 * on the contents of the mountinfo and cgroup files. 38 */ 39 void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { 40 char buf[MAXPATHLEN+1]; 41 if (_root != NULL && cgroup_path != NULL) { 42 if (strcmp(_root, "/") == 0) { 43 int buflen; 44 strncpy(buf, _mount_point, MAXPATHLEN); 45 buf[MAXPATHLEN-1] = '\0'; 46 if (strcmp(cgroup_path,"/") != 0) { 47 buflen = strlen(buf); 48 if ((buflen + strlen(cgroup_path)) > (MAXPATHLEN-1)) { 49 return; 50 } 51 strncat(buf, cgroup_path, MAXPATHLEN-buflen); 52 buf[MAXPATHLEN-1] = '\0'; 53 } 54 _path = os::strdup(buf); 55 } else { 56 if (strcmp(_root, cgroup_path) == 0) { 57 strncpy(buf, _mount_point, MAXPATHLEN); 58 buf[MAXPATHLEN-1] = '\0'; 59 _path = os::strdup(buf); 60 } else { 61 char *p = strstr(cgroup_path, _root); 62 if (p != NULL && p == _root) { 63 if (strlen(cgroup_path) > strlen(_root)) { 64 int buflen; 65 strncpy(buf, _mount_point, MAXPATHLEN); 66 buf[MAXPATHLEN-1] = '\0'; 67 buflen = strlen(buf); 68 if ((buflen + strlen(cgroup_path) - strlen(_root)) > (MAXPATHLEN-1)) { 69 return; 70 } 71 strncat(buf, cgroup_path + strlen(_root), MAXPATHLEN-buflen); 72 buf[MAXPATHLEN-1] = '\0'; 73 _path = os::strdup(buf); 74 } 75 } 76 } 77 } 78 } 79 } 80 81 /* uses_mem_hierarchy 82 * 83 * Return whether or not hierarchical cgroup accounting is being 84 * done. 85 * 86 * return: 87 * A number > 0 if true, or 88 * OSCONTAINER_ERROR for not supported 89 */ 90 jlong CgroupV1MemoryController::uses_mem_hierarchy() { 91 GET_CONTAINER_INFO(jlong, this, "/memory.use_hierarchy", 92 "Use Hierarchy is: " JLONG_FORMAT, JLONG_FORMAT, use_hierarchy); 93 return use_hierarchy; 94 } 95 96 void CgroupV1MemoryController::set_subsystem_path(char *cgroup_path) { 97 CgroupV1Controller::set_subsystem_path(cgroup_path); 98 jlong hierarchy = uses_mem_hierarchy(); 99 if (hierarchy > 0) { 100 set_hierarchical(true); 101 } 102 } 103 104 jlong CgroupV1Subsystem::read_memory_limit_in_bytes() { 105 GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.limit_in_bytes", 106 "Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, memlimit); 107 108 if (memlimit >= _unlimited_memory) { 109 log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited"); 110 CgroupV1MemoryController* mem_controller = reinterpret_cast<CgroupV1MemoryController*>(_memory->controller()); 111 if (mem_controller->is_hierarchical()) { 112 const char* matchline = "hierarchical_memory_limit"; 113 const char* format = "%s " JULONG_FORMAT; 114 GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchline, 115 "Hierarchical Memory Limit is: " JULONG_FORMAT, format, hier_memlimit) 116 if (hier_memlimit >= _unlimited_memory) { 117 log_trace(os, container)("Hierarchical Memory Limit is: Unlimited"); 118 } else { 119 return (jlong)hier_memlimit; 120 } 121 } 122 return (jlong)-1; 123 } 124 else { 125 return (jlong)memlimit; 126 } 127 } 128 129 jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() { 130 GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.memsw.limit_in_bytes", 131 "Memory and Swap Limit is: " JULONG_FORMAT, JULONG_FORMAT, memswlimit); 132 if (memswlimit >= _unlimited_memory) { 133 log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited"); 134 CgroupV1MemoryController* mem_controller = reinterpret_cast<CgroupV1MemoryController*>(_memory->controller()); 135 if (mem_controller->is_hierarchical()) { 136 const char* matchline = "hierarchical_memsw_limit"; 137 const char* format = "%s " JULONG_FORMAT; 138 GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchline, 139 "Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, format, hier_memlimit) 140 if (hier_memlimit >= _unlimited_memory) { 141 log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited"); 142 } else { 143 return (jlong)hier_memlimit; 144 } 145 } 146 return (jlong)-1; 147 } else { 148 return (jlong)memswlimit; 149 } 150 } 151 152 jlong CgroupV1Subsystem::memory_soft_limit_in_bytes() { 153 GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.soft_limit_in_bytes", 154 "Memory Soft Limit is: " JULONG_FORMAT, JULONG_FORMAT, memsoftlimit); 155 if (memsoftlimit >= _unlimited_memory) { 156 log_trace(os, container)("Memory Soft Limit is: Unlimited"); 157 return (jlong)-1; 158 } else { 159 return (jlong)memsoftlimit; 160 } 161 } 162 163 /* memory_usage_in_bytes 164 * 165 * Return the amount of used memory for this process. 166 * 167 * return: 168 * memory usage in bytes or 169 * -1 for unlimited 170 * OSCONTAINER_ERROR for not supported 171 */ 172 jlong CgroupV1Subsystem::memory_usage_in_bytes() { 173 GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.usage_in_bytes", 174 "Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memusage); 175 return memusage; 176 } 177 178 /* memory_max_usage_in_bytes 179 * 180 * Return the maximum amount of used memory for this process. 181 * 182 * return: 183 * max memory usage in bytes or 184 * OSCONTAINER_ERROR for not supported 185 */ 186 jlong CgroupV1Subsystem::memory_max_usage_in_bytes() { 187 GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.max_usage_in_bytes", 188 "Maximum Memory Usage is: " JLONG_FORMAT, JLONG_FORMAT, memmaxusage); 189 return memmaxusage; 190 } 191 192 char * CgroupV1Subsystem::cpu_cpuset_cpus() { 193 GET_CONTAINER_INFO_CPTR(cptr, _cpuset, "/cpuset.cpus", 194 "cpuset.cpus is: %s", "%1023s", cpus, 1024); 195 return os::strdup(cpus); 196 } 197 198 char * CgroupV1Subsystem::cpu_cpuset_memory_nodes() { 199 GET_CONTAINER_INFO_CPTR(cptr, _cpuset, "/cpuset.mems", 200 "cpuset.mems is: %s", "%1023s", mems, 1024); 201 return os::strdup(mems); 202 } 203 204 /* cpu_quota 205 * 206 * Return the number of milliseconds per period 207 * process is guaranteed to run. 208 * 209 * return: 210 * quota time in milliseconds 211 * -1 for no quota 212 * OSCONTAINER_ERROR for not supported 213 */ 214 int CgroupV1Subsystem::cpu_quota() { 215 GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.cfs_quota_us", 216 "CPU Quota is: %d", "%d", quota); 217 return quota; 218 } 219 220 int CgroupV1Subsystem::cpu_period() { 221 GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.cfs_period_us", 222 "CPU Period is: %d", "%d", period); 223 return period; 224 } 225 226 /* cpu_shares 227 * 228 * Return the amount of cpu shares available to the process 229 * 230 * return: 231 * Share number (typically a number relative to 1024) 232 * (2048 typically expresses 2 CPUs worth of processing) 233 * -1 for no share setup 234 * OSCONTAINER_ERROR for not supported 235 */ 236 int CgroupV1Subsystem::cpu_shares() { 237 GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.shares", 238 "CPU Shares is: %d", "%d", shares); 239 // Convert 1024 to no shares setup 240 if (shares == 1024) return -1; 241 242 return shares; 243 }