On Fri, Feb 14, 2025 at 07:34:51AM +0100, Martin Husemann wrote: > On Thu, Feb 13, 2025 at 11:13:07PM +0100, Thomas Klausner wrote: > > and versioned the statvfs syscall. I'm not sure how the syscall > > compatibility works, but rust's libc crate still has the old > > definition of the struct > > Where is that struct definition?
https://github.com/rust-lang/libc/blob/2258bf0fb96767bcffbe3ed09b29a31ee54b549b/src/unix/bsd/netbsdlike/netbsd/mod.rs#L853 > It seems to be wrong somehow. I tried your program on a powerpc machine > and get: > > Breakpoint 3, rust_getmntinfo::get_mount_points () at src/main.rs:20 > 20 let mut fs_infos: *mut libc::statvfs = std::ptr::null_mut(); > (gdb) n > 21 let count = unsafe { libc::getmntinfo(&mut fs_infos, > libc::MNT_WAIT) }; > (gdb) > 22 if count < 1 { > (gdb) p count > $1 = 7 > (gdb) p fs_infos[0] > $3 = libc::unix::bsd::netbsdlike::netbsd::statvfs {f_flag: 86016, f_bsize: > 4096, f_frsize: 32768, f_iosize: 116136549, f_blocks: 481244119186087439, > f_bfree: 124951791354018455, f_bavail: 184717953468299, f_bresvd: 20480, > f_files: 52110838204711, f_ffree: 1717990144, f_favail: 0, f_fresvd: > 788529152, f_syncreads: 0, f_syncwrites: 0, f_asyncreads: 0, f_asyncwrites: > 0, f_fsidx: libc::unix::bsd::fsid_t {__fsid_val: [0, > 0]}, f_fsid: 0, f_namemax: 0, f_owner: 0, f_spare: [0, 0, 0, 0], > f_fstypename: [ > 0 <repeats 18 times>, 47, 100, 101, 118, 47, 100, 107, 48, 0, 0, 0, 0, 0, > 0], f_mntonname: [ > 0 <repeats 77 times>, 7, 16, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0 > <repeats 18 times>, 139, 1, 0, > 1, 210, 139, 0, 0, 0, 0, 0, 0, 16, 0 <repeats 13 times>, 107, 101, 114, > 110, 102, 115, 0, 0, 0, 0, 0, > 0, 0, 0, 0, 0, 47, 107, 101, 114, 110, 0 <repeats 85 times>, 107, 101, > 114, 110, 102, 115, > 0 <repeats 86 times>, 16, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0 > <repeats 18 times>, 123, 2, 0, 0, > 107, 123, 0, 0, 0, 0, 0, 0, 16, 0 <repeats 13 times>, 112, 116, 121, 102, > 115, 0 <repeats 11 times>, > 47, 100, 101, 118, 47, 112, 116, 115, 0 <repeats 82 times>, 112, 116, > 121, 102, 115, > 0 <repeats 87 times>...], f_mntfromname: [0 <repeats 77 times>, 2, 0, 0, > 0, 0, 2, 0, 0, 0, 32, 0, 127, > 255, 255, 255, 127, 255, 255, 255, 96, 61, 106, 120, 21, 103, 253, 254, > 21, 86, 181, 164, 0, 0, 11, 5, > 0, 0, 7, 11, 0 <repeats 20 times>, 110, 102, 115, 0 <repeats 13 times>, > 47, 109, 112, 51, > 0 <repeats 86 times>, 101, 109, 109, 97, 115, 58, 47, 110, 111, 114, 97, > 105, 100, 47, 109, 112, 51, > 0 <repeats 74 times>, 2, 0, 0, 0, 0, 2, 0, 0, 0, 32, 0, 127, 255, 255, > 255, 127, 255, 255, 255, 96, > 61, 106, 120, 21, 103, 253, 254, 21, 86, 181, 164, 0, 0, 11, 6, 0, 0, 7, > 11, 0 <repeats 20 times>, > 110, 102, 115, 0 <repeats 13 times>, 47, 109, 110, 116, 0 <repeats 86 > times>, 101, 109, 109, 97, 115, > 58, 47, 110, 101, 108, 108...]} > (gdb) p sizeof(fs_infos[0].f_flag) > $5 = 4 > > Compare with: > > > df -G / > / (/dev/dk0 ): 32768 block size 4096 frag size > 116136549 total blocks 112048377 free blocks 106241550 available > 29092606 total files 28605079 free files a800 filesys id > ffs fstype 0x5000 flag 255 filename length > 0 owner 12151 syncwrites 2684 asyncwrites Yes, it's similarly broken on my system: (gdb) p fs_infos[0] $2 = libc::unix::bsd::netbsdlike::netbsd::statvfs {f_flag: 1342177281, f_bsize: 4096, f_frsize: 32768, f_iosize: 207559395, f_blocks: 152865344, f_bfree: 142487375, f_bavail: 52001278, f_bresvd: 50758388, f_files: 8293581891585, f_ffree: 0, f_favail: 20480, f_fresvd: 1819408, f_syncreads: 297679, f_syncwrites: 0, f_asyncreads: 7562854, f_asyncwrites: 0, f_fsidx: libc::unix::bsd::fsid_t {__fsid_val: [47, 0]}, f_fsid: 0, f_namemax: 0, f_owner: 0, f_spare: [0, 0, 0, 0], f_fstypename: [0 <repeats 32 times>], f_mntonname: [0 <repeats 14 times>, 47, 100, 101, 118, 47, 100, 107, 49, 0 <repeats 86 times>, 7, 0, 0, 16, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0 <repeats 39 times>, 1, -117, 0, 0, -117, -46, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0 <repeats 30 times>, 107, 101, 114, 110, 102, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 107, 101, 114, 110, 0 <repeats 85 times>, 107, 101, 114, 110, 102, 115, 0 <repeats 91 times>, 16, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, 0 <repeats 39 times>, 2, 123, 0, 0, 123, 107, 0 <repeats 11 times>, 16, 0 <repeats 30 times>, 112, 116, 121...], f_mntfromname: [0 <repeats 23 times>, 16, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, -43, -17, 23, 0, 0, 0, 0, 0, -43, -17, 23, 0, 0, 0, 0, 0, 3, 0, 96, 0, 0, 0, 0, 0, 116, -1, 95, 0, 0, 0, 0, 0, 4, -85, 0, 0, -85, 105, 0 <repeats 11 times>, 16, 0 <repeats 30 times>, 116, 109, 112, 102, 115, 0 <repeats 11 times>, 47, 116, 109, 112, 0 <repeats 86 times>, 116, 109, 112, 102, 115, 0 <repeats 92 times>, 16, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 22, -29, 50, 0, 0, 0, 0, 0, 22, -29, 50, 0, 0, 0, 0, 0, 22, -29, 50, 0, 0, 0, 0, 0, 93, -116, -53, 0, 0, 0, 0, 0, 92, -116, -53, 0, 0...]} > df -G / / (/dev/dk1 ): 32768 block size 4096 frag size 207559395 total blocks 152865277 free blocks 142487308 available 52001278 total files 50758387 free files a801 filesys id ffs fstype 0x5000 flag 255 filename length 0 owner 1819515 syncwrites 299458 asyncwrites > Nearly all fields are wrong or swapped with others (like f_bsize <-> > f_frsize) and the f_mntonname field starts 18 bytes early (mountname > should be /dev/dk0, aka 47, 100, 101, 118, 47, 100, 107, 48, 0) > > It would be good to compare with a C version calling __getvfsstat90 > explicitly (e.g. via syscall()) or a static binary with debug info > compiled on netbsd-9, so we can find out if the error is in the compat > code or the C structure mapping in rust. I've tried running this in qemu yesterday, but qemu just hung my machine. How does one use syscall? > The kernel compat part works by calling do_sys_getvfsstat() with entry_sz = > sizeof (struct statvfs) and copyfn = copyout. This just copies mnt_stat > from each mountpoint out to userland (in the not-chrooted case). I see > no kind of translation happen anywhere here. I found lib/libc/compat/gen/compat___getmntinfo13.c which calls __compat_getvfsstat and ./lib/libc/compat/gen/compat_getmntinfo.c which calls __compat_getfsstat (no 'v'). So perhaps rust gets the even older getmntinfo which provides statfs (no 'v') information? Perhaps we need to add code like FreeBSD has (to rust libc): https://github.com/rust-lang/libc/blob/2258bf0fb96767bcffbe3ed09b29a31ee54b549b/src/unix/bsd/freebsdlike/freebsd/mod.rs#L5340 #[cfg_attr( all(target_os = "freebsd", freebsd11), link_name = "getmntinfo@FBSD_1.0" )] pub fn getmntinfo(mntbufp: *mut *mut crate::statfs, mode: c_int) -> c_int; to use the proper version of getmntinfo, the one with the first version of statvfs. What name would that be now, '__getmntinfo13'? Thomas