]> Cypherpunks repositories - gostls13.git/commitdiff
internal/poll: use sync.Once instead to guard CopyFileRange() with kernel 5.3
authorAndy Pan <panjf2000@gmail.com>
Fri, 26 Aug 2022 19:29:19 +0000 (03:29 +0800)
committerGopher Robot <gobot@golang.org>
Mon, 29 Aug 2022 20:06:09 +0000 (20:06 +0000)
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>

src/internal/poll/copy_file_range_linux.go

index 5b9e5d402068ee6610efea08e3697d582e275239..c2347ba7f2f689e45866e4b8d4fe0aa313935816 100644 (file)
@@ -6,11 +6,14 @@ package poll
 
 import (
        "internal/syscall/unix"
-       "sync/atomic"
+       "sync"
        "syscall"
 )
 
-var copyFileRangeSupported int32 = -1 // accessed atomically
+var (
+       kernelVersion53Once sync.Once
+       kernelVersion53     bool
+)
 
 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
 // 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 supported := atomic.LoadInt32(&copyFileRangeSupported); supported == 0 {
-               return 0, false, nil
-       } else if supported == -1 {
+       kernelVersion53Once.Do(func() {
                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) {
-                       atomic.StoreInt32(&copyFileRangeSupported, 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(&copyFileRangeSupported, 0)
-                       return 0, false, nil
+                       kernelVersion53 = true
                }
+       })
+
+       if !kernelVersion53 {
+               return 0, false, nil
        }
+
        for remain > 0 {
                max := remain
                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
                        // couldn't handle the transfer and let them fall
                        // 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
                case syscall.EXDEV, syscall.EINVAL, syscall.EIO, syscall.EOPNOTSUPP, syscall.EPERM:
                        // Prior to Linux 5.3, it was not possible to