Skip to content

netbsd: Fix statvfs struct layout and add symbol versioning for NetBSD 10.x#5243

Open
fraggerfox wants to merge 3 commits into
rust-lang:mainfrom
fraggerfox:netbsd-statvfs-fix
Open

netbsd: Fix statvfs struct layout and add symbol versioning for NetBSD 10.x#5243
fraggerfox wants to merge 3 commits into
rust-lang:mainfrom
fraggerfox:netbsd-statvfs-fix

Conversation

@fraggerfox

@fraggerfox fraggerfox commented Jul 3, 2026

Copy link
Copy Markdown

Description

Fixes the statvfs structure layout and adds symbol versioning for NetBSD 10.x (and above) compatibility.

Note: AI assistance was used to discover the fixes as well as to test the fixes within a NetBSD environment.

NetBSD 10.0 changed the statvfs structure:

  • f_spare changed from [u32; 4] to [u64; 4]
  • Added f_mntfromlabel field (1024 bytes)
  • Total size increased from 2256 to 3296 bytes

Without explicit link_name attributes, Rust bindings resolve to compatibility wrappers (__compat_statvfs) that expect the old struct layout, causing data corruption even with the correct struct definition.

  • statvfs()__statvfs190
  • fstatvfs()__fstatvfs190
  • getmntinfo()__getmntinfo90

Note: This is a breaking change for NetBSD 9.x and earlier. Those versions use __statvfs90/__fstatvfs90 which return the old struct format without f_mntfromlabel. NetBSD 11 is expected to release later this year, making NetBSD 9.x increasingly obsolete.

https://endoflife.date/netbsd

Previous changes

1816f6061

This PR removed the deprecated symbol, which was previously added by @0-wiz-0 and tries to maintain compatibility from NetBSD 9.x and above.

The current PR, bumps compatibility for NetBSD 10.x and above.

Discovery

The problem with getmntinfo() was discovered when debugging why bottom was not populating the Disks panel correctly in NetBSD.

Sources

NetBSD statvfs structure definition:

NetBSD symbol versioning documentation:

Checklist

  • Relevant tests in libc-test/semver have been updated
    • No updates needed: statvfs/fstatvfs already in unix.txt, getmntinfo already in netbsd.txt
  • No placeholder or unstable values like *LAST or *MAX are included
  • Tested locally (cd libc-test && cargo test --target mytarget)
    • Tested on NetBSD 10.1 x86_64: CC=cc cargo test --target x86_64-unknown-netbsd --workspace
    • All 3 test configurations pass (4822 ctest verifications each)

@rustbot label +stable-nominated

cc: @0323pin

@0323pin

0323pin commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

LGTM
NetBSD-9 is living it's last days and I don't think we should stop this because of it. It's more important to support 10 and future versions of the OS.

@fraggerfox can you please add the stable-nominated flag to this PR so it gets added to the stable version of libc?
Thank you for working on this and thanks to @0-wiz-0 for reviewing.

@tgross35 tgross35 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please handwrite all PR descriptions and commit messages, there's no need to restate the diff and copy the C header. Do make sure to permalink the headers (currently statvfs.h is a regular link).

View changes since this review

Comment thread src/new/netbsd/sys/statvfs.rs Outdated
Comment on lines +38 to +39
// This type is updated in a future version
f_spare: [u32; 4],
__pad1: Padding<u32>,
pub f_spare: [u64; 4],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to make this public. Where does __pad1 come from?

@fraggerfox fraggerfox Jul 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the pub from f_spare.

Without the padding between f_owner and f_spare caused the Rust struct to be misaligned by 4 bytes, here is the output of the sample program that I used for testing (generated by AI)

=== STRUCT LAYOUT COMPARISON ===

WITH padding (correct):
  Total size:      3296 bytes
  f_owner offset:  152
  f_spare offset:  160
  Gap after owner: 4 bytes

WITHOUT padding (packed, wrong):
  Total size:      3292 bytes
  f_owner offset:  152
  f_spare offset:  156
  Gap after owner: 0 bytes

=== CALLING statvfs() WITH BOTH STRUCTS ===

CORRECT struct (with padding):
  f_fstypename:   'ffs'
  f_mntonname:    '/'
  f_mntfromname:  '/dev/ld0a'
  f_spare[0]:     0x0000000000000000

PACKED struct (without padding - WRONG):
  f_fstypename:   ''
  f_mntonname:    ''
  f_mntfromname:  ''
  f_spare[0]:     0x0000000000000000

The size of the struct when taken from a native C program matches 3296 bytes.

@fraggerfox fraggerfox Jul 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I will need to debug further to see why the CI is failing without the pub. will do that once I get a bit more free time.

Seems like a transient failure, @tgross35 can you help retrigger the CI?

  + /usr/sbin/pkg_add curl
  pkg_add: Can't process [http://cdn.NetBSD.org:80/pub/pkgsrc/packages/NetBSD/x86_64/10.1/All//curl*:](http://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/10.1/All//curl*:) 
  pkg_add: no pkg found for 'curl', sorry.
  pkg_add: 1 package addition failed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the padding between f_owner and f_spare caused the Rust struct to be misaligned by 4 bytes, here is the output of the sample program that I used for testing (generated by AI)

That doesn't really track - why would they be mismatched? There are no alignment attributes on either, so did another field change sizes or something?

Seems like a transient failure, @tgross35 can you help retrigger the CI?

* https://github.com/rust-lang/libc/actions/runs/28645611965/job/84951914997?pr=5243#step:5:243
  + /usr/sbin/pkg_add curl
  pkg_add: Can't process [http://cdn.NetBSD.org:80/pub/pkgsrc/packages/NetBSD/x86_64/10.1/All//curl*:](http://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/10.1/All//curl*:) 
  pkg_add: no pkg found for 'curl', sorry.
  pkg_add: 1 package addition failed

We hit this error all the time, I don't know why. @0323pin do you happen to have any ideas here?

@fraggerfox fraggerfox Jul 3, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the padding between f_owner and f_spare caused the Rust struct to be misaligned by 4 bytes, here is the output of the sample program that I used for testing (generated by AI)

That doesn't really track - why would they be mismatched? There are no alignment attributes on either, so did another field change sizes or something?

Nothing changed, this is definitely an alignment issue of the types in struct. My best guess is gcc is probably padding it in someway when generating the struct, hence the size mismatch between C and Rust. I am not too familiar with how gcc pads the struct (neither in Rust), but I can investigate and get back.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GCC doesn't insert padding out of nowhere, it uses the same layout calculations as rust with #[repr(C)]. If you just run libc-test without the padding it may give a hint.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tgross35 : Alright, let me run these tests in a NetBSD environment and get back to you.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tgross35 : I have removed the explict padding. It seems I had a bug in implementation for bottom that was reading the values wrongly (since I was using bottom as a test harness to check if libc changes were working).

I wrote an independent test directly calling statvfs struct and it seems to work, my mistake was the small test program I was working with was explicitly recreating the structs and checking if field was it was correct and there was a mistake in that approach.

TL;DR, I have removed the explicit padding, the CI also looks green, thank you @tgross35 for pushing me to check it correctly.

@tgross35 tgross35 Jul 4, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we aren't actually testing this type so CI should be green regardless :)

libc/libc-test/build.rs

Lines 1427 to 1428 in e98332b

// ABI change in NetBSD10, with symbol versioning.
"statvfs" if !netbsd9 => true,
.

If you're interested, I think you could move that from skip_struct to skip_struct_field and only exclude the fields that differ among versions so we test the rest. But do that in a separate PR preferably.

@rustbot

rustbot commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@tgross35

tgross35 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

I'm actually not sure we should do this; per https://doc.rust-lang.org/rustc/platform-support/netbsd.html we support down to 8.x in some cases.

@0323pin

0323pin commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

I'm actually not sure we should do this; per https://doc.rust-lang.org/rustc/platform-support/netbsd.html we support down to 8.x in some cases.

At any given moment in time, NetBSD only supports the current latest + latest-1. 8 is officially not supported anymore. Besides, Rust doesn't even build on 8.

9 will follow the same path as soon as 11 is released. But, do you @0-wiz-0 feel differently about it?

@fraggerfox

fraggerfox commented Jul 3, 2026

Copy link
Copy Markdown
Author

Please handwrite all PR descriptions and commit messages, there's no need to restate the diff and copy the C header. Do make sure to permalink the headers (currently statvfs.h is a regular link).

View changes since this review

This was handwritten, I put in stuff there for context, but I can always cut down on the content.

I put in the link to the trunk based on the examples given in the PR template. It has been changed it to the hashed one.

The reason I put in a verbose description is because I spent quite a lot of time tracking down the historical changes done for NetBSD previously for making this PR (tracking down the exact commit was not easy either)

The aim of the description was so that people in the future can find such a change done more easily.

@rustbot rustbot added the stable-nominated This PR should be considered for cherry-pick to libc's stable release branch label Jul 3, 2026
@fraggerfox fraggerfox force-pushed the netbsd-statvfs-fix branch from a7cbba5 to 81e85cd Compare July 3, 2026 08:07
@tgross35

tgross35 commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

I'm actually not sure we should do this; per https://doc.rust-lang.org/rustc/platform-support/netbsd.html we support down to 8.x in some cases.

At any given moment in time, NetBSD only supports the current latest + latest-1. 8 is officially not supported anymore. Besides, Rust doesn't even build on 8.

9 will follow the same path as soon as 11 is released. But, do you @0-wiz-0 feel differently about it?

The policy seems reasonable to me, would be good to update the platform docs to clarify N-1 is supported.

In that case though, we should hold off here right? If it was just the field changes I wouldn't be concerned, but the link name changes will cause link failures for anybody building on NetBSD 9.

It's also possible to do something like FreeBSD and add an unstable config to toggle things. We really need rust-lang/rfcs#3905...

@0323pin

0323pin commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

@tgross35

We hit this error all the time, I don't know why. @0323pin do you happen to have any ideas here?

Actually, I don't know ... curl is there.

Screenshot_20260703_191105_Opera Mini beta

@tgross35

tgross35 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

In case that's just how network errors show up, I'm going to try a retry with #5246.

@fraggerfox fraggerfox force-pushed the netbsd-statvfs-fix branch from 4d93348 to 3a033fb Compare July 4, 2026 09:43
@fraggerfox fraggerfox requested a review from tgross35 July 4, 2026 09:43
@fraggerfox fraggerfox marked this pull request as ready for review July 4, 2026 09:45
@rustbot

rustbot commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in a NetBSD-like module

cc @semarie

@tgross35

tgross35 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

This looks technically correct at this point, but it sounds like 9.x is still supported so I think we should hold off, given AIUI there isn't any rush. So for this to be ready I think we need:

  1. The 11.0 release, which should also come with the deprecation of 9.x
  2. An update to https://doc.rust-lang.org/nightly/rustc/platform-support/netbsd.html changing 9.x to 10.x, preferably also just stating a supported version policy

Seems like 11.0 is in RC so let's revisit in a couple months? Unless @0323pin you feel strongly that there's a reason to ship this now.

@rustbot blocked
@SnoozeThis wait 3 months -> remove label S-blocked, add label S-waiting-on-review

@SnoozeThis

Copy link
Copy Markdown

(https://snoozeth.is/wmRMPHBukiA) I will wait until Sun, 04 Oct 2026 10:20:42 UTC and then add label S-waiting-on-review and remove label S-blocked.

@rustbot claim.

@fraggerfox

Copy link
Copy Markdown
Author

This looks technically correct at this point, but it sounds like 9.x is still supported so I think we should hold off, given AIUI there isn't any rush. So for this to be ready I think we need:

Good to know and thank you!

1. The 11.0 release, which should also come with the deprecation of 9.x

2. An update to https://doc.rust-lang.org/nightly/rustc/platform-support/netbsd.html changing 9.x to 10.x, preferably also just stating a supported version policy

Seems like 11.0 is in RC so let's revisit in a couple months? Unless @0323pin you feel strongly that there's a reason to ship this now.

I am fine with maintaining this patch for now in the bottom package itself (in pkgsrc) until this is merged and a release is made.

@tgross35

tgross35 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

What exactly is the issue in bottom? I don't see getmntinfo or statvfs mentioned in the linked thread, does it just need the f_mntfromlabel field for some reason?

@fraggerfox

fraggerfox commented Jul 4, 2026

Copy link
Copy Markdown
Author

What exactly is the issue in bottom? I don't see getmntinfo or statvfs mentioned in the linked thread, does it just need the f_mntfromlabel field for some reason?

bottom uses sysinfo crate which uses the libc crate to call getmntinfo()

The f_mntfromlabel is not used, but f_mntfromname is needed so that the disk panel is populated correctly

  • Disks panel showing the correct values after the fixes.

    • image
  • Process panel showing the Reads / Writes per process level

    • image

@tgross35

tgross35 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

I'm still not sure I follow - f_mntfromname appears present in the initial addition of statvfs 23 years ago NetBSD/src@6bd1d6d#diff-190233bad1103409b2b5a94638ddb03aa71a0c6f3b84923668a56e8695a9eb87

@0323pin

0323pin commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

@tgross35

Unless @0323pin you feel strongly that there's a reason to ship this now.

I don't mind waiting but to me 9 is nearly dead and doesn't feel like a valid waiting reason. But, I still would like to have a second opinion on this. So, asking @0-wiz-0 once more 😉

@tgross35

tgross35 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

It's fine by me, especially since it looks like 9.0 is pretty old, but would prefer https://github.com/rust-lang/rust/blob/main/src/doc/rustc/src/platform-support/netbsd.md gets updated first. Usually that's where we point people if they have questions about what we try to support if there's ever any version confusion.

@fraggerfox

fraggerfox commented Jul 4, 2026

Copy link
Copy Markdown
Author

I'm still not sure I follow - f_mntfromname appears present in the initial addition of statvfs 23 years ago NetBSD/src@6bd1d6d#diff-190233bad1103409b2b5a94638ddb03aa71a0c6f3b84923668a56e8695a9eb87

The problem is not statvfs struct itself but the getmntinfo() call, in Rust the unversioned call results in invoking __compat_getmntinfo() which returns a different struct called statfs12

My understanding from @0-wiz-0 's explanation when were discussing this is, the __strong_alias(getmntinfo, __compat_getmntinfo) causes Rust to link to the __compat_getmntinfo (since Rust does not read C headers).

I am not sure if the explanation is sufficient and answers your question.

Note: I do not have much experience dealing with linkers, so most of my understanding is based on reading the code, so there may be mistakes

Changes:

1. Fixed statvfs struct in new API (src/new/netbsd/sys/statvfs.rs):
   - Changed f_spare from [u32; 4] to [u64; 4] (16 → 32 bytes)
   - Added Padding<u32> after f_owner for correct alignment
   - Added f_mntfromlabel field ([c_char; 1024])

2. Added symbol versioning for syscalls (src/unix/bsd/netbsdlike/netbsd/mod.rs):
   - Added __getmntinfo90 link_name for getmntinfo()

3. Added symbol versioning for syscalls (src/unix/mod.rs):
   - Added __statvfs190 link_name for statvfs()
   - Added __fstatvfs190 link_name for fstatvfs()
@fraggerfox fraggerfox force-pushed the netbsd-statvfs-fix branch from 3a033fb to 09a7d3b Compare July 4, 2026 15:07
@rustbot

rustbot commented Jul 4, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@tgross35

tgross35 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

The problem is not statvfs struct itself but the getmntinfo() call, in Rust the unversioned call results in invoking __compat_getmntinfo() which returns a different struct called statfs12

* https://github.com/NetBSD/src/blob/trunk/lib/libc/compat/gen/compat_getmntinfo.c
* https://github.com/NetBSD/src/blob/trunk/sys/compat/sys/mount.h#L43

My understanding from @0-wiz-0 's explanation when were discussing this is, the __strong_alias(getmntinfo, __compat_getmntinfo) causes Rust to link to the __compat_getmntinfo (since Rust does not read C headers).

Ah! That makes a lot more sense, thanks. How is anything using getmntinfo even working at all? It looks like f_bsize lines up but pretty much every other field is mismatched between statfs12 and statvfs90/statvfs.

Could you just link __getmntinfo13 here? That should be present in the 9.0 tree https://github.com/NetBSD/src/blob/bc7bd704f7c4458f83e06fa841ecf05c3b23a547/sys/sys/statvfs.h#L155 and the statvfs definition matches our current struct https://github.com/NetBSD/src/blob/bc7bd704f7c4458f83e06fa841ecf05c3b23a547/sys/sys/statvfs.h#L66. I think that would mean the completely broken stuff gets fixed without jumping all the way to __getmntinfo90 (the only benefit of which is f_mntfromlabel IIUC).

@fraggerfox

fraggerfox commented Jul 4, 2026

Copy link
Copy Markdown
Author

Ah! That makes a lot more sense, thanks. How is anything using getmntinfo even working at all? It looks like f_bsize lines up but pretty much every other field is mismatched between statfs12 and statvfs90/statvfs.

I am not sure how many consumers of that call are there in pkgsrc, and more importantly who all are using those packages 😅

Could you just link __getmntinfo13 here? That should be present in the 9.0 tree https://github.com/NetBSD/src/blob/bc7bd704f7c4458f83e06fa841ecf05c3b23a547/sys/sys/statvfs.h#L155 and the statvfs definition matches our current struct https://github.com/NetBSD/src/blob/bc7bd704f7c4458f83e06fa841ecf05c3b23a547/sys/sys/statvfs.h#L66. I think that would mean the completely broken stuff gets fixed without jumping all the way to __getmntinfo90 (the only benefit of which is f_mntfromlabel IIUC).

This was the change done by @0-wiz-0,

which got removed in this

  • 1816f6061 (because __getmntinfo13 has been marked as deprecated).

And then when discussing with @0323pin and @0-wiz-0 we came to the conclusion of sticking to the __getmntinfo90 call.

I could raise another one line change PR to restore the old linking to restore functionality to any existing consumers of this API in pkgsrc, until this PR is ready to merge. What do you think?

@tgross35

tgross35 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

which got removed in this

* [1816f6061](https://github.com/rust-lang/libc/commit/1816f6061) (because `__getmntinfo13` has been marked as deprecated).

That's my fault, I guess I misunderstood something about the comment at the time. Sorry about that, but I'd be happy to accept a change back __getmntinfo13 assuming that fixes things.

You can do that in a separate PR if you'd like and keep this one around to change to __getmntinfo90 once 11.0 is released.

@fraggerfox

Copy link
Copy Markdown
Author

which got removed in this

* [1816f6061](https://github.com/rust-lang/libc/commit/1816f6061) (because `__getmntinfo13` has been marked as deprecated).

That's my fault, I guess I misunderstood something about the comment at the time. Sorry about that, but I'd be happy to accept a change back __getmntinfo13 assuming that fixes things.

You can do that in a separate PR if you'd like and keep this one around to change to __getmntinfo90 once 11.0 is released.

Here you go #5251

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-blocked stable-nominated This PR should be considered for cherry-pick to libc's stable release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants