OP#792 initial commit after fork

This commit is contained in:
2026-09-27 11:03:48 +02:00
parent 1fc33f4f1f
commit 55b0890196
1338 changed files with 428609 additions and 57 deletions

View File

@@ -0,0 +1,47 @@
//go:build darwin
// Copyright (c) 2015-2023 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"os"
"github.com/ncw/directio"
"golang.org/x/sys/unix"
)
// ODirectPlatform indicates if the platform supports O_DIRECT
const ODirectPlatform = true
// OpenFileDirectIO - bypass kernel cache.
func OpenFileDirectIO(filePath string, flag int, perm os.FileMode) (*os.File, error) {
return directio.OpenFile(filePath, flag, perm)
}
// DisableDirectIO - disables directio mode.
func DisableDirectIO(f *os.File) error {
fd := f.Fd()
_, err := unix.FcntlInt(fd, unix.F_NOCACHE, 0)
return err
}
// AlignedBlock - pass through to directio implementation.
func AlignedBlock(blockSize int) []byte {
return directio.AlignedBlock(blockSize)
}

View File

@@ -0,0 +1,54 @@
//go:build !windows && !darwin && !openbsd && !plan9
// +build !windows,!darwin,!openbsd,!plan9
// Copyright (c) 2015-2023 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"os"
"syscall"
"github.com/ncw/directio"
"golang.org/x/sys/unix"
)
// ODirectPlatform indicates if the platform supports O_DIRECT
const ODirectPlatform = true
// OpenFileDirectIO - bypass kernel cache.
func OpenFileDirectIO(filePath string, flag int, perm os.FileMode) (*os.File, error) {
return directio.OpenFile(filePath, flag, perm)
}
// DisableDirectIO - disables directio mode.
func DisableDirectIO(f *os.File) error {
fd := f.Fd()
flag, err := unix.FcntlInt(fd, unix.F_GETFL, 0)
if err != nil {
return err
}
flag &= ^(syscall.O_DIRECT)
_, err = unix.FcntlInt(fd, unix.F_SETFL, flag)
return err
}
// AlignedBlock - pass through to directio implementation.
func AlignedBlock(blockSize int) []byte {
return directio.AlignedBlock(blockSize)
}

View File

@@ -0,0 +1,68 @@
//go:build windows || openbsd || plan9
// Copyright (c) 2015-2023 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"os"
)
// ODirectPlatform indicates if the platform supports O_DIRECT
const ODirectPlatform = false
// OpenBSD, Windows, and illumos do not support O_DIRECT.
// On Windows there is no documentation on disabling O_DIRECT.
// For these systems we do not attempt to build the 'directio' dependency since
// the O_DIRECT symbol may not be exposed resulting in a failed build.
//
//
// On illumos an explicit O_DIRECT flag is not necessary for two primary
// reasons. Note that ZFS is effectively the default filesystem on illumos
// systems.
//
// One benefit of using DirectIO on Linux is that the page cache will not be
// polluted with single-access data. The ZFS read cache (ARC) is scan-resistant
// so there is no risk of polluting the entire cache with data accessed once.
// Another goal of DirectIO is to minimize the mutation of data by the kernel
// before issuing IO to underlying devices. ZFS users often enable features like
// compression and checksumming which currently necessitates mutating data in
// the kernel.
//
// DirectIO semantics for a filesystem like ZFS would be quite different than
// the semantics on filesystems like XFS, and these semantics are not
// implemented at this time.
// For more information on why typical DirectIO semantics do not apply to ZFS
// see this ZFS-on-Linux commit message:
// https://github.com/openzfs/zfs/commit/a584ef26053065f486d46a7335bea222cb03eeea
// OpenFileDirectIO wrapper around os.OpenFile nothing special
func OpenFileDirectIO(filePath string, flag int, perm os.FileMode) (*os.File, error) {
return os.OpenFile(filePath, flag, perm)
}
// DisableDirectIO is a no-op
func DisableDirectIO(f *os.File) error {
return nil
}
// AlignedBlock simply returns an unaligned buffer
// for systems that do not support DirectIO.
func AlignedBlock(blockSize int) []byte {
return make([]byte, blockSize)
}

62
internal/disk/disk.go Normal file
View File

@@ -0,0 +1,62 @@
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
// Info stat fs struct is container which holds following values
// Total - total size of the volume / disk
// Free - free size of the volume / disk
// Files - total inodes available
// Ffree - free inodes available
// FSType - file system type
// Major - major dev id
// Minor - minor dev id
// Devname - device name
type Info struct {
Total uint64
Free uint64
Used uint64
Files uint64
Ffree uint64
FSType string
Major uint32
Minor uint32
Name string
Rotational *bool
NRRequests uint64
}
// IOStats contains stats of a single drive
type IOStats struct {
ReadIOs uint64
ReadMerges uint64
ReadSectors uint64
ReadTicks uint64
WriteIOs uint64
WriteMerges uint64
WriteSectors uint64
WriteTicks uint64
CurrentIOs uint64
TotalTicks uint64
ReqTicks uint64
DiscardIOs uint64
DiscardMerges uint64
DiscardSectors uint64
DiscardTicks uint64
FlushIOs uint64
FlushTicks uint64
}

View File

@@ -0,0 +1,38 @@
//go:build !netbsd && !solaris
// +build !netbsd,!solaris
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk_test
import (
"testing"
"github.com/minio/minio/internal/disk"
)
func TestFree(t *testing.T) {
di, err := disk.GetInfo(t.TempDir(), true)
if err != nil {
t.Fatal(err)
}
if di.FSType == "UNKNOWN" {
t.Error("Unexpected FSType", di.FSType)
}
}

View File

@@ -0,0 +1,41 @@
//go:build !windows
// +build !windows
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"syscall"
)
// SameDisk reports whether di1 and di2 describe the same disk.
func SameDisk(disk1, disk2 string) (bool, error) {
st1 := syscall.Stat_t{}
st2 := syscall.Stat_t{}
if err := syscall.Stat(disk1, &st1); err != nil {
return false, err
}
if err := syscall.Stat(disk2, &st2); err != nil {
return false, err
}
return st1.Dev == st2.Dev, nil
}

View File

@@ -0,0 +1,26 @@
//go:build windows
// +build windows
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
// SameDisk reports whether di1 and di2 describe the same disk.
func SameDisk(disk1, disk2 string) (bool, error) {
return false, nil
}

View File

@@ -0,0 +1,47 @@
//go:build linux
// +build linux
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"os"
"syscall"
"golang.org/x/sys/unix"
)
// Fdatasync - fdatasync() is similar to fsync(), but does not flush modified metadata
// unless that metadata is needed in order to allow a subsequent data retrieval
// to be correctly handled. For example, changes to st_atime or st_mtime
// (respectively, time of last access and time of last modification; see inode(7))
// do not require flushing because they are not necessary for a subsequent data
// read to be handled correctly. On the other hand, a change to the file size
// (st_size, as made by say ftruncate(2)), would require a metadata flush.
//
// The aim of fdatasync() is to reduce disk activity for applications that
// do not require all metadata to be synchronized with the disk.
func Fdatasync(f *os.File) error {
return syscall.Fdatasync(int(f.Fd()))
}
// FadviseDontNeed invalidates page-cache
func FadviseDontNeed(f *os.File) error {
return unix.Fadvise(int(f.Fd()), 0, 0, unix.FADV_DONTNEED)
}

View File

@@ -0,0 +1,36 @@
//go:build freebsd || netbsd || openbsd || darwin
// +build freebsd netbsd openbsd darwin
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"os"
"syscall"
)
// Fdatasync is fsync on freebsd/darwin
func Fdatasync(f *os.File) error {
return syscall.Fsync(int(f.Fd()))
}
// FadviseDontNeed is a no-op
func FadviseDontNeed(f *os.File) error {
return nil
}

View File

@@ -0,0 +1,35 @@
//go:build !linux && !netbsd && !freebsd && !darwin && !openbsd
// +build !linux,!netbsd,!freebsd,!darwin,!openbsd
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"os"
)
// Fdatasync is a no-op
func Fdatasync(f *os.File) error {
return nil
}
// FadviseDontNeed is a no-op
func FadviseDontNeed(f *os.File) error {
return nil
}

View File

@@ -0,0 +1,29 @@
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import "runtime"
// IsRootDisk returns if diskPath belongs to root-disk, i.e the disk mounted at "/"
func IsRootDisk(diskPath string, rootDisk string) (bool, error) {
if runtime.GOOS == "windows" {
// On windows this function is not implemented.
return false, nil
}
return SameDisk(diskPath, rootDisk)
}

54
internal/disk/stat_bsd.go Normal file
View File

@@ -0,0 +1,54 @@
//go:build darwin || dragonfly
// +build darwin dragonfly
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"errors"
"fmt"
"syscall"
)
// GetInfo returns total and free bytes available in a directory, e.g. `/`.
func GetInfo(path string, _ bool) (info Info, err error) {
s := syscall.Statfs_t{}
err = syscall.Statfs(path, &s)
if err != nil {
return Info{}, err
}
reservedBlocks := s.Bfree - s.Bavail
info = Info{
Total: uint64(s.Bsize) * (s.Blocks - reservedBlocks),
Free: uint64(s.Bsize) * s.Bavail,
Files: s.Files,
Ffree: s.Ffree,
FSType: getFSType(s.Fstypename[:]),
}
if info.Free > info.Total {
return info, fmt.Errorf("detected free space (%d) > total drive space (%d), fs corruption at (%s). please run 'fsck'", info.Free, info.Total, path)
}
info.Used = info.Total - info.Free
return info, nil
}
// GetDriveStats returns IO stats of the drive by its major:minor
func GetDriveStats(major, minor uint32) (iostats IOStats, err error) {
return IOStats{}, errors.New("operation unsupported")
}

View File

@@ -0,0 +1,54 @@
//go:build freebsd
// +build freebsd
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"errors"
"fmt"
"syscall"
)
// GetInfo returns total and free bytes available in a directory, e.g. `/`.
func GetInfo(path string, _ bool) (info Info, err error) {
s := syscall.Statfs_t{}
err = syscall.Statfs(path, &s)
if err != nil {
return Info{}, err
}
reservedBlocks := s.Bfree - uint64(s.Bavail)
info = Info{
Total: uint64(s.Bsize) * (s.Blocks - reservedBlocks),
Free: uint64(s.Bsize) * uint64(s.Bavail),
Files: s.Files,
Ffree: uint64(s.Ffree),
FSType: getFSType(s.Fstypename[:]),
}
if info.Free > info.Total {
return info, fmt.Errorf("detected free space (%d) > total drive space (%d), fs corruption at (%s). please run 'fsck'", info.Free, info.Total, path)
}
info.Used = info.Total - info.Free
return info, nil
}
// GetDriveStats returns IO stats of the drive by its major:minor
func GetDriveStats(major, minor uint32) (iostats IOStats, err error) {
return IOStats{}, errors.New("operation unsupported")
}

173
internal/disk/stat_linux.go Normal file
View File

@@ -0,0 +1,173 @@
//go:build linux && !s390x && !arm && !386
// +build linux,!s390x,!arm,!386
// Copyright (c) 2015-2023 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"bufio"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/prometheus/procfs/blockdevice"
"golang.org/x/sys/unix"
)
// GetInfo returns total and free bytes available in a directory, e.g. `/`.
func GetInfo(path string, firstTime bool) (info Info, err error) {
s := syscall.Statfs_t{}
err = syscall.Statfs(path, &s)
if err != nil {
return Info{}, err
}
reservedBlocks := s.Bfree - s.Bavail
info = Info{
Total: uint64(s.Frsize) * (s.Blocks - reservedBlocks),
Free: uint64(s.Frsize) * s.Bavail,
Files: s.Files,
Ffree: s.Ffree,
//nolint:unconvert
FSType: getFSType(int64(s.Type)),
}
st := syscall.Stat_t{}
err = syscall.Stat(path, &st)
if err != nil {
return Info{}, err
}
//nolint:unconvert
devID := uint64(st.Dev) // Needed to support multiple GOARCHs
info.Major = unix.Major(devID)
info.Minor = unix.Minor(devID)
// Check for overflows.
// https://github.com/minio/minio/issues/8035
// XFS can show wrong values at times error out
// in such scenarios.
if info.Free > info.Total {
return info, fmt.Errorf("detected free space (%d) > total drive space (%d), fs corruption at (%s). please run 'fsck'", info.Free, info.Total, path)
}
info.Used = info.Total - info.Free
if firstTime {
bfs, err := blockdevice.NewDefaultFS()
if err == nil {
devName := ""
diskstats, _ := bfs.ProcDiskstats()
for _, dstat := range diskstats {
// ignore all loop devices
if strings.HasPrefix(dstat.DeviceName, "loop") {
continue
}
if dstat.MajorNumber == info.Major && dstat.MinorNumber == info.Minor {
devName = dstat.DeviceName
break
}
}
if devName != "" {
info.Name = devName
qst, err := bfs.SysBlockDeviceQueueStats(devName)
if err != nil { // Mostly not found error
// Check if there is a parent device:
// e.g. if the mount is based on /dev/nvme0n1p1, let's calculate the
// real device name (nvme0n1) to get its sysfs information
parentDevPath, e := os.Readlink("/sys/class/block/" + devName)
if e == nil {
parentDev := filepath.Base(filepath.Dir(parentDevPath))
qst, err = bfs.SysBlockDeviceQueueStats(parentDev)
}
}
if err == nil {
info.NRRequests = qst.NRRequests
rot := qst.Rotational == 1 // Rotational is '1' if the device is HDD
info.Rotational = &rot
}
}
}
}
return info, nil
}
// GetDriveStats returns IO stats of the drive by its major:minor
func GetDriveStats(major, minor uint32) (iostats IOStats, err error) {
return readDriveStats(fmt.Sprintf("/sys/dev/block/%v:%v/stat", major, minor))
}
func readDriveStats(statsFile string) (iostats IOStats, err error) {
stats, err := readStat(statsFile)
if err != nil {
return IOStats{}, err
}
if len(stats) < 11 {
return IOStats{}, fmt.Errorf("found invalid format while reading %v", statsFile)
}
// refer https://www.kernel.org/doc/Documentation/block/stat.txt
iostats = IOStats{
ReadIOs: stats[0],
ReadMerges: stats[1],
ReadSectors: stats[2],
ReadTicks: stats[3],
WriteIOs: stats[4],
WriteMerges: stats[5],
WriteSectors: stats[6],
WriteTicks: stats[7],
CurrentIOs: stats[8],
TotalTicks: stats[9],
ReqTicks: stats[10],
}
// as per the doc, only 11 fields are guaranteed
// only set if available
if len(stats) > 14 {
iostats.DiscardIOs = stats[11]
iostats.DiscardMerges = stats[12]
iostats.DiscardSectors = stats[13]
iostats.DiscardTicks = stats[14]
}
return iostats, err
}
func readStat(fileName string) (stats []uint64, err error) {
file, err := os.Open(fileName)
if err != nil {
return nil, err
}
defer file.Close()
s, err := bufio.NewReader(file).ReadString('\n')
if err != nil && !errors.Is(err, io.EOF) {
return nil, err
}
statLine := strings.TrimSpace(s)
for _, token := range strings.Fields(statLine) {
ui64, err := strconv.ParseUint(token, 10, 64)
if err != nil {
return nil, err
}
stats = append(stats, ui64)
}
return stats, nil
}

View File

@@ -0,0 +1,89 @@
//go:build (linux && arm) || (linux && 386)
// +build linux,arm linux,386
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"errors"
"fmt"
"strconv"
"syscall"
)
// fsType2StringMap - list of filesystems supported on linux
var fsType2StringMap = map[string]string{
"1021994": "TMPFS",
"137d": "EXT",
"4244": "HFS",
"4d44": "MSDOS",
"52654973": "REISERFS",
"5346544e": "NTFS",
"58465342": "XFS",
"61756673": "AUFS",
"6969": "NFS",
"ef51": "EXT2OLD",
"ef53": "EXT4",
"f15f": "ecryptfs",
"794c7630": "overlayfs",
"2fc12fc1": "zfs",
"ff534d42": "cifs",
"53464846": "wslfs",
}
// getFSType returns the filesystem type of the underlying mounted filesystem
func getFSType(ftype int32) string {
fsTypeHex := strconv.FormatInt(int64(ftype), 16)
fsTypeString, ok := fsType2StringMap[fsTypeHex]
if !ok {
return "UNKNOWN"
}
return fsTypeString
}
// GetInfo returns total and free bytes available in a directory, e.g. `/`.
func GetInfo(path string, _ bool) (info Info, err error) {
s := syscall.Statfs_t{}
err = syscall.Statfs(path, &s)
if err != nil {
return Info{}, err
}
reservedBlocks := s.Bfree - s.Bavail
info = Info{
Total: uint64(s.Frsize) * (s.Blocks - reservedBlocks),
Free: uint64(s.Frsize) * s.Bavail,
Files: s.Files,
Ffree: s.Ffree,
FSType: getFSType(s.Type),
}
// Check for overflows.
// https://github.com/minio/minio/issues/8035
// XFS can show wrong values at times error out
// in such scenarios.
if info.Free > info.Total {
return info, fmt.Errorf("detected free space (%d) > total drive space (%d), fs corruption at (%s). please run 'fsck'", info.Free, info.Total, path)
}
info.Used = info.Total - info.Free
return info, nil
}
// GetDriveStats returns IO stats of the drive by its major:minor
func GetDriveStats(major, minor uint32) (iostats IOStats, err error) {
return IOStats{}, errors.New("operation unsupported")
}

View File

@@ -0,0 +1,89 @@
//go:build linux && s390x
// +build linux,s390x
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"errors"
"fmt"
"strconv"
"syscall"
)
// fsType2StringMap - list of filesystems supported on linux
var fsType2StringMap = map[string]string{
"1021994": "TMPFS",
"137d": "EXT",
"4244": "HFS",
"4d44": "MSDOS",
"52654973": "REISERFS",
"5346544e": "NTFS",
"58465342": "XFS",
"61756673": "AUFS",
"6969": "NFS",
"ef51": "EXT2OLD",
"ef53": "EXT4",
"f15f": "ecryptfs",
"794c7630": "overlayfs",
"2fc12fc1": "zfs",
"ff534d42": "cifs",
"53464846": "wslfs",
}
// getFSType returns the filesystem type of the underlying mounted filesystem
func getFSType(ftype uint32) string {
fsTypeHex := strconv.FormatUint(uint64(ftype), 16)
fsTypeString, ok := fsType2StringMap[fsTypeHex]
if !ok {
return "UNKNOWN"
}
return fsTypeString
}
// GetInfo returns total and free bytes available in a directory, e.g. `/`.
func GetInfo(path string, _ bool) (info Info, err error) {
s := syscall.Statfs_t{}
err = syscall.Statfs(path, &s)
if err != nil {
return Info{}, err
}
reservedBlocks := s.Bfree - s.Bavail
info = Info{
Total: uint64(s.Frsize) * (s.Blocks - reservedBlocks),
Free: uint64(s.Frsize) * s.Bavail,
Files: s.Files,
Ffree: s.Ffree,
FSType: getFSType(s.Type),
}
// Check for overflows.
// https://github.com/minio/minio/issues/8035
// XFS can show wrong values at times error out
// in such scenarios.
if info.Free > info.Total {
return info, fmt.Errorf("detected free space (%d) > total drive space (%d), fs corruption at (%s). please run 'fsck'", info.Free, info.Total, path)
}
info.Used = info.Total - info.Free
return info, nil
}
// GetDriveStats returns IO stats of the drive by its major:minor
func GetDriveStats(major, minor uint32) (iostats IOStats, err error) {
return IOStats{}, errors.New("operation unsupported")
}

View File

@@ -0,0 +1,54 @@
//go:build netbsd
// +build netbsd
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"errors"
"fmt"
"golang.org/x/sys/unix"
)
// GetInfo returns total and free bytes available in a directory, e.g. `/`.
func GetInfo(path string, _ bool) (info Info, err error) {
s := unix.Statvfs_t{}
if err = unix.Statvfs(path, &s); err != nil {
return Info{}, err
}
reservedBlocks := uint64(s.Bfree) - uint64(s.Bavail)
info = Info{
Total: uint64(s.Frsize) * (uint64(s.Blocks) - reservedBlocks),
Free: uint64(s.Frsize) * uint64(s.Bavail),
Files: uint64(s.Files),
Ffree: uint64(s.Ffree),
FSType: string(s.Fstypename[:]),
}
if info.Free > info.Total {
return info, fmt.Errorf("detected free space (%d) > total drive space (%d), fs corruption at (%s). please run 'fsck'", info.Free, info.Total, path)
}
info.Used = info.Total - info.Free
return info, nil
}
// GetDriveStats returns IO stats of the drive by its major:minor
func GetDriveStats(major, minor uint32) (iostats IOStats, err error) {
return IOStats{}, errors.New("operation unsupported")
}

View File

@@ -0,0 +1,54 @@
//go:build openbsd
// +build openbsd
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"errors"
"fmt"
"syscall"
)
// GetInfo returns total and free bytes available in a directory, e.g. `/`.
func GetInfo(path string, _ bool) (info Info, err error) {
s := syscall.Statfs_t{}
err = syscall.Statfs(path, &s)
if err != nil {
return Info{}, err
}
reservedBlocks := uint64(s.F_bfree) - uint64(s.F_bavail)
info = Info{
Total: uint64(s.F_bsize) * (uint64(s.F_blocks) - reservedBlocks),
Free: uint64(s.F_bsize) * uint64(s.F_bavail),
Files: uint64(s.F_files),
Ffree: uint64(s.F_ffree),
FSType: getFSType(s.F_fstypename[:]),
}
if info.Free > info.Total {
return info, fmt.Errorf("detected free space (%d) > total drive space (%d), fs corruption at (%s). please run 'fsck'", info.Free, info.Total, path)
}
info.Used = info.Total - info.Free
return info, nil
}
// GetDriveStats returns IO stats of the drive by its major:minor
func GetDriveStats(major, minor uint32) (iostats IOStats, err error) {
return IOStats{}, errors.New("operation unsupported")
}

View File

@@ -0,0 +1,54 @@
//go:build solaris
// +build solaris
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"errors"
"fmt"
"golang.org/x/sys/unix"
)
// GetInfo returns total and free bytes available in a directory, e.g. `/`.
func GetInfo(path string, _ bool) (info Info, err error) {
s := unix.Statvfs_t{}
if err = unix.Statvfs(path, &s); err != nil {
return Info{}, err
}
reservedBlocks := uint64(s.Bfree) - uint64(s.Bavail)
info = Info{
Total: uint64(s.Frsize) * (uint64(s.Blocks) - reservedBlocks),
Free: uint64(s.Frsize) * uint64(s.Bavail),
Files: uint64(s.Files),
Ffree: uint64(s.Ffree),
FSType: getFSType(s.Fstr[:]),
}
if info.Free > info.Total {
return info, fmt.Errorf("detected free space (%d) > total drive space (%d), fs corruption at (%s). please run 'fsck'", info.Free, info.Total, path)
}
info.Used = info.Total - info.Free
return info, nil
}
// GetDriveStats returns IO stats of the drive by its major:minor
func GetDriveStats(major, minor uint32) (iostats IOStats, err error) {
return IOStats{}, errors.New("operation unsupported")
}

126
internal/disk/stat_test.go Normal file
View File

@@ -0,0 +1,126 @@
//go:build linux && !s390x && !arm && !386
// +build linux,!s390x,!arm,!386
// Copyright (c) 2015-2024 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"os"
"reflect"
"testing"
)
func TestReadDriveStats(t *testing.T) {
testCases := []struct {
stat string
expectedIOStats IOStats
expectErr bool
}{
{
stat: "1432553 420084 66247626 2398227 7077314 8720147 157049224 7469810 0 7580552 9869354 46037 0 41695120 1315 0 0",
expectedIOStats: IOStats{
ReadIOs: 1432553,
ReadMerges: 420084,
ReadSectors: 66247626,
ReadTicks: 2398227,
WriteIOs: 7077314,
WriteMerges: 8720147,
WriteSectors: 157049224,
WriteTicks: 7469810,
CurrentIOs: 0,
TotalTicks: 7580552,
ReqTicks: 9869354,
DiscardIOs: 46037,
DiscardMerges: 0,
DiscardSectors: 41695120,
DiscardTicks: 1315,
FlushIOs: 0,
FlushTicks: 0,
},
expectErr: false,
},
{
stat: "1432553 420084 66247626 2398227 7077314 8720147 157049224 7469810 0 7580552 9869354 46037 0 41695120 1315",
expectedIOStats: IOStats{
ReadIOs: 1432553,
ReadMerges: 420084,
ReadSectors: 66247626,
ReadTicks: 2398227,
WriteIOs: 7077314,
WriteMerges: 8720147,
WriteSectors: 157049224,
WriteTicks: 7469810,
CurrentIOs: 0,
TotalTicks: 7580552,
ReqTicks: 9869354,
DiscardIOs: 46037,
DiscardMerges: 0,
DiscardSectors: 41695120,
DiscardTicks: 1315,
},
expectErr: false,
},
{
stat: "1432553 420084 66247626 2398227 7077314 8720147 157049224 7469810 0 7580552 9869354",
expectedIOStats: IOStats{
ReadIOs: 1432553,
ReadMerges: 420084,
ReadSectors: 66247626,
ReadTicks: 2398227,
WriteIOs: 7077314,
WriteMerges: 8720147,
WriteSectors: 157049224,
WriteTicks: 7469810,
CurrentIOs: 0,
TotalTicks: 7580552,
ReqTicks: 9869354,
},
expectErr: false,
},
{
stat: "1432553 420084 66247626 2398227",
expectedIOStats: IOStats{},
expectErr: true,
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run("", func(t *testing.T) {
tmpfile, err := os.CreateTemp(t.TempDir(), "testfile")
if err != nil {
t.Error(err)
}
tmpfile.WriteString(testCase.stat)
tmpfile.Sync()
tmpfile.Close()
iostats, err := readDriveStats(tmpfile.Name())
if err != nil && !testCase.expectErr {
t.Fatalf("unexpected err; %v", err)
}
if testCase.expectErr && err == nil {
t.Fatal("expected to fail but err is nil")
}
if !reflect.DeepEqual(iostats, testCase.expectedIOStats) {
t.Fatalf("expected iostats: %v but got %v", testCase.expectedIOStats, iostats)
}
})
}
}

View File

@@ -0,0 +1,114 @@
//go:build windows
// +build windows
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"errors"
"fmt"
"os"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var (
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
// GetDiskFreeSpaceEx - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx
// Retrieves information about the amount of space that is available on a disk volume,
// which is the total amount of space, the total amount of free space, and the total
// amount of free space available to the user that is associated with the calling thread.
GetDiskFreeSpaceEx = kernel32.NewProc("GetDiskFreeSpaceExW")
// GetDiskFreeSpace - https://msdn.microsoft.com/en-us/library/windows/desktop/aa364935(v=vs.85).aspx
// Retrieves information about the specified disk, including the amount of free space on the disk.
GetDiskFreeSpace = kernel32.NewProc("GetDiskFreeSpaceW")
)
// GetInfo returns total and free bytes available in a directory, e.g. `C:\`.
// It returns free space available to the user (including quota limitations)
//
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85).aspx
func GetInfo(path string, _ bool) (info Info, err error) {
// Stat to know if the path exists.
if _, err = os.Stat(path); err != nil {
return Info{}, err
}
lpFreeBytesAvailable := int64(0)
lpTotalNumberOfBytes := int64(0)
lpTotalNumberOfFreeBytes := int64(0)
// Extract values safely
// BOOL WINAPI GetDiskFreeSpaceEx(
// _In_opt_ LPCTSTR lpDirectoryName,
// _Out_opt_ PULARGE_INTEGER lpFreeBytesAvailable,
// _Out_opt_ PULARGE_INTEGER lpTotalNumberOfBytes,
// _Out_opt_ PULARGE_INTEGER lpTotalNumberOfFreeBytes
// );
_, _, _ = GetDiskFreeSpaceEx.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))),
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)))
if uint64(lpTotalNumberOfFreeBytes) > uint64(lpTotalNumberOfBytes) {
return info, fmt.Errorf("detected free space (%d) > total drive space (%d), fs corruption at (%s). please run 'fsck'",
uint64(lpTotalNumberOfFreeBytes), uint64(lpTotalNumberOfBytes), path)
}
info = Info{
Total: uint64(lpTotalNumberOfBytes),
Free: uint64(lpTotalNumberOfFreeBytes),
Used: uint64(lpTotalNumberOfBytes) - uint64(lpTotalNumberOfFreeBytes),
FSType: getFSType(path),
}
// Return values of GetDiskFreeSpace()
lpSectorsPerCluster := uint32(0)
lpBytesPerSector := uint32(0)
lpNumberOfFreeClusters := uint32(0)
lpTotalNumberOfClusters := uint32(0)
// Extract values safely
// BOOL WINAPI GetDiskFreeSpace(
// _In_ LPCTSTR lpRootPathName,
// _Out_ LPDWORD lpSectorsPerCluster,
// _Out_ LPDWORD lpBytesPerSector,
// _Out_ LPDWORD lpNumberOfFreeClusters,
// _Out_ LPDWORD lpTotalNumberOfClusters
// );
_, _, _ = GetDiskFreeSpace.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(path))),
uintptr(unsafe.Pointer(&lpSectorsPerCluster)),
uintptr(unsafe.Pointer(&lpBytesPerSector)),
uintptr(unsafe.Pointer(&lpNumberOfFreeClusters)),
uintptr(unsafe.Pointer(&lpTotalNumberOfClusters)))
info.Files = uint64(lpTotalNumberOfClusters)
info.Ffree = uint64(lpNumberOfFreeClusters)
return info, nil
}
// GetDriveStats returns IO stats of the drive by its major:minor
func GetDriveStats(major, minor uint32) (iostats IOStats, err error) {
return IOStats{}, errors.New("operation unsupported")
}

30
internal/disk/type_bsd.go Normal file
View File

@@ -0,0 +1,30 @@
//go:build darwin || freebsd || dragonfly || openbsd || solaris
// +build darwin freebsd dragonfly openbsd solaris
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
// getFSType returns the filesystem type of the underlying mounted filesystem
func getFSType(fstype []int8) string {
b := make([]byte, len(fstype))
for i, v := range fstype {
b[i] = byte(v)
}
return string(b)
}

View File

@@ -0,0 +1,53 @@
//go:build linux && !s390x && !arm && !386
// +build linux,!s390x,!arm,!386
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import "strconv"
// fsType2StringMap - list of filesystems supported on linux
var fsType2StringMap = map[string]string{
"1021994": "TMPFS",
"137d": "EXT",
"4244": "HFS",
"4d44": "MSDOS",
"52654973": "REISERFS",
"5346544e": "NTFS",
"58465342": "XFS",
"61756673": "AUFS",
"6969": "NFS",
"ef51": "EXT2OLD",
"ef53": "EXT4",
"f15f": "ecryptfs",
"794c7630": "overlayfs",
"2fc12fc1": "zfs",
"ff534d42": "cifs",
"53464846": "wslfs",
}
// getFSType returns the filesystem type of the underlying mounted filesystem
func getFSType(ftype int64) string {
fsTypeHex := strconv.FormatInt(ftype, 16)
fsTypeString, ok := fsType2StringMap[fsTypeHex]
if !ok {
return "UNKNOWN"
}
return fsTypeString
}

View File

@@ -0,0 +1,62 @@
//go:build windows
// +build windows
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package disk
import (
"path/filepath"
"syscall"
"unsafe"
)
// GetVolumeInformation provides windows drive volume information.
var GetVolumeInformation = kernel32.NewProc("GetVolumeInformationW")
// getFSType returns the filesystem type of the underlying mounted filesystem
func getFSType(path string) string {
volumeNameSize, nFileSystemNameSize := uint32(260), uint32(260)
var lpVolumeSerialNumber uint32
var lpFileSystemFlags, lpMaximumComponentLength uint32
var lpFileSystemNameBuffer, volumeName [260]uint16
ps := syscall.StringToUTF16Ptr(filepath.VolumeName(path))
// Extract values safely
// BOOL WINAPI GetVolumeInformation(
// _In_opt_ LPCTSTR lpRootPathName,
// _Out_opt_ LPTSTR lpVolumeNameBuffer,
// _In_ DWORD nVolumeNameSize,
// _Out_opt_ LPDWORD lpVolumeSerialNumber,
// _Out_opt_ LPDWORD lpMaximumComponentLength,
// _Out_opt_ LPDWORD lpFileSystemFlags,
// _Out_opt_ LPTSTR lpFileSystemNameBuffer,
// _In_ DWORD nFileSystemNameSize
// );
_, _, _ = GetVolumeInformation.Call(uintptr(unsafe.Pointer(ps)),
uintptr(unsafe.Pointer(&volumeName)),
uintptr(volumeNameSize),
uintptr(unsafe.Pointer(&lpVolumeSerialNumber)),
uintptr(unsafe.Pointer(&lpMaximumComponentLength)),
uintptr(unsafe.Pointer(&lpFileSystemFlags)),
uintptr(unsafe.Pointer(&lpFileSystemNameBuffer)),
uintptr(nFileSystemNameSize))
return syscall.UTF16ToString(lpFileSystemNameBuffer[:])
}