From ec1c9a747c41bd7fc7fd7edd82b68051bf113acc Mon Sep 17 00:00:00 2001 From: Josef Eisl Date: Wed, 16 Apr 2025 08:28:59 +0200 Subject: [PATCH] svm: adopt "JDK-8349988: Change cgroup version detection logic to not depend on /proc/cgroups" --- .../svm/core/container/ContainerLibrary.java | 68 +++--- .../os/linux/cgroupSubsystem_linux.cpp | 194 ++++++++++++------ .../os/linux/cgroupSubsystem_linux.hpp | 3 +- .../src/hotspot/os/linux/os_linux.cpp | 47 ++--- .../src/hotspot/os/posix/os_posix.cpp | 4 +- .../src/hotspot/share/runtime/os.cpp | 44 ++-- .../share/utilities/globalDefinitions.hpp | 8 + .../share/utilities/globalDefinitions_gcc.hpp | 3 - .../src/hotspot/share/utilities/ostream.cpp | 7 + .../src/hotspot/share/utilities/ostream.hpp | 1 + 10 files changed, 227 insertions(+), 152 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java index 7d537b0ea95d..5afcb9b79a39 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/container/ContainerLibrary.java @@ -48,46 +48,46 @@ @CContext(ContainerLibraryDirectives.class) @CLibrary(value = "svm_container", requireStatic = true, dependsOn = "m") // The following annotations are for files in `src/hotspot`, which are copied from the JDK -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/java.base/share/native/include/jni.h") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+6/src/java.base/unix/native/include/jni_md.h") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/java.base/share/native/include/jni.h") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/java.base/unix/native/include/jni_md.h") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/cgroupSubsystem_linux.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/cgroupSubsystem_linux.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/linux/cgroupUtil_linux.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/linux/cgroupUtil_linux.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/linux/osContainer_linux.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/linux/osContainer_linux.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+17/src/hotspot/os/linux/os_linux.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/linux/os_linux.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/linux/os_linux.inline.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/posix/include/jvm_md.h") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/cgroupUtil_linux.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/cgroupUtil_linux.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/osContainer_linux.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/osContainer_linux.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/os_linux.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/os_linux.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/linux/os_linux.inline.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/posix/include/jvm_md.h") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/posix/os_posix.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/posix/os_posix.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/os/posix/os_posix.inline.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/memory/allocation.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/memory/allocation.inline.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/memory/allStatic.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/nmt/memTag.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+17/src/hotspot/share/runtime/os.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/runtime/os.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/runtime/os.inline.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/utilities/checkedCast.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/utilities/compilerWarnings_gcc.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/utilities/compilerWarnings.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+16/src/hotspot/share/utilities/globalDefinitions_gcc.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+16/src/hotspot/share/utilities/globalDefinitions.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/utilities/macros.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/posix/os_posix.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/os/posix/os_posix.inline.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/memory/allocation.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/memory/allocation.inline.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/memory/allStatic.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/nmt/memTag.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/runtime/os.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/runtime/os.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/runtime/os.inline.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/utilities/checkedCast.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/utilities/compilerWarnings_gcc.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/utilities/compilerWarnings.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/utilities/globalDefinitions_gcc.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/utilities/globalDefinitions.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/utilities/macros.hpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/utilities/ostream.cpp") @BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/utilities/ostream.hpp") // The following annotations are for files in `src/svm`, which are completely customized for SVM -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/logging/log.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/memory/allocation.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+15/src/hotspot/share/runtime/globals.hpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/utilities/debug.cpp") -@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+13/src/hotspot/share/utilities/debug.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/logging/log.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/memory/allocation.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/runtime/globals.hpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/utilities/debug.cpp") +@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-25+18/src/hotspot/share/utilities/debug.hpp") public class ContainerLibrary { static final int VERSION = 240100; diff --git a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index d2c02af79d9e..8c671388f573 100644 --- a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "cgroupSubsystem_linux.hpp" #include "cgroupV1Subsystem_linux.hpp" #include "cgroupV2Subsystem_linux.hpp" @@ -37,11 +38,29 @@ #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" +// Inlined from for portability. +#ifndef CGROUP2_SUPER_MAGIC +# define CGROUP2_SUPER_MAGIC 0x63677270 +#endif + // controller names have to match the *_IDX indices namespace svm_container { static const char* cg_controller_name[] = { "cpuset", "cpu", "cpuacct", "memory", "pids" }; +static inline int cg_v2_controller_index(const char* name) { + if (strcmp(name, "cpuset") == 0) { + return CPUSET_IDX; + } else if (strcmp(name, "cpu") == 0) { + return CPU_IDX; + } else if (strcmp(name, "memory") == 0) { + return MEMORY_IDX; + } else if (strcmp(name, "pids") == 0) { + return PIDS_IDX; + } else { + return -1; + } +} CgroupSubsystem* CgroupSubsystemFactory::create() { CgroupV1MemoryController* memory = nullptr; @@ -52,10 +71,25 @@ CgroupSubsystem* CgroupSubsystemFactory::create() { CgroupInfo cg_infos[CG_INFO_LENGTH]; u1 cg_type_flags = INVALID_CGROUPS_GENERIC; const char* proc_cgroups = "/proc/cgroups"; + const char* sys_fs_cgroup_cgroup_controllers = "/sys/fs/cgroup/cgroup.controllers"; + const char* controllers_file = proc_cgroups; const char* proc_self_cgroup = "/proc/self/cgroup"; const char* proc_self_mountinfo = "/proc/self/mountinfo"; + const char* sys_fs_cgroup = "/sys/fs/cgroup"; + struct statfs fsstat = {}; + bool cgroups_v2_enabled = false; + + // Assume cgroups v2 is usable by the JDK iff /sys/fs/cgroup has the cgroup v2 + // file system magic. If it does not then heuristics are required to determine + // if cgroups v1 is usable or not. + if (statfs(sys_fs_cgroup, &fsstat) != -1) { + cgroups_v2_enabled = (fsstat.f_type == CGROUP2_SUPER_MAGIC); + if (cgroups_v2_enabled) { + controllers_file = sys_fs_cgroup_cgroup_controllers; + } + } - bool valid_cgroup = determine_type(cg_infos, proc_cgroups, proc_self_cgroup, proc_self_mountinfo, &cg_type_flags); + bool valid_cgroup = determine_type(cg_infos, cgroups_v2_enabled, controllers_file, proc_self_cgroup, proc_self_mountinfo, &cg_type_flags); if (!valid_cgroup) { // Could not detect cgroup type @@ -220,84 +254,118 @@ static inline bool match_mount_info_line(char* line, } bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, - const char* proc_cgroups, + bool cgroups_v2_enabled, + const char* controllers_file, const char* proc_self_cgroup, const char* proc_self_mountinfo, u1* flags) { FILE *mntinfo = nullptr; - FILE *cgroups = nullptr; + FILE* controllers = nullptr; FILE *cgroup = nullptr; char buf[MAXPATHLEN+1]; char *p; - bool is_cgroupsV2; // true iff all required controllers, memory, cpu, cpuacct are enabled // at the kernel level. // pids might not be enabled on older Linux distros (SLES 12.1, RHEL 7.1) // cpuset might not be enabled on newer Linux distros (Fedora 41) - bool all_required_controllers_enabled; + bool all_required_controllers_enabled = true; - /* - * Read /proc/cgroups so as to be able to distinguish cgroups v2 vs cgroups v1. - * - * For cgroups v1 hierarchy (hybrid or legacy), cpu, cpuacct, cpuset, memory controllers - * must have non-zero for the hierarchy ID field and relevant controllers mounted. - * Conversely, for cgroups v2 (unified hierarchy), cpu, cpuacct, cpuset, memory - * controllers must have hierarchy ID 0 and the unified controller mounted. - */ - cgroups = os::fopen(proc_cgroups, "r"); - if (cgroups == nullptr) { - log_debug(os, container)("Can't open %s, %s", proc_cgroups, os::strerror(errno)); + // If cgroups v2 is enabled, open /sys/fs/cgroup/cgroup.controllers. If not, open /proc/cgroups. + controllers = os::fopen(controllers_file, "r"); + if (controllers == nullptr) { + log_debug(os, container)("Can't open %s, %s", controllers_file, os::strerror(errno)); *flags = INVALID_CGROUPS_GENERIC; return false; } - while ((p = fgets(buf, MAXPATHLEN, cgroups)) != nullptr) { - char name[MAXPATHLEN+1]; - int hierarchy_id; - int enabled; - - // Format of /proc/cgroups documented via man 7 cgroups - if (sscanf(p, "%s %d %*d %d", name, &hierarchy_id, &enabled) != 3) { - continue; + if (cgroups_v2_enabled) { + /* + * cgroups v2 is enabled. For cgroups v2 (unified hierarchy), the cpu and memory + * controllers must be enabled. + */ + if ((p = fgets(buf, MAXPATHLEN, controllers)) != nullptr) { + char* controller = nullptr; + #define ISSPACE_CHARS " \n\t\r\f\v" + while ((controller = strsep(&p, ISSPACE_CHARS)) != nullptr) { + int i; + if ((i = cg_v2_controller_index(controller)) != -1) { + cg_infos[i]._name = os::strdup(controller); + cg_infos[i]._enabled = true; + if (i == PIDS_IDX || i == CPUSET_IDX) { + log_debug(os, container)("Detected optional %s controller entry in %s", + controller, controllers_file); + } + } + } + #undef ISSPACE_CHARS + } else { + log_debug(os, container)("Can't read %s, %s", controllers_file, os::strerror(errno)); + *flags = INVALID_CGROUPS_V2; + return false; } - if (strcmp(name, "memory") == 0) { - cg_infos[MEMORY_IDX]._name = os::strdup(name); - cg_infos[MEMORY_IDX]._hierarchy_id = hierarchy_id; - cg_infos[MEMORY_IDX]._enabled = (enabled == 1); - } else if (strcmp(name, "cpuset") == 0) { - log_debug(os, container)("Detected optional cpuset controller entry in %s", proc_cgroups); - cg_infos[CPUSET_IDX]._name = os::strdup(name); - cg_infos[CPUSET_IDX]._hierarchy_id = hierarchy_id; - cg_infos[CPUSET_IDX]._enabled = (enabled == 1); - } else if (strcmp(name, "cpu") == 0) { - cg_infos[CPU_IDX]._name = os::strdup(name); - cg_infos[CPU_IDX]._hierarchy_id = hierarchy_id; - cg_infos[CPU_IDX]._enabled = (enabled == 1); - } else if (strcmp(name, "cpuacct") == 0) { - cg_infos[CPUACCT_IDX]._name = os::strdup(name); - cg_infos[CPUACCT_IDX]._hierarchy_id = hierarchy_id; - cg_infos[CPUACCT_IDX]._enabled = (enabled == 1); - } else if (strcmp(name, "pids") == 0) { - log_debug(os, container)("Detected optional pids controller entry in %s", proc_cgroups); - cg_infos[PIDS_IDX]._name = os::strdup(name); - cg_infos[PIDS_IDX]._hierarchy_id = hierarchy_id; - cg_infos[PIDS_IDX]._enabled = (enabled == 1); + for (int i = 0; i < CG_INFO_LENGTH; i++) { + // cgroups v2 does not have cpuacct. + if (i == CPUACCT_IDX) { + continue; + } + // For cgroups v2, cpuacct is rolled into cpu, and the pids and cpuset controllers + // are optional; the remaining controllers, cpu and memory, are required. + if (i == CPU_IDX || i == MEMORY_IDX) { + all_required_controllers_enabled = all_required_controllers_enabled && cg_infos[i]._enabled; + } + if (log_is_enabled(Debug, os, container) && !cg_infos[i]._enabled) { + log_debug(os, container)("controller %s is not enabled", cg_controller_name[i]); + } } - } - fclose(cgroups); + } else { + /* + * The /sys/fs/cgroup filesystem magic hint suggests we have cg v1. Read /proc/cgroups; for + * cgroups v1 hierarchy (hybrid or legacy), cpu, cpuacct, cpuset, and memory controllers must + * have non-zero for the hierarchy ID field and relevant controllers mounted. + */ + while ((p = fgets(buf, MAXPATHLEN, controllers)) != nullptr) { + char name[MAXPATHLEN+1]; + int hierarchy_id; + int enabled; - is_cgroupsV2 = true; - all_required_controllers_enabled = true; - for (int i = 0; i < CG_INFO_LENGTH; i++) { - // pids and cpuset controllers are optional. All other controllers are required - if (i != PIDS_IDX && i != CPUSET_IDX) { - is_cgroupsV2 = is_cgroupsV2 && cg_infos[i]._hierarchy_id == 0; - all_required_controllers_enabled = all_required_controllers_enabled && cg_infos[i]._enabled; + // Format of /proc/cgroups documented via man 7 cgroups + if (sscanf(p, "%s %d %*d %d", name, &hierarchy_id, &enabled) != 3) { + continue; + } + if (strcmp(name, "memory") == 0) { + cg_infos[MEMORY_IDX]._name = os::strdup(name); + cg_infos[MEMORY_IDX]._hierarchy_id = hierarchy_id; + cg_infos[MEMORY_IDX]._enabled = (enabled == 1); + } else if (strcmp(name, "cpuset") == 0) { + cg_infos[CPUSET_IDX]._name = os::strdup(name); + cg_infos[CPUSET_IDX]._hierarchy_id = hierarchy_id; + cg_infos[CPUSET_IDX]._enabled = (enabled == 1); + } else if (strcmp(name, "cpu") == 0) { + cg_infos[CPU_IDX]._name = os::strdup(name); + cg_infos[CPU_IDX]._hierarchy_id = hierarchy_id; + cg_infos[CPU_IDX]._enabled = (enabled == 1); + } else if (strcmp(name, "cpuacct") == 0) { + cg_infos[CPUACCT_IDX]._name = os::strdup(name); + cg_infos[CPUACCT_IDX]._hierarchy_id = hierarchy_id; + cg_infos[CPUACCT_IDX]._enabled = (enabled == 1); + } else if (strcmp(name, "pids") == 0) { + log_debug(os, container)("Detected optional pids controller entry in %s", controllers_file); + cg_infos[PIDS_IDX]._name = os::strdup(name); + cg_infos[PIDS_IDX]._hierarchy_id = hierarchy_id; + cg_infos[PIDS_IDX]._enabled = (enabled == 1); + } } - if (log_is_enabled(Debug, os, container) && !cg_infos[i]._enabled) { - log_debug(os, container)("controller %s is not enabled\n", cg_controller_name[i]); + for (int i = 0; i < CG_INFO_LENGTH; i++) { + // pids controller is optional. All other controllers are required + if (i != PIDS_IDX) { + all_required_controllers_enabled = all_required_controllers_enabled && cg_infos[i]._enabled; + } + if (log_is_enabled(Debug, os, container) && !cg_infos[i]._enabled) { + log_debug(os, container)("controller %s is not enabled\n", cg_controller_name[i]); + } } } + fclose(controllers); if (!all_required_controllers_enabled) { // one or more required controllers disabled, disable container support @@ -339,7 +407,7 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, continue; } - while (!is_cgroupsV2 && (token = strsep(&controllers, ",")) != nullptr) { + while (!cgroups_v2_enabled && (token = strsep(&controllers, ",")) != nullptr) { if (strcmp(token, "memory") == 0) { assert(hierarchy_id == cg_infos[MEMORY_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for memory"); cg_infos[MEMORY_IDX]._cgroup_path = os::strdup(cgroup_path); @@ -350,7 +418,7 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, assert(hierarchy_id == cg_infos[CPU_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpu"); cg_infos[CPU_IDX]._cgroup_path = os::strdup(cgroup_path); } else if (strcmp(token, "cpuacct") == 0) { - assert(hierarchy_id == cg_infos[CPUACCT_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpuacc"); + assert(hierarchy_id == cg_infos[CPUACCT_IDX]._hierarchy_id, "/proc/cgroups and /proc/self/cgroup hierarchy mismatch for cpuacct"); cg_infos[CPUACCT_IDX]._cgroup_path = os::strdup(cgroup_path); } else if (strcmp(token, "pids") == 0) { assert(hierarchy_id == cg_infos[PIDS_IDX]._hierarchy_id, "/proc/cgroups (%d) and /proc/self/cgroup (%d) hierarchy mismatch for pids", @@ -358,7 +426,7 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, cg_infos[PIDS_IDX]._cgroup_path = os::strdup(cgroup_path); } } - if (is_cgroupsV2) { + if (cgroups_v2_enabled) { // On some systems we have mixed cgroups v1 and cgroups v2 controllers (e.g. freezer on cg1 and // all relevant controllers on cg2). Only set the cgroup path when we see a hierarchy id of 0. if (hierarchy_id != 0) { @@ -394,14 +462,14 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, char *cptr = tmpcgroups; char *token; - /* Cgroup v2 relevant info. We only look for the _mount_path iff is_cgroupsV2 so + /* Cgroup v2 relevant info. We only look for the _mount_path iff cgroups_v2_enabled so * as to avoid memory stomping of the _mount_path pointer later on in the cgroup v1 * block in the hybrid case. * * We collect the read only mount option in the cgroup infos so as to have that * info ready when determining is_containerized(). */ - if (is_cgroupsV2 && match_mount_info_line(p, + if (cgroups_v2_enabled && match_mount_info_line(p, tmproot, tmpmount, mount_opts, @@ -480,7 +548,7 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, return false; } - if (is_cgroupsV2) { + if (cgroups_v2_enabled) { if (!cgroupv2_mount_point_found) { log_trace(os, container)("Mount point for cgroupv2 not found in /proc/self/mountinfo"); cleanup(cg_infos); diff --git a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index b3dba40f0fbd..a2ea1476d09a 100644 --- a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -339,7 +339,8 @@ class CgroupSubsystemFactory: AllStatic { // Determine the cgroup type (version 1 or version 2), given // relevant paths to files. Sets 'flags' accordingly. static bool determine_type(CgroupInfo* cg_infos, - const char* proc_cgroups, + bool cgroups_v2_enabled, + const char* controllers_file, const char* proc_self_cgroup, const char* proc_self_mountinfo, u1* flags); diff --git a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/os_linux.cpp b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/os_linux.cpp index 048eb331388b..b5d5bc1bd235 100644 --- a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/os_linux.cpp +++ b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/linux/os_linux.cpp @@ -3812,10 +3812,9 @@ static bool hugetlbfs_sanity_check(size_t page_size) { munmap(p, page_size); return true; } else { - log_info(pagesize)("Large page size (%zu%s) failed sanity check, " + log_info(pagesize)("Large page size (" EXACTFMT ") failed sanity check, " "checking if smaller large page sizes are usable", - byte_size_in_exact_unit(page_size), - exact_unit_for_byte_size(page_size)); + EXACTFMTARGS(page_size)); for (size_t page_size_ = page_sizes.next_smaller(page_size); page_size_ > os::vm_page_size(); page_size_ = page_sizes.next_smaller(page_size_)) { @@ -3824,9 +3823,8 @@ static bool hugetlbfs_sanity_check(size_t page_size) { if (p != MAP_FAILED) { // Mapping succeeded, sanity check passed. munmap(p, page_size_); - log_info(pagesize)("Large page size (%zu%s) passed sanity check", - byte_size_in_exact_unit(page_size_), - exact_unit_for_byte_size(page_size_)); + log_info(pagesize)("Large page size (" EXACTFMT ") passed sanity check", + EXACTFMTARGS(page_size_)); return true; } } @@ -4023,26 +4021,21 @@ void os::Linux::large_page_init() { LargePageSizeInBytes == 0 || LargePageSizeInBytes == default_large_page_size) { large_page_size = default_large_page_size; - log_info(pagesize)("Using the default large page size: %zu%s", - byte_size_in_exact_unit(large_page_size), - exact_unit_for_byte_size(large_page_size)); + log_info(pagesize)("Using the default large page size: " EXACTFMT, + EXACTFMTARGS(large_page_size)); } else { if (all_large_pages.contains(LargePageSizeInBytes)) { large_page_size = LargePageSizeInBytes; - log_info(pagesize)("Overriding default large page size (%zu%s) " - "using LargePageSizeInBytes: %zu%s", - byte_size_in_exact_unit(default_large_page_size), - exact_unit_for_byte_size(default_large_page_size), - byte_size_in_exact_unit(large_page_size), - exact_unit_for_byte_size(large_page_size)); + log_info(pagesize)("Overriding default large page size (" EXACTFMT ") " + "using LargePageSizeInBytes: " EXACTFMT, + EXACTFMTARGS(default_large_page_size), + EXACTFMTARGS(large_page_size)); } else { large_page_size = default_large_page_size; - log_info(pagesize)("LargePageSizeInBytes is not a valid large page size (%zu%s) " - "using the default large page size: %zu%s", - byte_size_in_exact_unit(LargePageSizeInBytes), - exact_unit_for_byte_size(LargePageSizeInBytes), - byte_size_in_exact_unit(large_page_size), - exact_unit_for_byte_size(large_page_size)); + log_info(pagesize)("LargePageSizeInBytes is not a valid large page size (" EXACTFMT ") " + "using the default large page size: " EXACTFMT, + EXACTFMTARGS(LargePageSizeInBytes), + EXACTFMTARGS(large_page_size)); } } @@ -4083,9 +4076,8 @@ static void log_on_commit_special_failure(char* req_addr, size_t bytes, assert(error == ENOMEM, "Only expect to fail if no memory is available"); log_info(pagesize)("Failed to reserve and commit memory with given page size. req_addr: " PTR_FORMAT - " size: %zu%s, page size: %zu%s, (errno = %d)", - p2i(req_addr), byte_size_in_exact_unit(bytes), exact_unit_for_byte_size(bytes), - byte_size_in_exact_unit(page_size), exact_unit_for_byte_size(page_size), error); + " size: " EXACTFMT ", page size: " EXACTFMT ", (errno = %d)", + p2i(req_addr), EXACTFMTARGS(bytes), EXACTFMTARGS(page_size), error); } static bool commit_memory_special(size_t bytes, @@ -4112,11 +4104,8 @@ static bool commit_memory_special(size_t bytes, return false; } - log_debug(pagesize)("Commit special mapping: " PTR_FORMAT ", size=%zu%s, page size=%zu%s", - p2i(addr), byte_size_in_exact_unit(bytes), - exact_unit_for_byte_size(bytes), - byte_size_in_exact_unit(page_size), - exact_unit_for_byte_size(page_size)); + log_debug(pagesize)("Commit special mapping: " PTR_FORMAT ", size=" EXACTFMT ", page size=" EXACTFMT, + p2i(addr), EXACTFMTARGS(bytes), EXACTFMTARGS(page_size)); assert(is_aligned(addr, page_size), "Must be"); return true; } diff --git a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/posix/os_posix.cpp b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/posix/os_posix.cpp index 4eb615f4c9de..08f1fed53010 100644 --- a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/posix/os_posix.cpp +++ b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/os/posix/os_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -560,7 +560,7 @@ void os::Posix::print_uptime_info(outputStream* st) { setutxent(); while ((ent = getutxent())) { if (!strcmp("system boot", ent->ut_line)) { - bootsec = ent->ut_tv.tv_sec; + bootsec = (int)ent->ut_tv.tv_sec; break; } } diff --git a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/runtime/os.cpp b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/runtime/os.cpp index 22e07d36b09f..d4f7b258f954 100644 --- a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/runtime/os.cpp +++ b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/runtime/os.cpp @@ -1343,6 +1343,12 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { bool accessible = is_readable_pointer(addr); + // Check if addr points into the narrow Klass protection zone + if (UseCompressedClassPointers && CompressedKlassPointers::is_in_protection_zone(addr)) { + st->print_cr(PTR_FORMAT " points into nKlass protection zone", p2i(addr)); + return; + } + // Check if addr is a JNI handle. if (align_down((intptr_t)addr, sizeof(intptr_t)) != 0 && accessible) { if (JNIHandles::is_global_handle((jobject) addr)) { @@ -1868,8 +1874,6 @@ int os::create_binary_file(const char* path, bool rewrite_existing) { return ::open(path, oflags, S_IREAD | S_IWRITE); } -#define trace_page_size_params(size) byte_size_in_exact_unit(size), exact_unit_for_byte_size(size) - void os::trace_page_sizes(const char* str, const size_t region_min_size, const size_t region_max_size, @@ -1878,17 +1882,17 @@ void os::trace_page_sizes(const char* str, const size_t page_size) { log_info(pagesize)("%s: " - " min=%zu%s" - " max=%zu%s" + " min=" EXACTFMT + " max=" EXACTFMT " base=" PTR_FORMAT - " size=%zu%s" - " page_size=%zu%s", + " size=" EXACTFMT + " page_size=" EXACTFMT, str, - trace_page_size_params(region_min_size), - trace_page_size_params(region_max_size), + EXACTFMTARGS(region_min_size), + EXACTFMTARGS(region_max_size), p2i(base), - trace_page_size_params(size), - trace_page_size_params(page_size)); + EXACTFMTARGS(size), + EXACTFMTARGS(page_size)); } void os::trace_page_sizes_for_requested_size(const char* str, @@ -1899,17 +1903,17 @@ void os::trace_page_sizes_for_requested_size(const char* str, const size_t page_size) { log_info(pagesize)("%s:" - " req_size=%zu%s" - " req_page_size=%zu%s" + " req_size=" EXACTFMT + " req_page_size=" EXACTFMT " base=" PTR_FORMAT - " size=%zu%s" - " page_size=%zu%s", + " size=" EXACTFMT + " page_size=" EXACTFMT, str, - trace_page_size_params(requested_size), - trace_page_size_params(requested_page_size), + EXACTFMTARGS(requested_size), + EXACTFMTARGS(requested_page_size), p2i(base), - trace_page_size_params(size), - trace_page_size_params(page_size)); + EXACTFMTARGS(size), + EXACTFMTARGS(page_size)); } @@ -2069,10 +2073,10 @@ char* os::attempt_reserve_memory_between(char* min, char* max, size_t bytes, siz const size_t alignment_adjusted = MAX2(alignment, system_allocation_granularity); // Calculate first and last possible attach points: - char* const lo_att = align_up(MAX2(absolute_min, min), alignment_adjusted); - if (lo_att == nullptr) { + if (!can_align_up(MAX2(absolute_min, min), alignment_adjusted)) { return nullptr; // overflow } + char* const lo_att = align_up(MAX2(absolute_min, min), alignment_adjusted); char* const hi_end = MIN2(max, absolute_max); if ((uintptr_t)hi_end <= bytes) { diff --git a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/globalDefinitions.hpp b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/globalDefinitions.hpp index b40088c219ed..5223f0f8ed4b 100644 --- a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/globalDefinitions.hpp @@ -852,6 +852,14 @@ inline jlong min_signed_integer(BasicType bt) { return min_jlong; } +inline uint bits_per_java_integer(BasicType bt) { + if (bt == T_INT) { + return BitsPerJavaInteger; + } + assert(bt == T_LONG, "int or long only"); + return BitsPerJavaLong; +} + // Auxiliary math routines // least common multiple extern size_t lcm(size_t a, size_t b); diff --git a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/globalDefinitions_gcc.hpp b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/globalDefinitions_gcc.hpp index 06d8be044572..81d9e6360d75 100644 --- a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/globalDefinitions_gcc.hpp +++ b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/globalDefinitions_gcc.hpp @@ -100,9 +100,6 @@ inline int g_isnan(double f) { return isnan(f); } #error "missing platform-specific definition here" #endif -#define CAN_USE_NAN_DEFINE 1 - - // Checking for finiteness diff --git a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/ostream.cpp b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/ostream.cpp index 9e7e5d879396..812c6ba19afb 100644 --- a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/ostream.cpp +++ b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/ostream.cpp @@ -461,6 +461,13 @@ char* stringStream::as_string(bool c_heap) const { } return copy; } + +char* stringStream::as_string(Arena* arena) const { + char* copy = NEW_ARENA_ARRAY(arena, char, _written + 1); + ::memcpy(copy, _buffer, _written); + copy[_written] = '\0'; // terminating null + return copy; +} #endif // !NATIVE_IMAGE stringStream::~stringStream() { diff --git a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/ostream.hpp b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/ostream.hpp index b4b70f5ff7dc..494d90d5ce8d 100644 --- a/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/ostream.hpp +++ b/substratevm/src/com.oracle.svm.native.libcontainer/src/hotspot/share/utilities/ostream.hpp @@ -297,6 +297,7 @@ class stringStream : public outputStream { bool is_empty() const { return _buffer[0] == '\0'; } // Copy to a resource, or C-heap, array as requested char* as_string(bool c_heap = false) const; + char* as_string(Arena* arena) const; #endif // !NATIVE_IMAGE };