1
0
mirror of https://github.com/golang/go synced 2024-11-23 14:30:02 -07:00

internal/poll: use F_FULLFSYNC fcntl for FD.Fsync on OS X

As reported in #26650 and also cautioned on the man page
for fsync on OS X, fsync doesn't properly flush content
to permanent storage, and might cause corruption of data if
the OS crashes or if the drive loses power. Thus it is recommended
to use the F_FULLFSYNC fcntl, which flushes all buffered data to
permanent storage and is important for applications such as
databases that require a strict ordering of writes.

Also added a note in syscall_darwin.go that syscall.Fsync is
not invoked for os.File.Sync.

Fixes #26650.

Change-Id: Idecd9adbbdd640b9c5b02e73b60ed254c98b48b6
Reviewed-on: https://go-review.googlesource.com/130676
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Emmanuel T Odeke 2018-08-21 22:58:08 -07:00 committed by Emmanuel Odeke
parent ccb70bd19c
commit be10ad7622
4 changed files with 42 additions and 9 deletions

View File

@ -0,0 +1,23 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package poll
import "syscall"
// Fsync invokes SYS_FCNTL with SYS_FULLFSYNC because
// on OS X, SYS_FSYNC doesn't fully flush contents to disk.
// See Issue #26650 as well as the man page for fsync on OS X.
func (fd *FD) Fsync() error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
_, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd.Sysfd), syscall.F_FULLFSYNC, 0)
if e1 != 0 {
return e1
}
return nil
}

View File

@ -0,0 +1,18 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
package poll
import "syscall"
// Fsync wraps syscall.Fsync.
func (fd *FD) Fsync() error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Fsync(fd.Sysfd)
}

View File

@ -46,12 +46,3 @@ func (fd *FD) Ftruncate(size int64) error {
defer fd.decref()
return syscall.Ftruncate(fd.Sysfd, size)
}
// Fsync wraps syscall.Fsync.
func (fd *FD) Fsync() error {
if err := fd.incref(); err != nil {
return err
}
defer fd.decref()
return syscall.Fsync(fd.Sysfd)
}

View File

@ -252,6 +252,7 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
//sys Fsync(fd int) (err error)
// Fsync is not called for os.File.Sync(). Please see internal/poll/fd_fsync_darwin.go
//sys Ftruncate(fd int, length int64) (err error)
//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
//sys Getdtablesize() (size int)