mirror of
https://github.com/minio/minio.git
synced 2024-12-26 15:15:55 -05:00
974073a2e5
Check if directio buffers have actually been fetched and prevent errors on double Close. Return error on Read after Close. Fixes ``` panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0xf8582f] goroutine 210 [running]: github.com/minio/minio/internal/ioutil.(*ODirectReader).Read(0xc0054f8320, {0xc0014560b0, 0xa8, 0x44d012}) github.com/minio/minio/internal/ioutil/odirect_reader.go:88 +0x10f io.ReadAtLeast({0x428c5c0, 0xc0054f8320}, {0xc0014560b0, 0xa8, 0xa8}, 0xa8) io/io.go:328 +0x9a io.ReadFull(...) io/io.go:347 github.com/minio/minio/internal/ioutil.ReadFile({0xc001bf60e0, 0x6}) github.com/minio/minio/internal/ioutil/read_file.go:48 +0x19b github.com/minio/minio/cmd.(*FSObjects).scanBucket.func1({{0xc00444e1e0, 0x4d}, 0x0, {0xc0040cf240, 0xe}, {0xc0040cf24f, 0x18}, {0xc0040cf268, 0x18}, 0x0, ...}) github.com/minio/minio/cmd/fs-v1.go:366 +0x1ea github.com/minio/minio/cmd.(*folderScanner).scanFolder.func1({0xc00474a6a8, 0xc0065d6793}, 0x0) github.com/minio/minio/cmd/data-scanner.go:494 +0xb15 github.com/minio/minio/cmd.readDirFn({0xc002803e80, 0x34}, 0xc000670270) github.com/minio/minio/cmd/os-readdir_unix.go:172 +0x638 github.com/minio/minio/cmd.(*folderScanner).scanFolder(0xc002deeb40, {0x42dc9d0, 0xc00068cbc0}, {{0xc001c6e2d0, 0x27}, 0xc0023db8e0, 0x1}, 0xc0001c7ab0) github.com/minio/minio/cmd/data-scanner.go:427 +0xa8f github.com/minio/minio/cmd.(*folderScanner).scanFolder.func2({{0xc001c6e2d0, 0x27}, 0xc0023db8e0, 0x27}) github.com/minio/minio/cmd/data-scanner.go:549 +0xd0 github.com/minio/minio/cmd.(*folderScanner).scanFolder(0xc002deeb40, {0x42dc9d0, 0xc00068cbc0}, {{0xc0013fa9e0, 0xe}, 0x0, 0x1}, 0xc000670dd8) github.com/minio/minio/cmd/data-scanner.go:623 +0x205d github.com/minio/minio/cmd.scanDataFolder({_, _}, {_, _}, {{{0xc0013fa9e0, 0xe}, 0x802, {0x210f15d2, 0xed8f903b8, 0x5bc0e80}, ...}, ...}, ...) github.com/minio/minio/cmd/data-scanner.go:333 +0xc51 github.com/minio/minio/cmd.(*FSObjects).scanBucket(_, {_, _}, {_, _}, {{{0xc0013fa9e0, 0xe}, 0x802, {0x210f15d2, 0xed8f903b8, ...}, ...}, ...}) github.com/minio/minio/cmd/fs-v1.go:364 +0x305 github.com/minio/minio/cmd.(*FSObjects).NSScanner(0x42dc9d0, {0x42dc9d0, 0xc00068cbc0}, 0x0, 0xc003bcfda0, 0x802) github.com/minio/minio/cmd/fs-v1.go:307 +0xa16 github.com/minio/minio/cmd.runDataScanner({0x42dc9d0, 0xc00068cbc0}, {0x436a6c0, 0xc000bfcf50}) github.com/minio/minio/cmd/data-scanner.go:150 +0x749 created by github.com/minio/minio/cmd.initDataScanner github.com/minio/minio/cmd/data-scanner.go:73 +0xb0 ```
137 lines
3.3 KiB
Go
137 lines
3.3 KiB
Go
// 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 ioutil
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
"sync"
|
|
"syscall"
|
|
|
|
"github.com/dustin/go-humanize"
|
|
"github.com/minio/minio/internal/disk"
|
|
)
|
|
|
|
// ODirectReader - to support O_DIRECT reads for erasure backends.
|
|
type ODirectReader struct {
|
|
File *os.File
|
|
SmallFile bool
|
|
err error
|
|
buf []byte
|
|
bufp *[]byte
|
|
seenRead bool
|
|
}
|
|
|
|
// Block sizes constant.
|
|
const (
|
|
BlockSizeSmall = 128 * humanize.KiByte // Default r/w block size for smaller objects.
|
|
BlockSizeLarge = 2 * humanize.MiByte // Default r/w block size for larger objects.
|
|
BlockSizeReallyLarge = 4 * humanize.MiByte // Default write block size for objects per shard >= 64MiB
|
|
)
|
|
|
|
// O_DIRECT aligned sync.Pool's
|
|
var (
|
|
ODirectPoolXLarge = sync.Pool{
|
|
New: func() interface{} {
|
|
b := disk.AlignedBlock(BlockSizeReallyLarge)
|
|
return &b
|
|
},
|
|
}
|
|
ODirectPoolLarge = sync.Pool{
|
|
New: func() interface{} {
|
|
b := disk.AlignedBlock(BlockSizeLarge)
|
|
return &b
|
|
},
|
|
}
|
|
ODirectPoolSmall = sync.Pool{
|
|
New: func() interface{} {
|
|
b := disk.AlignedBlock(BlockSizeSmall)
|
|
return &b
|
|
},
|
|
}
|
|
)
|
|
|
|
// Invalid argument, unsupported flags such as O_DIRECT
|
|
func isSysErrInvalidArg(err error) bool {
|
|
return errors.Is(err, syscall.EINVAL)
|
|
}
|
|
|
|
// Read - Implements Reader interface.
|
|
func (o *ODirectReader) Read(buf []byte) (n int, err error) {
|
|
if o.err != nil && (len(o.buf) == 0 || !o.seenRead) {
|
|
return 0, o.err
|
|
}
|
|
if o.buf == nil {
|
|
if o.SmallFile {
|
|
o.bufp = ODirectPoolSmall.Get().(*[]byte)
|
|
} else {
|
|
o.bufp = ODirectPoolLarge.Get().(*[]byte)
|
|
}
|
|
}
|
|
if !o.seenRead {
|
|
o.buf = *o.bufp
|
|
n, err = o.File.Read(o.buf)
|
|
if err != nil && err != io.EOF {
|
|
if isSysErrInvalidArg(err) {
|
|
if err = disk.DisableDirectIO(o.File); err != nil {
|
|
o.err = err
|
|
return n, err
|
|
}
|
|
n, err = o.File.Read(o.buf)
|
|
}
|
|
if err != nil && err != io.EOF {
|
|
o.err = err
|
|
return n, err
|
|
}
|
|
}
|
|
if n == 0 {
|
|
// err is likely io.EOF
|
|
o.err = err
|
|
return n, err
|
|
}
|
|
o.err = err
|
|
o.buf = o.buf[:n]
|
|
o.seenRead = true
|
|
}
|
|
if len(buf) >= len(o.buf) {
|
|
n = copy(buf, o.buf)
|
|
o.seenRead = false
|
|
return n, o.err
|
|
}
|
|
n = copy(buf, o.buf)
|
|
o.buf = o.buf[n:]
|
|
// There is more left in buffer, do not return any EOF yet.
|
|
return n, nil
|
|
}
|
|
|
|
// Close - Release the buffer and close the file.
|
|
func (o *ODirectReader) Close() error {
|
|
if o.bufp != nil {
|
|
if o.SmallFile {
|
|
ODirectPoolSmall.Put(o.bufp)
|
|
} else {
|
|
ODirectPoolLarge.Put(o.bufp)
|
|
}
|
|
o.bufp = nil
|
|
o.buf = nil
|
|
}
|
|
o.err = errors.New("internal error: ODirectReader Read after Close")
|
|
return o.File.Close()
|
|
}
|