-
Notifications
You must be signed in to change notification settings - Fork 5k
DriveInfo.Linux: use procfs mountinfo for formats and mount point paths. #116102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
For the format, mountinfo includes a string 'filesystem type' field which is more granular than the statfs f_type numeric field. For example: the ext2, ext3 and ext4 are distinct mountinfo values which have the same same f_type value. For the mount paths, mountinfo provides the mount point paths relative to the process's root directory. When the process runs with changed root dir (chroot), the paths are adjusted for it.
long numericFormat; | ||
int result = Interop.Sys.GetFormatInfoForMountPoint(SysFsCgroupFileSystemPath, formatBuffer, MountPointFormatBufferSizeInBytes, &numericFormat); | ||
if (result == 0) | ||
Span<char> buffer = stackalloc char[16]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file was also parsing mountinfo, so I've updated it to share the parsing logic with DriveInfo.
src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs
Show resolved
Hide resolved
Marshal.PtrToStringUTF8((IntPtr)formatBuffer)!; | ||
type = GetDriveType(format); | ||
// Canonicalize and resolve symbolic links. | ||
string? path = Sys.RealPath(name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is now going to make several syscalls where there used to be one.
If this turns out to be an performance issue, we can reduce the nr of calls:
-
If we use
statx
then we can get theSTATX_MNT_ID
which corresponds to the first field inmountinfo
. This replaces multiple syscalls made byrealpath
into a single syscall. -
For Linux 6.8+, we can call
statx
withSTATX_MNT_ID_UNIQUE
and then use that with thestatmount
syscall withSTATMOUNT_FS_TYPE
which avoids the syscalls for opening and readingmountinfo
to get the filesystem type name.
I don't intend to include these changes as part of this PR (unless someone finds it important).
@dotnet/area-system-io this is up for review. |
@tmds, was the refactoring on native side essential for this to work? I am asking because we implemented the fallbacks when I was on a "many different OS / filesystems configuration testing" trips (Android emulator on macOS vs. Windows, illumos various filesystems ZFS-based fs vs. the others, freebsd UFS vs. ZFS-based fs etc. etc.) and it took some time to figure out the magic values (this is the only place on the entire GitHub where we find such an exhaustive list of filesystem magic vals). I am pretty sure you have kept them logically equivalent, but on an off chance refactoring might break some prior contract, I suggest we keep this implementation to Linux only on C# side and refactor stuff in a separate PR (or leave it be to avoid going through laborious testing). |
This is about #116102 (comment). The main problem with I removed it because I assumed it was only used for Linux mapping for which the PR is now using I'll add back the |
…and remove duplicate value members.
This is up for review. |
} | ||
line = line.Slice(endOfOptionalFields + Separator.Length); | ||
fields = line.Split(' '); | ||
|
||
// (9) filesystem type | ||
if (!fields.MoveNext()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each block handles the field that is in the comment at the first line.
// (8) separator
updates fields
to be past the separator.
} | ||
line = line.Slice(endOfOptionalFields + Separator.Length); | ||
fields = line.Split(' '); | ||
|
||
// (9) filesystem type | ||
if (!fields.MoveNext()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Each block handles the field that is in the comment at the first line.
// (8) separator
updates fields
to be past the separator.
@dotnet/area-system-io ptal. |
@jeffhandley @adamsitnik can you take a look? It would be nice if this gets some usage in preview7. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise, LGTM. Thanks, @tmds.
string? path = Sys.RealPath(name); | ||
if (path is null) | ||
{ | ||
format = ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
string.Empty is used on ln 68.
format = ""; | |
format = string.Empty; |
if (File.Exists(ProcMountInfoFilePath)) | ||
{ | ||
try | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reduce nesting.
if (File.Exists(ProcMountInfoFilePath)) | |
{ | |
try | |
{ | |
if (!File.Exists(ProcMountInfoFilePath)) | |
return Error.ENOTSUP | |
try | |
{ |
/// where this enum must be a subset of the GetDriveType list, with the enum | ||
/// values here exactly matching a string there. | ||
/// where this enum must be a subset of the GetDriveType list, with the enum values here exactly matching a string there. | ||
/// If possible, use names that match the Linux file system type strings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
/// If possible, use names that match the Linux file system type strings. | |
/// If possible, use names that match the Linux file system type strings in /proc/filesystems. |
if (OperatingSystem.IsLinux()) | ||
{ | ||
if (File.Exists(Interop.procfs.ProcMountInfoFilePath)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (OperatingSystem.IsLinux()) | |
{ | |
if (File.Exists(Interop.procfs.ProcMountInfoFilePath)) | |
if (OperatingSystem.IsLinux() && File.Exists(Interop.procfs.ProcMountInfoFilePath)) |
selinux = 0xF97CFF8C, | ||
sffs = 0x786F4256, // same as vboxfs | ||
sharefs = 0x01021994, // same as tmpfs | ||
selinuxfs = 0xF97CFF8C, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these changes (add/del fs
suffix) seem to be worth including in the breaking change doc.
/ba-g
Merging to include in preview6. |
For the format, mountinfo includes a string 'filesystem type' field which is more granular than the statfs f_type numeric field. For example: the ext2, ext3 and ext4 are distinct mountinfo values which have the same f_type value.
For the mount paths, mountinfo provides the mount point paths relative to the process's root directory. When the process runs with changed root dir (chroot), the paths are adjusted for it.
This is a breaking change. On Linux, the DriveInfo.DriveFormat previously were names from the
UnixFileSystemTypes
enum members. With this change, they will be Linux kernel filesystem type strings.Fixes #95099.
@dotnet/area-system-io @stephentoub ptal.