/// <summary>Find the cgroup path for the specified subsystem.</summary> /// <param name="subsystem">The subsystem, e.g. "memory".</param> /// <returns>The cgroup path if found; otherwise, null.</returns> private static string FindCGroupPath(string subsystem, out CGroupVersion version) { if (TryFindHierarchyMount(subsystem, out version, out string hierarchyRoot, out string hierarchyMount) && TryFindCGroupPathForSubsystem(subsystem, out string cgroupPathRelativeToMount)) { // For a host cgroup, we need to append the relative path. // In a docker container, the root and relative path are the same and we don't need to append. return((hierarchyRoot != cgroupPathRelativeToMount) ? hierarchyMount + cgroupPathRelativeToMount : hierarchyMount); } return(null); }
internal static bool TryFindHierarchyMount(string mountInfoFilePath, string subsystem, out CGroupVersion version, out string root, out string path) { if (File.Exists(mountInfoFilePath)) { try { using (var reader = new StreamReader(mountInfoFilePath)) { string line; while ((line = reader.ReadLine()) != null) { // Look for an entry that has cgroup as the "filesystem type" // and, for cgroup1, that has options containing the specified subsystem // See man page for /proc/[pid]/mountinfo for details, e.g.: // (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) // 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue // but (7) is optional and could exist as multiple fields; the (8) separator marks // the end of the optional values. const string Separator = " - "; int endOfOptionalFields = line.IndexOf(Separator); if (endOfOptionalFields == -1) { // Malformed line. continue; } string postSeparatorLine = line.Substring(endOfOptionalFields + Separator.Length); string[] postSeparatorlineParts = postSeparatorLine.Split(' '); if (postSeparatorlineParts.Length < 3) { // Malformed line. continue; } bool validCGroup1Entry = ((postSeparatorlineParts[0] == "cgroup") && (Array.IndexOf(postSeparatorlineParts[2].Split(','), subsystem) >= 0)); bool validCGroup2Entry = postSeparatorlineParts[0] == "cgroup2"; if (!validCGroup1Entry && !validCGroup2Entry) { // Not the relevant entry. continue; } // Found the relevant entry. Extract the cgroup version, mount root and path. switch (postSeparatorlineParts[0]) { case "cgroup": version = CGroupVersion.CGroup1; break; case "cgroup2": version = CGroupVersion.CGroup2; break; default: version = CGroupVersion.None; Debug.Fail($"invalid value for CGroupVersion \"{postSeparatorlineParts[0]}\""); break; } string[] lineParts = line.Substring(0, endOfOptionalFields).Split(' '); root = lineParts[3]; path = lineParts[4]; return(true); } } } catch (Exception e) { Debug.Fail($"Failed to read or parse \"{ProcMountInfoFilePath}\": {e}"); } } version = CGroupVersion.None; root = null; path = null; return(false); }
/// <summary>Find the cgroup mount information for the specified subsystem.</summary> /// <param name="subsystem">The subsystem, e.g. "memory".</param> /// <param name="root">The path of the directory in the filesystem which forms the root of this mount; null if not found.</param> /// <param name="path">The path of the mount point relative to the process's root directory; null if not found.</param> /// <returns>true if the mount was found; otherwise, null.</returns> private static bool TryFindHierarchyMount(string subsystem, out CGroupVersion version, out string root, out string path) { return(TryFindHierarchyMount(ProcMountInfoFilePath, subsystem, out version, out root, out path)); }
private static bool TryFindHierarchyMount(string subsystem, out CGroupVersion version, [NotNullWhen(true)] out string?root, [NotNullWhen(true)] out string?path) { return(TryFindHierarchyMount(ProcMountInfoFilePath, subsystem, out version, out root, out path)); }