diff options
| author | Katie Hockman <katie@golang.org> | 2020-12-14 10:03:05 -0500 |
|---|---|---|
| committer | Katie Hockman <katie@golang.org> | 2020-12-14 10:06:13 -0500 |
| commit | 0345ede87ee12698988973884cfc0fd3d499dffd (patch) | |
| tree | 7123cff141ee5661208d2f5f437b8f5252ac7f6a /src/internal/poll | |
| parent | 4651d6b267818b0e0d128a5443289717c4bb8cbc (diff) | |
| parent | 0a02371b0576964e81c3b40d328db9a3ef3b031b (diff) | |
| download | go-0345ede87ee12698988973884cfc0fd3d499dffd.tar.xz | |
[dev.fuzz] all: merge master into dev.fuzz
Change-Id: I5d8c8329ccc9d747bd81ade6b1cb7cb8ae2e94b2
Diffstat (limited to 'src/internal/poll')
| -rw-r--r-- | src/internal/poll/copy_file_range_linux.go | 55 | ||||
| -rw-r--r-- | src/internal/poll/error_test.go | 3 | ||||
| -rw-r--r-- | src/internal/poll/fd_fsync_darwin.go | 7 | ||||
| -rw-r--r-- | src/internal/poll/fd_posix.go | 11 | ||||
| -rw-r--r-- | src/internal/poll/fd_unix.go | 18 | ||||
| -rw-r--r-- | src/internal/poll/fd_windows.go | 27 | ||||
| -rw-r--r-- | src/internal/poll/fd_writev_illumos.go | 16 | ||||
| -rw-r--r-- | src/internal/poll/hook_cloexec.go | 2 | ||||
| -rw-r--r-- | src/internal/poll/iovec_illumos.go | 16 | ||||
| -rw-r--r-- | src/internal/poll/iovec_unix.go | 13 | ||||
| -rw-r--r-- | src/internal/poll/read_test.go | 5 | ||||
| -rw-r--r-- | src/internal/poll/sock_cloexec.go | 2 | ||||
| -rw-r--r-- | src/internal/poll/sys_cloexec.go | 2 | ||||
| -rw-r--r-- | src/internal/poll/writev.go | 4 |
14 files changed, 155 insertions, 26 deletions
diff --git a/src/internal/poll/copy_file_range_linux.go b/src/internal/poll/copy_file_range_linux.go index 09de299ff7..fc34aef4cb 100644 --- a/src/internal/poll/copy_file_range_linux.go +++ b/src/internal/poll/copy_file_range_linux.go @@ -10,15 +10,61 @@ import ( "syscall" ) -var copyFileRangeSupported int32 = 1 // accessed atomically +var copyFileRangeSupported int32 = -1 // accessed atomically const maxCopyFileRangeRound = 1 << 30 +func kernelVersion() (major int, minor int) { + var uname syscall.Utsname + if err := syscall.Uname(&uname); err != nil { + return + } + + rl := uname.Release + var values [2]int + vi := 0 + value := 0 + for _, c := range rl { + if '0' <= c && c <= '9' { + value = (value * 10) + int(c-'0') + } else { + // Note that we're assuming N.N.N here. If we see anything else we are likely to + // mis-parse it. + values[vi] = value + vi++ + if vi >= len(values) { + break + } + value = 0 + } + } + switch vi { + case 0: + return 0, 0 + case 1: + return values[0], 0 + case 2: + return values[0], values[1] + } + return +} + // CopyFileRange copies at most remain bytes of data from src to dst, using // the copy_file_range system call. dst and src must refer to regular files. func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err error) { - if atomic.LoadInt32(©FileRangeSupported) == 0 { + if supported := atomic.LoadInt32(©FileRangeSupported); supported == 0 { return 0, false, nil + } else if supported == -1 { + major, minor := kernelVersion() + if major > 5 || (major == 5 && minor >= 3) { + atomic.StoreInt32(©FileRangeSupported, 1) + } else { + // copy_file_range(2) is broken in various ways on kernels older than 5.3, + // see issue #42400 and + // https://man7.org/linux/man-pages/man2/copy_file_range.2.html#VERSIONS + atomic.StoreInt32(©FileRangeSupported, 0) + return 0, false, nil + } } for remain > 0 { max := remain @@ -41,7 +87,7 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err // use copy_file_range(2) again. atomic.StoreInt32(©FileRangeSupported, 0) return 0, false, nil - case syscall.EXDEV, syscall.EINVAL, syscall.EOPNOTSUPP, syscall.EPERM: + case syscall.EXDEV, syscall.EINVAL, syscall.EIO, syscall.EOPNOTSUPP, syscall.EPERM: // Prior to Linux 5.3, it was not possible to // copy_file_range across file systems. Similarly to // the ENOSYS case above, if we see EXDEV, we have @@ -53,6 +99,9 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err // file. This is another case where no data has been // transfered, so we consider it unhandled. // + // If src and dst are on CIFS, we can see EIO. + // See issue #42334. + // // If the file is on NFS, we can see EOPNOTSUPP. // See issue #40731. // diff --git a/src/internal/poll/error_test.go b/src/internal/poll/error_test.go index 06b96f635a..abc8b1684f 100644 --- a/src/internal/poll/error_test.go +++ b/src/internal/poll/error_test.go @@ -6,6 +6,7 @@ package poll_test import ( "fmt" + "io/fs" "net" "os" "testing" @@ -37,7 +38,7 @@ func parseReadError(nestedErr error, verify func(error) (string, bool)) error { if nerr, ok := err.(*net.OpError); ok { err = nerr.Err } - if nerr, ok := err.(*os.PathError); ok { + if nerr, ok := err.(*fs.PathError); ok { err = nerr.Err } if nerr, ok := err.(*os.SyscallError); ok { diff --git a/src/internal/poll/fd_fsync_darwin.go b/src/internal/poll/fd_fsync_darwin.go index 91751496a4..48e7596922 100644 --- a/src/internal/poll/fd_fsync_darwin.go +++ b/src/internal/poll/fd_fsync_darwin.go @@ -14,7 +14,8 @@ func (fd *FD) Fsync() error { return err } defer fd.decref() - - _, e1 := fcntl(fd.Sysfd, syscall.F_FULLFSYNC, 0) - return e1 + return ignoringEINTR(func() error { + _, err := fcntl(fd.Sysfd, syscall.F_FULLFSYNC, 0) + return err + }) } diff --git a/src/internal/poll/fd_posix.go b/src/internal/poll/fd_posix.go index e5fb05c9c2..4edfa953a4 100644 --- a/src/internal/poll/fd_posix.go +++ b/src/internal/poll/fd_posix.go @@ -29,17 +29,6 @@ func (fd *FD) Shutdown(how int) error { return syscall.Shutdown(fd.Sysfd, how) } -// Fchmod wraps syscall.Fchmod. -func (fd *FD) Fchmod(mode uint32) error { - if err := fd.incref(); err != nil { - return err - } - defer fd.decref() - return ignoringEINTR(func() error { - return syscall.Fchmod(fd.Sysfd, mode) - }) -} - // Fchown wraps syscall.Fchown. func (fd *FD) Fchown(uid, gid int) error { if err := fd.incref(); err != nil { diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go index 1d5101eac3..2e77e76c87 100644 --- a/src/internal/poll/fd_unix.go +++ b/src/internal/poll/fd_unix.go @@ -74,7 +74,14 @@ func (fd *FD) destroy() error { // Poller may want to unregister fd in readiness notification mechanism, // so this must be executed before CloseFunc. fd.pd.close() + + // We don't use ignoringEINTR here because POSIX does not define + // whether the descriptor is closed if close returns EINTR. + // If the descriptor is indeed closed, using a loop would race + // with some other goroutine opening a new descriptor. + // (The Linux kernel guarantees that it is closed on an EINTR error.) err := CloseFunc(fd.Sysfd) + fd.Sysfd = -1 runtime_Semrelease(&fd.csema) return err @@ -437,6 +444,17 @@ func (fd *FD) ReadDirent(buf []byte) (int, error) { } } +// Fchmod wraps syscall.Fchmod. +func (fd *FD) Fchmod(mode uint32) error { + if err := fd.incref(); err != nil { + return err + } + defer fd.decref() + return ignoringEINTR(func() error { + return syscall.Fchmod(fd.Sysfd, mode) + }) +} + // Fchdir wraps syscall.Fchdir. func (fd *FD) Fchdir() error { if err := fd.incref(); err != nil { diff --git a/src/internal/poll/fd_windows.go b/src/internal/poll/fd_windows.go index e1ef6199b3..d8c834f929 100644 --- a/src/internal/poll/fd_windows.go +++ b/src/internal/poll/fd_windows.go @@ -886,6 +886,33 @@ func (fd *FD) FindNextFile(data *syscall.Win32finddata) error { return syscall.FindNextFile(fd.Sysfd, data) } +// Fchmod updates syscall.ByHandleFileInformation.Fileattributes when needed. +func (fd *FD) Fchmod(mode uint32) error { + if err := fd.incref(); err != nil { + return err + } + defer fd.decref() + + var d syscall.ByHandleFileInformation + if err := syscall.GetFileInformationByHandle(fd.Sysfd, &d); err != nil { + return err + } + attrs := d.FileAttributes + if mode&syscall.S_IWRITE != 0 { + attrs &^= syscall.FILE_ATTRIBUTE_READONLY + } else { + attrs |= syscall.FILE_ATTRIBUTE_READONLY + } + if attrs == d.FileAttributes { + return nil + } + + var du windows.FILE_BASIC_INFO + du.FileAttributes = attrs + l := uint32(unsafe.Sizeof(d)) + return windows.SetFileInformationByHandle(fd.Sysfd, windows.FileBasicInfo, uintptr(unsafe.Pointer(&du)), l) +} + // Fchdir wraps syscall.Fchdir. func (fd *FD) Fchdir() error { if err := fd.incref(); err != nil { diff --git a/src/internal/poll/fd_writev_illumos.go b/src/internal/poll/fd_writev_illumos.go new file mode 100644 index 0000000000..1fa47ab1a3 --- /dev/null +++ b/src/internal/poll/fd_writev_illumos.go @@ -0,0 +1,16 @@ +// Copyright 2020 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 illumos + +package poll + +import ( + "internal/syscall/unix" + "syscall" +) + +func writev(fd int, iovecs []syscall.Iovec) (uintptr, error) { + return unix.Writev(fd, iovecs) +} diff --git a/src/internal/poll/hook_cloexec.go b/src/internal/poll/hook_cloexec.go index 5c93bdaf6c..5fd5449bb0 100644 --- a/src/internal/poll/hook_cloexec.go +++ b/src/internal/poll/hook_cloexec.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build dragonfly freebsd linux netbsd openbsd +// +build dragonfly freebsd illumos linux netbsd openbsd package poll diff --git a/src/internal/poll/iovec_illumos.go b/src/internal/poll/iovec_illumos.go new file mode 100644 index 0000000000..057067465b --- /dev/null +++ b/src/internal/poll/iovec_illumos.go @@ -0,0 +1,16 @@ +// Copyright 2020 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 illumos + +package poll + +import ( + "syscall" + "unsafe" +) + +func newIovecWithBase(base *byte) syscall.Iovec { + return syscall.Iovec{Base: (*int8)(unsafe.Pointer(base))} +} diff --git a/src/internal/poll/iovec_unix.go b/src/internal/poll/iovec_unix.go new file mode 100644 index 0000000000..6f98947866 --- /dev/null +++ b/src/internal/poll/iovec_unix.go @@ -0,0 +1,13 @@ +// Copyright 2020 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 darwin dragonfly freebsd linux netbsd openbsd + +package poll + +import "syscall" + +func newIovecWithBase(base *byte) syscall.Iovec { + return syscall.Iovec{Base: base} +} diff --git a/src/internal/poll/read_test.go b/src/internal/poll/read_test.go index b4f5236d3e..598a52ee44 100644 --- a/src/internal/poll/read_test.go +++ b/src/internal/poll/read_test.go @@ -5,7 +5,6 @@ package poll_test import ( - "io/ioutil" "os" "runtime" "sync" @@ -22,7 +21,7 @@ func TestRead(t *testing.T) { go func(p string) { defer wg.Done() for i := 0; i < 100; i++ { - if _, err := ioutil.ReadFile(p); err != nil { + if _, err := os.ReadFile(p); err != nil { t.Error(err) return } @@ -38,7 +37,7 @@ func TestRead(t *testing.T) { func specialFiles() []string { var ps []string switch runtime.GOOS { - case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd": + case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd": ps = []string{ "/dev/null", } diff --git a/src/internal/poll/sock_cloexec.go b/src/internal/poll/sock_cloexec.go index 691cb8e36f..ff7982ca9e 100644 --- a/src/internal/poll/sock_cloexec.go +++ b/src/internal/poll/sock_cloexec.go @@ -5,7 +5,7 @@ // This file implements sysSocket and accept for platforms that // provide a fast path for setting SetNonblock and CloseOnExec. -// +build dragonfly freebsd linux netbsd openbsd +// +build dragonfly freebsd illumos linux netbsd openbsd package poll diff --git a/src/internal/poll/sys_cloexec.go b/src/internal/poll/sys_cloexec.go index 7b87f136df..4b3c642173 100644 --- a/src/internal/poll/sys_cloexec.go +++ b/src/internal/poll/sys_cloexec.go @@ -5,7 +5,7 @@ // This file implements sysSocket and accept for platforms that do not // provide a fast path for setting SetNonblock and CloseOnExec. -// +build aix darwin js,wasm solaris +// +build aix darwin js,wasm solaris,!illumos package poll diff --git a/src/internal/poll/writev.go b/src/internal/poll/writev.go index 305e2fd209..0123fc33de 100644 --- a/src/internal/poll/writev.go +++ b/src/internal/poll/writev.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux netbsd openbsd +// +build darwin dragonfly freebsd illumos linux netbsd openbsd package poll @@ -38,7 +38,7 @@ func (fd *FD) Writev(v *[][]byte) (int64, error) { if len(chunk) == 0 { continue } - iovecs = append(iovecs, syscall.Iovec{Base: &chunk[0]}) + iovecs = append(iovecs, newIovecWithBase(&chunk[0])) if fd.IsStream && len(chunk) > 1<<30 { iovecs[len(iovecs)-1].SetLen(1 << 30) break // continue chunk on next writev |
