|
|
@ -187,7 +187,7 @@ func newPosix(path string) (*posix, error) { |
|
|
|
p := &posix{ |
|
|
|
p := &posix{ |
|
|
|
connected: true, |
|
|
|
connected: true, |
|
|
|
diskPath: path, |
|
|
|
diskPath: path, |
|
|
|
// 1MiB buffer pool for posix internal operations.
|
|
|
|
// 4MiB buffer pool for posix internal operations.
|
|
|
|
pool: sync.Pool{ |
|
|
|
pool: sync.Pool{ |
|
|
|
New: func() interface{} { |
|
|
|
New: func() interface{} { |
|
|
|
b := directio.AlignedBlock(posixWriteBlockSize) |
|
|
|
b := directio.AlignedBlock(posixWriteBlockSize) |
|
|
@ -1028,10 +1028,9 @@ func (s *posix) ReadFileStream(volume, path string, offset, length int64) (io.Re |
|
|
|
|
|
|
|
|
|
|
|
// CreateFile - creates the file.
|
|
|
|
// CreateFile - creates the file.
|
|
|
|
func (s *posix) CreateFile(volume, path string, fileSize int64, r io.Reader) (err error) { |
|
|
|
func (s *posix) CreateFile(volume, path string, fileSize int64, r io.Reader) (err error) { |
|
|
|
if fileSize < 0 { |
|
|
|
if fileSize < -1 { |
|
|
|
return errInvalidArgument |
|
|
|
return errInvalidArgument |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
defer func() { |
|
|
|
defer func() { |
|
|
|
if err == errFaultyDisk { |
|
|
|
if err == errFaultyDisk { |
|
|
|
atomic.AddInt32(&s.ioErrCount, 1) |
|
|
|
atomic.AddInt32(&s.ioErrCount, 1) |
|
|
@ -1120,69 +1119,69 @@ func (s *posix) CreateFile(volume, path string, fileSize int64, r io.Reader) (er |
|
|
|
defer s.pool.Put(bufp) |
|
|
|
defer s.pool.Put(bufp) |
|
|
|
|
|
|
|
|
|
|
|
buf := *bufp |
|
|
|
buf := *bufp |
|
|
|
var written int64 |
|
|
|
|
|
|
|
dioCount := int(fileSize) / len(buf) |
|
|
|
// Writes remaining bytes in the buffer.
|
|
|
|
for i := 0; i < dioCount; i++ { |
|
|
|
writeRemaining := func(w *os.File, buf []byte) (remainingWritten int, err error) { |
|
|
|
var n int |
|
|
|
var n int |
|
|
|
_, err = io.ReadFull(r, buf) |
|
|
|
remaining := len(buf) |
|
|
|
if err != nil { |
|
|
|
// The following logic writes the remainging data such that it writes whatever best is possible (aligned buffer)
|
|
|
|
return err |
|
|
|
// in O_DIRECT mode and remaining (unaligned buffer) in non-O_DIRECT mode.
|
|
|
|
} |
|
|
|
|
|
|
|
n, err = w.Write(buf) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
written += int64(n) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// The following logic writes the remainging data such that it writes whatever best is possible (aligned buffer)
|
|
|
|
|
|
|
|
// in O_DIRECT mode and remaining (unaligned buffer) in non-O_DIRECT mode.
|
|
|
|
|
|
|
|
remaining := fileSize % int64(len(buf)) |
|
|
|
|
|
|
|
if remaining != 0 { |
|
|
|
|
|
|
|
buf = buf[:remaining] |
|
|
|
|
|
|
|
_, err = io.ReadFull(r, buf) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
remainingAligned := (remaining / directioAlignSize) * directioAlignSize |
|
|
|
remainingAligned := (remaining / directioAlignSize) * directioAlignSize |
|
|
|
remainingAlignedBuf := buf[:remainingAligned] |
|
|
|
remainingAlignedBuf := buf[:remainingAligned] |
|
|
|
remainingUnalignedBuf := buf[remainingAligned:] |
|
|
|
remainingUnalignedBuf := buf[remainingAligned:] |
|
|
|
if len(remainingAlignedBuf) > 0 { |
|
|
|
if len(remainingAlignedBuf) > 0 { |
|
|
|
var n int |
|
|
|
|
|
|
|
n, err = w.Write(remainingAlignedBuf) |
|
|
|
n, err = w.Write(remainingAlignedBuf) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
return 0, err |
|
|
|
} |
|
|
|
} |
|
|
|
written += int64(n) |
|
|
|
remainingWritten += n |
|
|
|
} |
|
|
|
} |
|
|
|
if len(remainingUnalignedBuf) > 0 { |
|
|
|
if len(remainingUnalignedBuf) > 0 { |
|
|
|
var n int |
|
|
|
|
|
|
|
// Write on O_DIRECT fds fail if buffer is not 4K aligned, hence disable O_DIRECT.
|
|
|
|
// Write on O_DIRECT fds fail if buffer is not 4K aligned, hence disable O_DIRECT.
|
|
|
|
if err = disk.DisableDirectIO(w); err != nil { |
|
|
|
if err = disk.DisableDirectIO(w); err != nil { |
|
|
|
return err |
|
|
|
return 0, err |
|
|
|
} |
|
|
|
} |
|
|
|
n, err = w.Write(remainingUnalignedBuf) |
|
|
|
n, err = w.Write(remainingUnalignedBuf) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
return 0, err |
|
|
|
} |
|
|
|
} |
|
|
|
written += int64(n) |
|
|
|
remainingWritten += n |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return remainingWritten, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Do some sanity checks.
|
|
|
|
var written int |
|
|
|
_, err = io.ReadFull(r, buf) |
|
|
|
for { |
|
|
|
if err != io.EOF { |
|
|
|
var n int |
|
|
|
return errMoreData |
|
|
|
n, err = io.ReadFull(r, buf) |
|
|
|
} |
|
|
|
switch err { |
|
|
|
|
|
|
|
case nil: |
|
|
|
if written < fileSize { |
|
|
|
n, err = w.Write(buf) |
|
|
|
return errLessData |
|
|
|
if err != nil { |
|
|
|
} |
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
if written > fileSize { |
|
|
|
written += n |
|
|
|
return errMoreData |
|
|
|
case io.ErrUnexpectedEOF: |
|
|
|
|
|
|
|
n, err = writeRemaining(w, buf[:n]) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
written += n |
|
|
|
|
|
|
|
fallthrough |
|
|
|
|
|
|
|
case io.EOF: |
|
|
|
|
|
|
|
if fileSize != -1 { |
|
|
|
|
|
|
|
if written < int(fileSize) { |
|
|
|
|
|
|
|
return errLessData |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if written > int(fileSize) { |
|
|
|
|
|
|
|
return errMoreData |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *posix) WriteAll(volume, path string, buf []byte) (err error) { |
|
|
|
func (s *posix) WriteAll(volume, path string, buf []byte) (err error) { |
|
|
|