Path: blob/master/src/hotspot/os/linux/cgroupSubsystem_linux.cpp
64440 views
/*1* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include <string.h>25#include <math.h>26#include <errno.h>27#include "cgroupSubsystem_linux.hpp"28#include "cgroupV1Subsystem_linux.hpp"29#include "cgroupV2Subsystem_linux.hpp"30#include "logging/log.hpp"31#include "memory/allocation.hpp"32#include "runtime/globals.hpp"33#include "runtime/os.hpp"34#include "utilities/globalDefinitions.hpp"3536// controller names have to match the *_IDX indices37static const char* cg_controller_name[] = { "cpu", "cpuset", "cpuacct", "memory", "pids" };3839CgroupSubsystem* CgroupSubsystemFactory::create() {40CgroupV1MemoryController* memory = NULL;41CgroupV1Controller* cpuset = NULL;42CgroupV1Controller* cpu = NULL;43CgroupV1Controller* cpuacct = NULL;44CgroupV1Controller* pids = NULL;45CgroupInfo cg_infos[CG_INFO_LENGTH];46u1 cg_type_flags = INVALID_CGROUPS_GENERIC;47const char* proc_cgroups = "/proc/cgroups";48const char* proc_self_cgroup = "/proc/self/cgroup";49const char* proc_self_mountinfo = "/proc/self/mountinfo";5051bool valid_cgroup = determine_type(cg_infos, proc_cgroups, proc_self_cgroup, proc_self_mountinfo, &cg_type_flags);5253if (!valid_cgroup) {54// Could not detect cgroup type55return NULL;56}57assert(is_valid_cgroup(&cg_type_flags), "Expected valid cgroup type");5859if (is_cgroup_v2(&cg_type_flags)) {60// Cgroups v2 case, we have all the info we need.61// Construct the subsystem, free resources and return62// Note: any index in cg_infos will do as the path is the same for63// all controllers.64CgroupController* unified = new CgroupV2Controller(cg_infos[MEMORY_IDX]._mount_path, cg_infos[MEMORY_IDX]._cgroup_path);65log_debug(os, container)("Detected cgroups v2 unified hierarchy");66cleanup(cg_infos);67return new CgroupV2Subsystem(unified);68}6970/*71* Cgroup v1 case:72*73* Use info gathered previously from /proc/self/cgroup74* and map host mount point to75* local one via /proc/self/mountinfo content above76*77* Docker example:78* 5:memory:/docker/6558aed8fc662b194323ceab5b964f69cf36b3e8af877a14b80256e93aecb04479*80* Host example:81* 5:memory:/user.slice82*83* Construct a path to the process specific memory and cpuset84* cgroup directory.85*86* For a container running under Docker from memory example above87* the paths would be:88*89* /sys/fs/cgroup/memory90*91* For a Host from memory example above the path would be:92*93* /sys/fs/cgroup/memory/user.slice94*95*/96assert(is_cgroup_v1(&cg_type_flags), "Cgroup v1 expected");97for (int i = 0; i < CG_INFO_LENGTH; i++) {98CgroupInfo info = cg_infos[i];99if (info._data_complete) { // pids controller might have incomplete data100if (strcmp(info._name, "memory") == 0) {101memory = new CgroupV1MemoryController(info._root_mount_path, info._mount_path);102memory->set_subsystem_path(info._cgroup_path);103} else if (strcmp(info._name, "cpuset") == 0) {104cpuset = new CgroupV1Controller(info._root_mount_path, info._mount_path);105cpuset->set_subsystem_path(info._cgroup_path);106} else if (strcmp(info._name, "cpu") == 0) {107cpu = new CgroupV1Controller(info._root_mount_path, info._mount_path);108cpu->set_subsystem_path(info._cgroup_path);109} else if (strcmp(info._name, "cpuacct") == 0) {110cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path);111cpuacct->set_subsystem_path(info._cgroup_path);112} else if (strcmp(info._name, "pids") == 0) {113pids = new CgroupV1Controller(info._root_mount_path, info._mount_path);114pids->set_subsystem_path(info._cgroup_path);115}116} else {117log_debug(os, container)("CgroupInfo for %s not complete", cg_controller_name[i]);118}119}120cleanup(cg_infos);121return new CgroupV1Subsystem(cpuset, cpu, cpuacct, pids, memory);122}123124bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos,125const char* proc_cgroups,126const char* proc_self_cgroup,127const char* proc_self_mountinfo,128u1* flags) {129FILE *mntinfo = NULL;130FILE *cgroups = NULL;131FILE *cgroup = NULL;132char buf[MAXPATHLEN+1];133char *p;134bool is_cgroupsV2;135// true iff all required controllers, memory, cpu, cpuset, cpuacct are enabled136// at the kernel level.137// pids might not be enabled on older Linux distros (SLES 12.1, RHEL 7.1)138bool all_required_controllers_enabled;139140/*141* Read /proc/cgroups so as to be able to distinguish cgroups v2 vs cgroups v1.142*143* For cgroups v1 hierarchy (hybrid or legacy), cpu, cpuacct, cpuset, memory controllers144* must have non-zero for the hierarchy ID field and relevant controllers mounted.145* Conversely, for cgroups v2 (unified hierarchy), cpu, cpuacct, cpuset, memory146* controllers must have hierarchy ID 0 and the unified controller mounted.147*/148cgroups = fopen(proc_cgroups, "r");149if (cgroups == NULL) {150log_debug(os, container)("Can't open %s, %s", proc_cgroups, os::strerror(errno));151*flags = INVALID_CGROUPS_GENERIC;152return false;153}154155while ((p = fgets(buf, MAXPATHLEN, cgroups)) != NULL) {156char name[MAXPATHLEN+1];157int hierarchy_id;158int enabled;159160// Format of /proc/cgroups documented via man 7 cgroups161if (sscanf(p, "%s %d %*d %d", name, &hierarchy_id, &enabled) != 3) {162continue;163}164if (strcmp(name, "memory") == 0) {165cg_infos[MEMORY_IDX]._name = os::strdup(name);166cg_infos[MEMORY_IDX]._hierarchy_id = hierarchy_id;167cg_infos[MEMORY_IDX]._enabled = (enabled == 1);168} else if (strcmp(name, "cpuset") == 0) {169cg_infos[CPUSET_IDX]._name = os::strdup(name);170cg_infos[CPUSET_IDX]._hierarchy_id = hierarchy_id;171cg_infos[CPUSET_IDX]._enabled = (enabled == 1);172} else if (strcmp(name, "cpu") == 0) {173cg_infos[CPU_IDX]._name = os::strdup(name);174cg_infos[CPU_IDX]._hierarchy_id = hierarchy_id;175cg_infos[CPU_IDX]._enabled = (enabled == 1);176} else if (strcmp(name, "cpuacct") == 0) {177cg_infos[CPUACCT_IDX]._name = os::strdup(name);178cg_infos[CPUACCT_IDX]._hierarchy_id = hierarchy_id;179cg_infos[CPUACCT_IDX]._enabled = (enabled == 1);180} else if (strcmp(name, "pids") == 0) {181log_debug(os, container)("Detected optional pids controller entry in %s", proc_cgroups);182cg_infos[PIDS_IDX]._name = os::strdup(name);183cg_infos[PIDS_IDX]._hierarchy_id = hierarchy_id;184cg_infos[PIDS_IDX]._enabled = (enabled == 1);185}186}187fclose(cgroups);188189is_cgroupsV2 = true;190all_required_controllers_enabled = true;191for (int i = 0; i < CG_INFO_LENGTH; i++) {192// pids controller is optional. All other controllers are required193if (i != PIDS_IDX) {194is_cgroupsV2 = is_cgroupsV2 && cg_infos[i]._hierarchy_id == 0;195all_required_controllers_enabled = all_required_controllers_enabled && cg_infos[i]._enabled;196}197if (log_is_enabled(Debug, os, container) && !cg_infos[i]._enabled) {198log_debug(os, container)("controller %s is not enabled\n", cg_controller_name[i]);199}200}201202if (!all_required_controllers_enabled) {203// one or more required controllers disabled, disable container support204log_debug(os, container)("One or more required controllers disabled at kernel level.");205cleanup(cg_infos);206*flags = INVALID_CGROUPS_GENERIC;207return false;208}209210/*211* Read /proc/self/cgroup and determine:212* - the cgroup path for cgroups v2 or213* - on a cgroups v1 system, collect info for mapping214* the host mount point to the local one via /proc/self/mountinfo below.215*/216cgroup = fopen(proc_self_cgroup, "r");217if (cgroup == NULL) {218log_debug(os, container)("Can't open %s, %s",219proc_self_cgroup, os::strerror(errno));220cleanup(cg_infos);221*flags = INVALID_CGROUPS_GENERIC;222return false;223}224225while ((p = fgets(buf, MAXPATHLEN, cgroup)) != NULL) {226char *controllers;227char *token;228char *hierarchy_id_str;229int hierarchy_id;230char *cgroup_path;231232hierarchy_id_str = strsep(&p, ":");233hierarchy_id = atoi(hierarchy_id_str);234/* Get controllers and base */235controllers = strsep(&p, ":");236cgroup_path = strsep(&p, "\n");237238if (controllers == NULL) {239continue;240}241242while (!is_cgroupsV2 && (token = strsep(&controllers, ",")) != NULL) {243if (strcmp(token, "memory") == 0) {244assert(hierarchy_id == cg_infos[MEMORY_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for memory");245cg_infos[MEMORY_IDX]._cgroup_path = os::strdup(cgroup_path);246} else if (strcmp(token, "cpuset") == 0) {247assert(hierarchy_id == cg_infos[CPUSET_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpuset");248cg_infos[CPUSET_IDX]._cgroup_path = os::strdup(cgroup_path);249} else if (strcmp(token, "cpu") == 0) {250assert(hierarchy_id == cg_infos[CPU_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpu");251cg_infos[CPU_IDX]._cgroup_path = os::strdup(cgroup_path);252} else if (strcmp(token, "cpuacct") == 0) {253assert(hierarchy_id == cg_infos[CPUACCT_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpuacc");254cg_infos[CPUACCT_IDX]._cgroup_path = os::strdup(cgroup_path);255} else if (strcmp(token, "pids") == 0) {256assert(hierarchy_id == cg_infos[PIDS_IDX]._hierarchy_id, "/proc/cgroups (%d) and /proc/self/cgroup (%d) hierarchy mismatch for pids",257cg_infos[PIDS_IDX]._hierarchy_id, hierarchy_id);258cg_infos[PIDS_IDX]._cgroup_path = os::strdup(cgroup_path);259}260}261if (is_cgroupsV2) {262// On some systems we have mixed cgroups v1 and cgroups v2 controllers (e.g. freezer on cg1 and263// all relevant controllers on cg2). Only set the cgroup path when we see a hierarchy id of 0.264if (hierarchy_id != 0) {265continue;266}267for (int i = 0; i < CG_INFO_LENGTH; i++) {268assert(cg_infos[i]._cgroup_path == NULL, "cgroup path must only be set once");269cg_infos[i]._cgroup_path = os::strdup(cgroup_path);270}271}272}273fclose(cgroup);274275// Find various mount points by reading /proc/self/mountinfo276// mountinfo format is documented at https://www.kernel.org/doc/Documentation/filesystems/proc.txt277mntinfo = fopen(proc_self_mountinfo, "r");278if (mntinfo == NULL) {279log_debug(os, container)("Can't open %s, %s",280proc_self_mountinfo, os::strerror(errno));281cleanup(cg_infos);282*flags = INVALID_CGROUPS_GENERIC;283return false;284}285286bool cgroupv2_mount_point_found = false;287bool any_cgroup_mounts_found = false;288while ((p = fgets(buf, MAXPATHLEN, mntinfo)) != NULL) {289char tmp_mount_point[MAXPATHLEN+1];290char tmp_fs_type[MAXPATHLEN+1];291char tmproot[MAXPATHLEN+1];292char tmpmount[MAXPATHLEN+1];293char tmpcgroups[MAXPATHLEN+1];294char *cptr = tmpcgroups;295char *token;296297// Cgroup v2 relevant info. We only look for the _mount_path iff is_cgroupsV2 so298// as to avoid memory stomping of the _mount_path pointer later on in the cgroup v1299// block in the hybrid case.300//301if (is_cgroupsV2 && sscanf(p, "%*d %*d %*d:%*d %*s %s %*[^-]- %s %*s %*s", tmp_mount_point, tmp_fs_type) == 2) {302// we likely have an early match return (e.g. cgroup fs match), be sure we have cgroup2 as fstype303if (!cgroupv2_mount_point_found && strcmp("cgroup2", tmp_fs_type) == 0) {304cgroupv2_mount_point_found = true;305any_cgroup_mounts_found = true;306for (int i = 0; i < CG_INFO_LENGTH; i++) {307assert(cg_infos[i]._mount_path == NULL, "_mount_path memory stomping");308cg_infos[i]._mount_path = os::strdup(tmp_mount_point);309}310}311}312313/* Cgroup v1 relevant info314*315* Find the cgroup mount point for memory, cpuset, cpu, cpuacct, pids316*317* Example for docker:318* 219 214 0:29 /docker/7208cebd00fa5f2e342b1094f7bed87fa25661471a4637118e65f1c995be8a34 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,memory319*320* Example for host:321* 34 28 0:29 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,memory322*323* 44 31 0:39 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:23 - cgroup cgroup rw,pids324*/325if (sscanf(p, "%*d %*d %*d:%*d %s %s %*[^-]- %s %*s %s", tmproot, tmpmount, tmp_fs_type, tmpcgroups) == 4) {326if (strcmp("cgroup", tmp_fs_type) != 0) {327// Skip cgroup2 fs lines on hybrid or unified hierarchy.328continue;329}330while ((token = strsep(&cptr, ",")) != NULL) {331if (strcmp(token, "memory") == 0) {332any_cgroup_mounts_found = true;333assert(cg_infos[MEMORY_IDX]._mount_path == NULL, "stomping of _mount_path");334cg_infos[MEMORY_IDX]._mount_path = os::strdup(tmpmount);335cg_infos[MEMORY_IDX]._root_mount_path = os::strdup(tmproot);336cg_infos[MEMORY_IDX]._data_complete = true;337} else if (strcmp(token, "cpuset") == 0) {338any_cgroup_mounts_found = true;339if (cg_infos[CPUSET_IDX]._mount_path != NULL) {340// On some systems duplicate cpuset controllers get mounted in addition to341// the main cgroup controllers most likely under /sys/fs/cgroup. In that342// case pick the one under /sys/fs/cgroup and discard others.343if (strstr(cg_infos[CPUSET_IDX]._mount_path, "/sys/fs/cgroup") != cg_infos[CPUSET_IDX]._mount_path) {344log_warning(os, container)("Duplicate cpuset controllers detected. Picking %s, skipping %s.",345tmpmount, cg_infos[CPUSET_IDX]._mount_path);346os::free(cg_infos[CPUSET_IDX]._mount_path);347cg_infos[CPUSET_IDX]._mount_path = os::strdup(tmpmount);348} else {349log_warning(os, container)("Duplicate cpuset controllers detected. Picking %s, skipping %s.",350cg_infos[CPUSET_IDX]._mount_path, tmpmount);351}352} else {353cg_infos[CPUSET_IDX]._mount_path = os::strdup(tmpmount);354}355cg_infos[CPUSET_IDX]._root_mount_path = os::strdup(tmproot);356cg_infos[CPUSET_IDX]._data_complete = true;357} else if (strcmp(token, "cpu") == 0) {358any_cgroup_mounts_found = true;359assert(cg_infos[CPU_IDX]._mount_path == NULL, "stomping of _mount_path");360cg_infos[CPU_IDX]._mount_path = os::strdup(tmpmount);361cg_infos[CPU_IDX]._root_mount_path = os::strdup(tmproot);362cg_infos[CPU_IDX]._data_complete = true;363} else if (strcmp(token, "cpuacct") == 0) {364any_cgroup_mounts_found = true;365assert(cg_infos[CPUACCT_IDX]._mount_path == NULL, "stomping of _mount_path");366cg_infos[CPUACCT_IDX]._mount_path = os::strdup(tmpmount);367cg_infos[CPUACCT_IDX]._root_mount_path = os::strdup(tmproot);368cg_infos[CPUACCT_IDX]._data_complete = true;369} else if (strcmp(token, "pids") == 0) {370any_cgroup_mounts_found = true;371assert(cg_infos[PIDS_IDX]._mount_path == NULL, "stomping of _mount_path");372cg_infos[PIDS_IDX]._mount_path = os::strdup(tmpmount);373cg_infos[PIDS_IDX]._root_mount_path = os::strdup(tmproot);374cg_infos[PIDS_IDX]._data_complete = true;375}376}377}378}379fclose(mntinfo);380381// Neither cgroup2 nor cgroup filesystems mounted via /proc/self/mountinfo382// No point in continuing.383if (!any_cgroup_mounts_found) {384log_trace(os, container)("No relevant cgroup controllers mounted.");385cleanup(cg_infos);386*flags = INVALID_CGROUPS_NO_MOUNT;387return false;388}389390if (is_cgroupsV2) {391if (!cgroupv2_mount_point_found) {392log_trace(os, container)("Mount point for cgroupv2 not found in /proc/self/mountinfo");393cleanup(cg_infos);394*flags = INVALID_CGROUPS_V2;395return false;396}397// Cgroups v2 case, we have all the info we need.398*flags = CGROUPS_V2;399return true;400}401402// What follows is cgroups v1403log_debug(os, container)("Detected cgroups hybrid or legacy hierarchy, using cgroups v1 controllers");404405if (!cg_infos[MEMORY_IDX]._data_complete) {406log_debug(os, container)("Required cgroup v1 memory subsystem not found");407cleanup(cg_infos);408*flags = INVALID_CGROUPS_V1;409return false;410}411if (!cg_infos[CPUSET_IDX]._data_complete) {412log_debug(os, container)("Required cgroup v1 cpuset subsystem not found");413cleanup(cg_infos);414*flags = INVALID_CGROUPS_V1;415return false;416}417if (!cg_infos[CPU_IDX]._data_complete) {418log_debug(os, container)("Required cgroup v1 cpu subsystem not found");419cleanup(cg_infos);420*flags = INVALID_CGROUPS_V1;421return false;422}423if (!cg_infos[CPUACCT_IDX]._data_complete) {424log_debug(os, container)("Required cgroup v1 cpuacct subsystem not found");425cleanup(cg_infos);426*flags = INVALID_CGROUPS_V1;427return false;428}429if (log_is_enabled(Debug, os, container) && !cg_infos[PIDS_IDX]._data_complete) {430log_debug(os, container)("Optional cgroup v1 pids subsystem not found");431// keep the other controller info, pids is optional432}433// Cgroups v1 case, we have all the info we need.434*flags = CGROUPS_V1;435return true;436};437438void CgroupSubsystemFactory::cleanup(CgroupInfo* cg_infos) {439assert(cg_infos != NULL, "Invariant");440for (int i = 0; i < CG_INFO_LENGTH; i++) {441os::free(cg_infos[i]._name);442os::free(cg_infos[i]._cgroup_path);443os::free(cg_infos[i]._root_mount_path);444os::free(cg_infos[i]._mount_path);445}446}447448/* active_processor_count449*450* Calculate an appropriate number of active processors for the451* VM to use based on these three inputs.452*453* cpu affinity454* cgroup cpu quota & cpu period455* cgroup cpu shares456*457* Algorithm:458*459* Determine the number of available CPUs from sched_getaffinity460*461* If user specified a quota (quota != -1), calculate the number of462* required CPUs by dividing quota by period.463*464* If shares are in effect (shares != -1), calculate the number465* of CPUs required for the shares by dividing the share value466* by PER_CPU_SHARES.467*468* All results of division are rounded up to the next whole number.469*470* If neither shares or quotas have been specified, return the471* number of active processors in the system.472*473* If both shares and quotas have been specified, the results are474* based on the flag PreferContainerQuotaForCPUCount. If true,475* return the quota value. If false return the smallest value476* between shares or quotas.477*478* If shares and/or quotas have been specified, the resulting number479* returned will never exceed the number of active processors.480*481* return:482* number of CPUs483*/484int CgroupSubsystem::active_processor_count() {485int quota_count = 0, share_count = 0;486int cpu_count, limit_count;487int result;488489// We use a cache with a timeout to avoid performing expensive490// computations in the event this function is called frequently.491// [See 8227006].492CachingCgroupController* contrl = cpu_controller();493CachedMetric* cpu_limit = contrl->metrics_cache();494if (!cpu_limit->should_check_metric()) {495int val = (int)cpu_limit->value();496log_trace(os, container)("CgroupSubsystem::active_processor_count (cached): %d", val);497return val;498}499500cpu_count = limit_count = os::Linux::active_processor_count();501int quota = cpu_quota();502int period = cpu_period();503504// It's not a good idea to use cpu_shares() to limit the number505// of CPUs used by the JVM. See JDK-8281181.506int share = UseContainerCpuShares ? cpu_shares() : -1;507508if (quota > -1 && period > 0) {509quota_count = ceilf((float)quota / (float)period);510log_trace(os, container)("CPU Quota count based on quota/period: %d", quota_count);511}512if (share > -1) {513share_count = ceilf((float)share / (float)PER_CPU_SHARES);514log_trace(os, container)("CPU Share count based on shares: %d", share_count);515}516517// If both shares and quotas are setup results depend518// on flag PreferContainerQuotaForCPUCount.519// If true, limit CPU count to quota520// If false, use minimum of shares and quotas521if (quota_count !=0 && share_count != 0) {522if (PreferContainerQuotaForCPUCount) {523limit_count = quota_count;524} else {525limit_count = MIN2(quota_count, share_count);526}527} else if (quota_count != 0) {528limit_count = quota_count;529} else if (share_count != 0) {530limit_count = share_count;531}532533result = MIN2(cpu_count, limit_count);534log_trace(os, container)("OSContainer::active_processor_count: %d", result);535536// Update cached metric to avoid re-reading container settings too often537cpu_limit->set_value(result, OSCONTAINER_CACHE_TIMEOUT);538539return result;540}541542/* memory_limit_in_bytes543*544* Return the limit of available memory for this process.545*546* return:547* memory limit in bytes or548* -1 for unlimited549* OSCONTAINER_ERROR for not supported550*/551jlong CgroupSubsystem::memory_limit_in_bytes() {552CachingCgroupController* contrl = memory_controller();553CachedMetric* memory_limit = contrl->metrics_cache();554if (!memory_limit->should_check_metric()) {555return memory_limit->value();556}557jlong mem_limit = read_memory_limit_in_bytes();558// Update cached metric to avoid re-reading container settings too often559memory_limit->set_value(mem_limit, OSCONTAINER_CACHE_TIMEOUT);560return mem_limit;561}562563jlong CgroupSubsystem::limit_from_str(char* limit_str) {564if (limit_str == NULL) {565return OSCONTAINER_ERROR;566}567// Unlimited memory in cgroups is the literal string 'max' for568// some controllers, for example the pids controller.569if (strcmp("max", limit_str) == 0) {570os::free(limit_str);571return (jlong)-1;572}573julong limit;574if (sscanf(limit_str, JULONG_FORMAT, &limit) != 1) {575os::free(limit_str);576return OSCONTAINER_ERROR;577}578os::free(limit_str);579return (jlong)limit;580}581582583