diff --git a/jdk/src/linux/classes/jdk/internal/platform/CgroupSubsystemFactory.java b/jdk/src/linux/classes/jdk/internal/platform/CgroupSubsystemFactory.java index e47513e02fe..b6141e3bae5 100644 --- a/jdk/src/linux/classes/jdk/internal/platform/CgroupSubsystemFactory.java +++ b/jdk/src/linux/classes/jdk/internal/platform/CgroupSubsystemFactory.java @@ -85,7 +85,10 @@ static CgroupMetrics create() { } catch (UncheckedIOException e) { return null; } + return create(optResult); + } + public static CgroupMetrics create(Optional optResult) { if (optResult.equals(Optional.empty())) { return null; } diff --git a/jdk/test/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java b/jdk/test/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java index 15793041c1b..fe5e1bc1abf 100644 --- a/jdk/test/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java +++ b/jdk/test/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java @@ -25,6 +25,7 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -50,7 +51,7 @@ /* * @test - * @bug 8293540 8287107 + * @bug 8287107 8287073 8293540 * @requires os.family == "linux" * @modules java.base/jdk.internal.platform * @library /lib/testlibrary @@ -64,6 +65,7 @@ public class TestCgroupSubsystemFactory { private Path cgroupv1CgInfoZeroHierarchy; private Path cgroupv1MntInfoZeroHierarchy; private Path cgroupv2CgInfoZeroHierarchy; + private Path cgroupv2CgInfoZeroMinimal; private Path cgroupv2MntInfoZeroHierarchy; private Path cgroupv1CgInfoNonZeroHierarchy; private Path cgroupv1MntInfoNonZeroHierarchy; @@ -125,6 +127,9 @@ public class TestCgroupSubsystemFactory { "net_cls 0 1 1\n" + "blkio 0 1 1\n" + "perf_event 0 1 1 "; + private String cgroupsZeroHierarchyMinimal = + "#subsys_name hierarchy num_cgroups enabled\n" + + "cpu 0 1 1\n"; private String mntInfoHybrid = "30 23 0:26 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:4 - tmpfs tmpfs ro,seclabel,mode=755\n" + "31 30 0:27 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:5 - cgroup2 none rw,seclabel,nsdelegate\n" + @@ -308,6 +313,9 @@ public void setup() { cgroupv1MountInfoCgroupsOnlyCPUCtrl = Paths.get(existingDirectory.toString(), "self_mountinfo_cpu_only_controller"); Files.write(cgroupv1MountInfoCgroupsOnlyCPUCtrl, mntInfoCpuOnly.getBytes(StandardCharsets.UTF_8)); + cgroupv2CgInfoZeroMinimal = Paths.get(existingDirectory.toString(), "cgv2_proc_cgroups_minimal"); + Files.write(cgroupv2CgInfoZeroMinimal, cgroupsZeroHierarchyMinimal.getBytes(StandardCharsets.UTF_8)); + cgroupv2CgInfoNoZeroHierarchyOnlyFreezer = Paths.get(existingDirectory.toString(), "cgroups_cgv2_non_zero_only_freezer"); Files.write(cgroupv2CgInfoNoZeroHierarchyOnlyFreezer, cgroupsNonZeroHierarchyOnlyFreezer.getBytes(StandardCharsets.UTF_8)); @@ -489,6 +497,30 @@ public void testZeroHierarchyCgroupsV2() throws IOException { assertEquals("/sys/fs/cgroup", cpuInfo.getMountPoint()); } + /* + * On some systems the memory controller might not show up in /proc/cgroups + * which may provoke a NPE on instantiation. See bug 8287073. + */ + @Test + public void testZeroHierarchyCgroupsV2Minimal() throws IOException { + String cgroups = cgroupv2CgInfoZeroMinimal.toString(); + String mountInfo = cgroupv2MntInfoZeroHierarchy.toString(); + String selfCgroup = cgroupv2SelfCgroup.toString(); + Optional result = CgroupSubsystemFactory.determineType(mountInfo, cgroups, selfCgroup); + + assertTrue("Expected non-empty cgroup result", result.isPresent()); + CgroupTypeResult res = result.get(); + + assertTrue("zero hierarchy ids with mounted controllers expected cgroups v2", res.isCgroupV2()); + assertNull("Only cpu controller present", res.getInfos().get("memory")); + try { + CgroupSubsystemFactory.create(result); + // pass + } catch (NullPointerException e) { + fail("Missing memory controller should not cause any NPE"); + } + } + @Test(expected = IOException.class) public void mountInfoFileNotFound() throws IOException { String cgroups = cgroupv1CgInfoZeroHierarchy.toString(); // any existing file