OP#792 initial commit after fork
This commit is contained in:
47
internal/disk/directio_darwin.go
Normal file
47
internal/disk/directio_darwin.go
Normal 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)
|
||||
}
|
||||
54
internal/disk/directio_unix.go
Normal file
54
internal/disk/directio_unix.go
Normal 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)
|
||||
}
|
||||
68
internal/disk/directio_unsupported.go
Normal file
68
internal/disk/directio_unsupported.go
Normal 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
62
internal/disk/disk.go
Normal 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
|
||||
}
|
||||
38
internal/disk/disk_test.go
Normal file
38
internal/disk/disk_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
41
internal/disk/disk_unix.go
Normal file
41
internal/disk/disk_unix.go
Normal 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
|
||||
}
|
||||
26
internal/disk/disk_windows.go
Normal file
26
internal/disk/disk_windows.go
Normal 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
|
||||
}
|
||||
47
internal/disk/fdatasync_linux.go
Normal file
47
internal/disk/fdatasync_linux.go
Normal 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)
|
||||
}
|
||||
36
internal/disk/fdatasync_unix.go
Normal file
36
internal/disk/fdatasync_unix.go
Normal 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
|
||||
}
|
||||
35
internal/disk/fdatasync_unsupported.go
Normal file
35
internal/disk/fdatasync_unsupported.go
Normal 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
|
||||
}
|
||||
29
internal/disk/root_disk.go
Normal file
29
internal/disk/root_disk.go
Normal 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
54
internal/disk/stat_bsd.go
Normal 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")
|
||||
}
|
||||
54
internal/disk/stat_freebsd.go
Normal file
54
internal/disk/stat_freebsd.go
Normal 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
173
internal/disk/stat_linux.go
Normal 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
|
||||
}
|
||||
89
internal/disk/stat_linux_32bit.go
Normal file
89
internal/disk/stat_linux_32bit.go
Normal 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")
|
||||
}
|
||||
89
internal/disk/stat_linux_s390x.go
Normal file
89
internal/disk/stat_linux_s390x.go
Normal 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")
|
||||
}
|
||||
54
internal/disk/stat_netbsd.go
Normal file
54
internal/disk/stat_netbsd.go
Normal 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")
|
||||
}
|
||||
54
internal/disk/stat_openbsd.go
Normal file
54
internal/disk/stat_openbsd.go
Normal 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")
|
||||
}
|
||||
54
internal/disk/stat_solaris.go
Normal file
54
internal/disk/stat_solaris.go
Normal 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
126
internal/disk/stat_test.go
Normal 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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
114
internal/disk/stat_windows.go
Normal file
114
internal/disk/stat_windows.go
Normal 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
30
internal/disk/type_bsd.go
Normal 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)
|
||||
}
|
||||
53
internal/disk/type_linux.go
Normal file
53
internal/disk/type_linux.go
Normal 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
|
||||
}
|
||||
62
internal/disk/type_windows.go
Normal file
62
internal/disk/type_windows.go
Normal 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[:])
|
||||
}
|
||||
Reference in New Issue
Block a user