Add Filesystem::statx() for FUSE_STATX - #746
Merged
Merged
Conversation
The kernel sends FUSE_STATX for statx(2) once the connection is at ABI 7.38 or above, falling back to FUSE_GETATTR when the filesystem answers ENOSYS - which it takes as permanent, as it does for the other opcodes added this way. What the opcode is worth implementing for is the creation time. fuse_attr has a field for it on macOS alone, so on Linux there has been no way for a filesystem to report one, and statx(2) answers with whatever the kernel last cached. StatxAttr carries it as an Option, and the reply's mask is derived from what was actually filled in rather than supplied by the caller, so it cannot claim a field that is not there. StatxAttr also carries the STATX_ATTR_* properties - immutable, append-only and the rest - because the wire format has a field for them. The kernel does not use it: fuse_do_statx() copies the mask, the creation time and the basic stats out of the reply and ignores the attributes, so setting them does not make chattr +i visible to statx(2). That is worth having anyway, since a filesystem that fills the field is correct today and needs no change if the kernel starts reading it, but it is documented on the field, in the CHANGELOG, and pinned by the test, so that nobody implements it expecting otherwise. The integration test goes through statx(2) itself rather than asserting against the encoding, which is what showed the attributes being dropped. It also asserts the drop, so a kernel that starts honoring the field fails the test rather than silently outdating the documentation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4hiZwHE9fEYdn7DK3ZrV2
cberner
force-pushed
the
claude/xfstests-skip-investigation-s9gdr1
branch
from
August 5, 2026 01:38
99a94fe to
2b64265
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The kernel sends
FUSE_STATXforstatx(2)once the connection is at ABI 7.38 orabove, and falls back to
FUSE_GETATTRwhen the filesystem answersENOSYS-which it takes as permanent, the same way it does for
tmpfile()andsyncfs().What it is worth implementing for
The creation time.
fuse_attrhas a field for it on macOS alone, so on Linuxthere has been no way for a filesystem to report one and
statx(2)answers withwhatever the kernel last cached.
StatxAttrcarries it as anOption<SystemTime>, and the reply'sstx_maskisderived from what was actually filled in rather than supplied by the caller, so
it cannot claim a field that is not there.
What it is not worth implementing for
I went in expecting this to make
chattr +ivisible tostatx(2), which wouldhave let generic/424 run. It does not, and the reason is worth recording since
the wire format suggests otherwise.
struct fuse_statxhas anattributesfield carrying theSTATX_ATTR_*bits,and this PR fills and sends it. The kernel ignores it.
fuse_do_statx()copiesthe mask, the creation time and the basic stats out of the reply and nothing
else:
Measured before it was read, by setting
IMMUTABLE | APPENDin a test filesystemand calling
statx(2)against it:The creation time arrives; the attributes do not, and
stx_attributes_maskholdsonly the VFS's own
MOUNT_ROOT | AUTOMOUNT | DAX. Sincebtimesits at offset 80of the struct and
sizeat 40, and both arrive intact, this is the kerneldiscarding the field rather than a layout mistake on this side.
The field is kept and sent regardless: a filesystem that fills it is correct today
and needs no change if the kernel starts reading it. But it is documented as
inert on the field itself, in the CHANGELOG, and pinned by the test, so nobody
implements it expecting
chattr +ito show up.Testing
FUSE_STATXrequest, for bothendiannesses, covering the file handle being present and absent.
statx(2)for real,asserting the creation time survives the round trip and that the request
reaches
statx()rather than falling back togetattr(). It also asserts theattributes are dropped, so a kernel that starts honoring them fails here rather
than silently outdating the documentation. Skipped below 7.38, as the tmpfile
test is below 7.37.
/dev/nulland/dev/fuseasstatreports them plus a minor number too large for its lowbyte, since
struct statxwants a major/minor pair wherefuse_attrcarriesthe encoded number.
cargo test --allis 104 passed, 1 failed -mnt::test::mount_unmount_auto_unmount,which fails the same way on unmodified master here for want of a
fusermount3binary. Clippy clean with
--deny warnings, andcargo check --target x86_64-apple-darwin --features=macos-no-mountclean, whichcaught two things: a version constant that is only needed by the tests, and
nix::sys::stat::major/minornot existing on macOS - replaced with thekernel's own
new_decode_dev()split.🤖 Generated with Claude Code
https://claude.ai/code/session_01Q4hiZwHE9fEYdn7DK3ZrV2
Generated by Claude Code