Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: getmntinfo compatibility question



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


Home | Main Index | Thread Index | Old Index