Skip to content

Fix StatVfsMountFlags::RELATIME on the linux_raw backend - #1695

Open
hiking90 wants to merge 2 commits into
bytecodealliance:mainfrom
hiking90:fix-statvfs-relatime
Open

hiking90 wants to merge 2 commits into
bytecodealliance:mainfrom
hiking90:fix-statvfs-relatime

Conversation

@hiking90

@hiking90 hiking90 commented Oct 3, 2026

Copy link
Copy Markdown

On the linux_raw backend, StatVfsMountFlags is defined with the MS_* mount flag values, because linux-raw-sys has no ST_* names. statvfs fills f_flag with the kernel's statfs f_flags unconverted, and those are ST_* values. Most of the two sets coincide, but ST_RELATIME is 0x1000 while MS_RELATIME is 1 << 21. As a result, statvfs(p)?.f_flag.contains(StatVfsMountFlags::RELATIME) is false on every relatime mount — most mounts on a default Linux system.

Reproduction: on a relatime root, rustix::fs::statvfs("/") returns StatVfsMountFlags(0x1020) (ST_RELATIME | ST_VALID), and contains(RELATIME) is false. The libc backend uses libc::ST_RELATIME and is correct.

Impact: code that reads the per-mount flags to preserve them across a bind remount loses relatime. In a user namespace, where atime flags are locked, the remount then fails with EPERM; outside one, it silently switches the mount to strictatime.

This PR spells out the ST_* values in the linux_raw backend, following the precedent of EXT4_IOC_RESIZE_FS, and adds two tests: one compares the constants with libc's on glibc, and one compares what statvfs reports for / and /proc with their /proc/self/mountinfo options. Both tests fail without the fix:

test statfs::test_statvfs_mount_flags_abi ... FAILED
  left: 2097152
 right: 4096
test statfs::test_statvfs_mount_flags_match_mountinfo ... FAILED
/: relatime in ["rw", "relatime"], statvfs says StatVfsMountFlags(0x1020)

All nine constants are written as ST_* values, not only RELATIME, so that none of them depends on an MS_* value happening to be equal.

Note: changing the value of a public constant is observable, but the old value of RELATIME never matched anything the kernel reports in this field, so no correct caller could have depended on it.

The linux_raw backend defined the `StatVfsMountFlags` constants with
the `MS_*` mount flag values, because linux-raw-sys has no `ST_*`
names. `statvfs` fills `f_flag` with the kernel's `statfs` `f_flags`
unconverted, and those are `ST_*` values. Most of the two sets agree,
but `ST_RELATIME` is 0x1000 while `MS_RELATIME` is 1 << 21, so
`f_flag.contains(StatVfsMountFlags::RELATIME)` was false on every
`relatime` mount, and the bit the kernel did set was left unnamed.

`f_flag` therefore could not tell a `relatime` mount from a strictatime
one. A caller that derives the atime mode from these flags (neither
`NOATIME` nor `RELATIME` means strictatime) and restates it in a bind
remount changed every `relatime` mount it touched to strictatime, or
got `EPERM` on a mount whose atime flags are locked, such as one
inherited by a less privileged mount namespace.

The `ST_*` values are not in the kernel's uapi headers, which
linux-raw-sys is generated from, so spell them out, as the libc backend
gets them from libc. Add a test that checks them against libc's on
glibc, and one that compares what `statvfs` reports for `/` and
`/proc` with the options in their `/proc/self/mountinfo` lines; both
fail without the fix.
The libc backend defines `StatVfsMountFlags::RELATIME` only where libc
has `ST_RELATIME` (Android and glibc), so the mountinfo test did not
compile for x86_64-unknown-linux-musl with use-libc. Compare the other
flags everywhere, and `RELATIME` where the constant exists.
@hiking90
hiking90 force-pushed the fix-statvfs-relatime branch from 853458a to 3628957 Compare October 3, 2026 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant