Provide the correct free block size volume/disk information (#4943)

On *NIX platforms the statfs(2) system call returns a struct containing both the
free blocks in the filesystem (Statfs_t.Bfree) and the free blocks available to
the unprivileged or non-superuser (Statfs_t.Bavail).

The `Bfree` and `Bavail` fields (with `Bfree >= Bavail`) will be set to
different values on e.g. filesystems such as ext4 that reserve a certain
percentage of the filesystem blocks which may only be allocated by admnistrative
privileged processes.

The calculations for the `Total` disk space need to subtract the difference
between the `Bfree` and `Bavail` fields for it to correctly show the total
available storage space available for unprivileged users.

This implicitly fixes a bug where the `Used = Total - Free` calculation yielded
different (and also incorrect) results for identical contents stored when only
the sizes of the disks or backing volumes differed. (as can be witnessed in the
`Used:` value displayed in the Minio browser)

See:
- https://wiki.archlinux.org/index.php/ext4#Reserved_blocks
- http://man7.org/linux/man-pages/man2/statfs.2.html
- https://man.openbsd.org/statfs
- http://lingrok.org/xref/coreutils/src/df.c#893
This commit is contained in:
Tamer Fahmy 2017-09-26 03:46:19 +02:00 committed by Dee Koder
parent d3eb5815d9
commit 0bf981278e
3 changed files with 24 additions and 18 deletions

View file

@ -29,11 +29,13 @@ func GetInfo(path string) (info Info, err error) {
if err != nil {
return Info{}, err
}
info = Info{}
info.Total = uint64(s.Bsize) * uint64(s.Blocks)
info.Free = uint64(s.Bsize) * uint64(s.Bavail)
info.Files = uint64(s.Files)
info.Ffree = uint64(s.Ffree)
info.FSType = getFSType(s.Fstypename)
fsReservedBlocks := uint64(s.Bfree) - uint64(s.Bavail)
info = Info{
Total: uint64(s.Bsize) * (uint64(s.Blocks) - fsReservedBlocks),
Free: uint64(s.Bsize) * uint64(s.Bavail),
Files: uint64(s.Files),
Ffree: uint64(s.Ffree),
FSType: getFSType(s.Fstypename),
}
return info, nil
}

View file

@ -29,11 +29,13 @@ func GetInfo(path string) (info Info, err error) {
if err != nil {
return Info{}, err
}
info = Info{}
info.Total = uint64(s.Bsize) * uint64(s.Blocks)
info.Free = uint64(s.Bsize) * uint64(s.Bavail)
info.Files = uint64(s.Files)
info.Ffree = uint64(s.Ffree)
info.FSType = getFSType(int64(s.Type))
fsReservedBlocks := uint64(s.Bfree) - uint64(s.Bavail)
info = Info{
Total: uint64(s.Bsize) * (uint64(s.Blocks) - fsReservedBlocks),
Free: uint64(s.Bsize) * uint64(s.Bavail),
Files: uint64(s.Files),
Ffree: uint64(s.Ffree),
FSType: getFSType(int64(s.Type)),
}
return info, nil
}

View file

@ -29,11 +29,13 @@ func GetInfo(path string) (info Info, err error) {
if err != nil {
return Info{}, err
}
info = Info{}
info.Total = uint64(s.F_bsize) * uint64(s.F_blocks)
info.Free = uint64(s.F_bsize) * uint64(s.F_bavail)
info.Files = uint64(s.F_files)
info.Ffree = uint64(s.F_ffree)
info.FSType = getFSType(s.F_fstypename)
fsReservedBlocks := uint64(s.F_bfree) - uint64(s.F_bavail)
info = Info{
Total: uint64(s.F_bsize) * (uint64(s.F_blocks) - fsReservedBlocks),
Free: uint64(s.F_bsize) * uint64(s.F_bavail),
Files: uint64(s.F_files),
Ffree: uint64(s.F_ffree),
FSType: getFSType(s.F_fstypename),
}
return info, nil
}