1
0
mirror of https://github.com/golang/go synced 2024-11-22 18:44:54 -07:00

internal/poll: use sync.Once instead to guard CopyFileRange() with kernel 5.3

The existing implementation creates more branches with more states: -1, 0, 1,
which makes it not very intuitive to understand, let's use sync.Once and boolean
instead to make it more straightforward.

Change-Id: I05766e5fdf7dba37d6565f84d3db4373f9342fe5
Reviewed-on: https://go-review.googlesource.com/c/go/+/425880
Run-TryBot: Ian Lance Taylor <iant@google.com>
Reviewed-by: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
This commit is contained in:
Andy Pan 2022-08-27 03:29:19 +08:00 committed by Gopher Robot
parent 9da49a7d2e
commit c108a682ff

View File

@ -6,11 +6,14 @@ package poll
import ( import (
"internal/syscall/unix" "internal/syscall/unix"
"sync/atomic" "sync"
"syscall" "syscall"
) )
var copyFileRangeSupported int32 = -1 // accessed atomically var (
kernelVersion53Once sync.Once
kernelVersion53 bool
)
const maxCopyFileRangeRound = 1 << 30 const maxCopyFileRangeRound = 1 << 30
@ -52,20 +55,20 @@ func kernelVersion() (major int, minor int) {
// CopyFileRange copies at most remain bytes of data from src to dst, using // 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. // 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) { func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err error) {
if supported := atomic.LoadInt32(&copyFileRangeSupported); supported == 0 { kernelVersion53Once.Do(func() {
return 0, false, nil
} else if supported == -1 {
major, minor := kernelVersion() major, minor := kernelVersion()
// 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
if major > 5 || (major == 5 && minor >= 3) { if major > 5 || (major == 5 && minor >= 3) {
atomic.StoreInt32(&copyFileRangeSupported, 1) kernelVersion53 = true
} 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(&copyFileRangeSupported, 0)
return 0, false, nil
} }
})
if !kernelVersion53 {
return 0, false, nil
} }
for remain > 0 { for remain > 0 {
max := remain max := remain
if max > maxCopyFileRangeRound { if max > maxCopyFileRangeRound {
@ -82,10 +85,6 @@ func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err
// any data, so we can tell the caller that we // any data, so we can tell the caller that we
// couldn't handle the transfer and let them fall // couldn't handle the transfer and let them fall
// back to more generic code. // back to more generic code.
//
// Seeing ENOSYS also means that we will not try to
// use copy_file_range(2) again.
atomic.StoreInt32(&copyFileRangeSupported, 0)
return 0, false, nil return 0, false, nil
case syscall.EXDEV, syscall.EINVAL, syscall.EIO, 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 // Prior to Linux 5.3, it was not possible to