Created attachment 11939 [details] patch to add solaris_statvfs() We run samba on solaris or similar (illumos). When mounting a share on a linux client, the filesystem size as reported by "df" is wrong : Server side : Filesystem Size Used Available Capacity Mounted on testpool/test 10G 96K 10G 1% /testpool/test Client side (size is wrong ): Filesystem Size Used Avail Use% Mounted on //10.6.2.4/testpool_test 2.5T 24M 2.5T 1% /cifs We see this difference in the statvfs() syscall result : Server side : f_blocks: 20971520 f_frsize: 512 f_bsize: 131072 Client side : f_blocks: 20971520 f_frsize: 131072 f_bsize: 131072 f_bsize is the "preferred file system block size". It is populated with the value of ZFS's recordsize, which in this example is 128k (default value). f_frsize is the supported block size, 512 bytes. (other filesystems have the same values for bsize and frsize, and there is no issue in this case) Now on the samba side, sys_statvfs will be either linux_statvfs or bsd_statvfs, detected at ./configure time. On solaris, samba will use linux_statvfs because solaris statvfs struct lacks f_iosize. linux_statvfs does this : statbuf->OptimalTransferSize = statvfs_buf.f_frsize; statbuf->BlockSize = statvfs_buf.f_bsize; Which does not match the manpage definition on solaris. BlockSize should be made equal to f_frsize, not f_bsize. Recompiling with this change fixes the problem. I attach a patch that adds a solaris_statvfs() method. If it is not the correct approach, I'll be happy to modify it or test any other change.
It is very confusing that the definitions of bsize and frsize are the other way round on Solaris. It actually turns out that the kernel view and the syscall view are defined differently there, which leads to this funny output that you get on a Solaris 10 box: # grep "fundamental file system block size" /usr/include/sys/statvfs.h unsigned long f_bsize; /* fundamental file system block size */ uint32_t f_bsize; /* fundamental file system block size */ unsigned long f_frsize; /* fundamental file system block size */ uint32_t f_frsize; /* fundamental file system block size */ No comment. I think in this case we should actually use a ifdef SOLARIS (even if we hate this) because the alternative way of checking for f_fstr to decide if we mix them up the same way might break other platforms in the future.
the same name mixup of bsize and frsize in statvfs was taken over by FreeBSD and Darwin also. Arrg ...
-- Darwin mixed up: f_frsize The size in bytes of the minimum unit of allocation on this file system. (This corresponds to the f_bsize mem-ber member ber of struct statfs.) f_bsize The preferred length of I/O requests for files on this file system. (Corresponds to the f_iosize member of struct statfs.) -- Tru64 is mixed up also: unsigned long f_bsize; /* prefered file system block size */ unsigned long f_frsize; /* fundamental file system block size */ - AIX is mixed up also: ulong_t f_bsize; /* preferred file system block size */ ulong_t f_frsize; /* fundamental file system block size */ -- NetBSD is more like Linux again unsigned long f_bsize; /* system block size */ unsigned long f_frsize; /* system fragment size */ -- Linux unsigned long f_bsize; /* Filesystem block size */ unsigned long f_frsize; /* Fragment size */ I would like to test what they acually return but on Linux all the filesystems return 4096 for f_bsize and f_frsize. I will send a patch for BSD to reverse the assginment of f_bsize and f_iosize. We need to figure out if the Linux/glibc implementation is really different. My guess is that it's just bad documented but also reverse. I tend to say that we need to reverse
okay, bsd_statvfs is using statfs which doesn't have that naming confusion. For glibc finally it really looks like statfs f_bsize is the same as statvfs f_bsize, which would not be nice looking at sysdeps/unix/sysv/linux/internal_statvfs.c --snip-- INTERNAL_STATVFS (const char *name, struct STATVFS *buf, struct STATFS *fsbuf, int fd) { /* Now fill in the fields we have information for. */ buf->f_bsize = fsbuf->f_bsize; /* Linux has the f_frsize size only in later version of the kernel. If the value is not filled in use f_bsize. */ buf->f_frsize = fsbuf->f_frsize ?: fsbuf->f_bsize; --snap--
in glibc also the statfs members have different meanings than in all the other UNIX flavours: from STATFS(2): f_bsize; /* Optimal transfer block size */ (this is f_iosize in all the other UNIX flavours) and that that is f_bsize in other UNIX flavours does not exist in glibc.
the usage of the right bsize/frsize is now fixed in master with d7d3ee18a5979168b6cab42d692eb39fa5d44154 and will be in 4.10. For clarification of the glibc implementation and Linux statvfs documentation I filed https://sourceware.org/bugzilla/show_bug.cgi?id=24087