Skip to content

Commit 6596919

Browse files
committed
Reimplement mountinfo parsing without using regex
1 parent 84016e1 commit 6596919

File tree

1 file changed

+60
-34
lines changed

1 file changed

+60
-34
lines changed

src/java.base/linux/classes/jdk/internal/platform/CgroupSubsystemFactory.java

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@
3838
import java.util.Optional;
3939
import java.util.Objects;
4040
import java.util.function.Consumer;
41-
import java.util.regex.Matcher;
42-
import java.util.regex.Pattern;
4341
import java.util.stream.Stream;
4442

4543
import jdk.internal.platform.cgroupv1.CgroupV1Subsystem;
@@ -54,31 +52,6 @@ public class CgroupSubsystemFactory {
5452
private static final String MEMORY_CTRL = "memory";
5553
private static final String PIDS_CTRL = "pids";
5654

57-
/*
58-
* From https://www.kernel.org/doc/Documentation/filesystems/proc.txt
59-
*
60-
* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
61-
* (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
62-
*
63-
* (1) mount ID: unique identifier of the mount (may be reused after umount)
64-
* (2) parent ID: ID of parent (or of self for the top of the mount tree)
65-
* (3) major:minor: value of st_dev for files on filesystem
66-
* (4) root: root of the mount within the filesystem
67-
* (5) mount point: mount point relative to the process's root
68-
* (6) mount options: per mount options
69-
* (7) optional fields: zero or more fields of the form "tag[:value]"
70-
* (8) separator: marks the end of the optional fields
71-
* (9) filesystem type: name of filesystem of the form "type[.subtype]"
72-
* (10) mount source: filesystem specific information or "none"
73-
* (11) super options: per super block options
74-
*/
75-
private static final Pattern MOUNTINFO_PATTERN = Pattern.compile(
76-
"^[^\\s]+\\s+[^\\s]+\\s+[^\\s]+\\s+" + // (1), (2), (3)
77-
"([^\\s]+)\\s+([^\\s]+)\\s+" + // (4), (5) - group 1, 2: root, mount point
78-
"[^-]+-\\s+" + // (6), (7), (8)
79-
"([^\\s]+)\\s+" + // (9) - group 3: filesystem type
80-
".*$"); // (10), (11)
81-
8255
static CgroupMetrics create() {
8356
Optional<CgroupTypeResult> optResult = null;
8457
try {
@@ -285,8 +258,8 @@ private static void setCgroupV1Path(Map<String, CgroupInfo> infos,
285258
/**
286259
* Amends cgroup infos with mount path and mount root. The passed in
287260
* 'mntInfoLine' represents a single line in, for example,
288-
* /proc/self/mountinfo. Each line is matched with MOUNTINFO_PATTERN
289-
* (see above), so as to extract the relevant tokens from the line.
261+
* /proc/self/mountinfo. Each line is parsed with {@link MountInfo#parse},
262+
* so as to extract the relevant tokens from the line.
290263
*
291264
* Host example cgroups v1:
292265
*
@@ -307,13 +280,13 @@ private static void setCgroupV1Path(Map<String, CgroupInfo> infos,
307280
private static boolean amendCgroupInfos(String mntInfoLine,
308281
Map<String, CgroupInfo> infos,
309282
boolean isCgroupsV2) {
310-
Matcher lineMatcher = MOUNTINFO_PATTERN.matcher(mntInfoLine.trim());
283+
MountInfo mountInfo = MountInfo.parse(mntInfoLine);
311284
boolean cgroupv1ControllerFound = false;
312285
boolean cgroupv2ControllerFound = false;
313-
if (lineMatcher.matches()) {
314-
String mountRoot = lineMatcher.group(1);
315-
String mountPath = lineMatcher.group(2);
316-
String fsType = lineMatcher.group(3);
286+
if (mountInfo != null) {
287+
String mountRoot = mountInfo.mountRoot;
288+
String mountPath = mountInfo.mountPath;
289+
String fsType = mountInfo.fsType;
317290
if (fsType.equals("cgroup")) {
318291
Path p = Paths.get(mountPath);
319292
String[] controllerNames = p.getFileName().toString().split(",");
@@ -349,6 +322,59 @@ private static boolean amendCgroupInfos(String mntInfoLine,
349322
return cgroupv1ControllerFound || cgroupv2ControllerFound;
350323
}
351324

325+
private record MountInfo(String mountRoot, String mountPath, String fsType) {
326+
/*
327+
* From https://www.kernel.org/doc/Documentation/filesystems/proc.txt
328+
*
329+
* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
330+
* (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
331+
*
332+
* (1) mount ID: unique identifier of the mount (may be reused after umount)
333+
* (2) parent ID: ID of parent (or of self for the top of the mount tree)
334+
* (3) major:minor: value of st_dev for files on filesystem
335+
* (4) root: root of the mount within the filesystem
336+
* (5) mount point: mount point relative to the process's root
337+
* (6) mount options: per mount options
338+
* (7) optional fields: zero or more fields of the form "tag[:value]"
339+
* (8) separator: marks the end of the optional fields
340+
* (9) filesystem type: name of filesystem of the form "type[.subtype]"
341+
* (10) mount source: filesystem specific information or "none"
342+
* (11) super options: per super block options
343+
*/
344+
static MountInfo parse(String line) {
345+
String mountRoot = null;
346+
String mountPath = null;
347+
348+
int separatorOrdinal = -1;
349+
// loop over space-separated tokens
350+
for (int tOrdinal = 1, tStart = 0, tEnd = line.indexOf(' '); tEnd != -1; tOrdinal++, tStart = tEnd + 1, tEnd = line.indexOf(' ', tStart)) {
351+
if (tStart == tEnd) {
352+
break; // unexpected empty token
353+
}
354+
switch (tOrdinal) {
355+
case 1, 2, 3, 6 -> {} // skip token
356+
case 4 -> mountRoot = line.substring(tStart, tEnd); // root token
357+
case 5 -> mountPath = line.substring(tStart, tEnd); // mount point token
358+
default -> {
359+
assert tOrdinal >= 7;
360+
if (separatorOrdinal == -1) {
361+
// check if we found a separator token
362+
if (tEnd - tStart == 1 && line.charAt(tStart) == '-') {
363+
separatorOrdinal = tOrdinal;
364+
}
365+
continue; // skip token
366+
}
367+
if (tOrdinal == separatorOrdinal + 1) { // filesystem type token
368+
String fsType = line.substring(tStart, tEnd);
369+
return new MountInfo(mountRoot, mountPath, fsType);
370+
}
371+
}
372+
}
373+
}
374+
return null; // parsing failed
375+
}
376+
}
377+
352378
private static void setMountPoints(CgroupInfo info, String mountPath, String mountRoot) {
353379
if (info.getMountPoint() != null) {
354380
// On some systems duplicate controllers get mounted in addition to

0 commit comments

Comments
 (0)