Bug 11810 - Wrong filesystem size reported to client (df)
Summary: Wrong filesystem size reported to client (df)
Alias: None
Product: Samba 4.1 and newer
Classification: Unclassified
Component: File services (show other bugs)
Version: 4.4.0
Hardware: All Solaris
: P5 normal (vote)
Target Milestone: ---
Assignee: Björn Jacke
QA Contact: Samba QA Contact
Depends on:
Reported: 2016-03-25 09:57 UTC by alexandre.lecuyer
Modified: 2019-01-11 09:45 UTC (History)
1 user (show)

See Also:

patch to add solaris_statvfs() (3.03 KB, patch)
2016-03-25 09:57 UTC, alexandre.lecuyer
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description alexandre.lecuyer 2016-03-25 09:57:32 UTC
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
//  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.
Comment 1 Björn Jacke 2019-01-07 02:11:09 UTC
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.
Comment 2 Björn Jacke 2019-01-07 11:24:36 UTC
the same name mixup of bsize and frsize in statvfs was taken over by FreeBSD and Darwin also. Arrg ...
Comment 3 Björn Jacke 2019-01-07 13:04:00 UTC
-- 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
Comment 4 Björn Jacke 2019-01-07 13:40:48 UTC
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

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;
Comment 5 Björn Jacke 2019-01-07 14:53:09 UTC
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.
Comment 6 Björn Jacke 2019-01-11 09:45:55 UTC
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