mirror of
https://github.com/golang/go.git
synced 2025-10-19 11:03:18 +00:00
internal/syscall/unix: add KernelVersionGE
There are a few places in the code which checks that the running kernel is greater than or equal to x.y. The check takes a few lines and the checking code is somewhat distracting. Let's abstract this check into a simple function, KernelVersionGE, and convert the users accordingly. Add a test case (I'm not sure it has much value, can be dropped). Change-Id: I8ec91dcc7452363361f95e46794701c0ae57d956 Reviewed-on: https://go-review.googlesource.com/c/go/+/700796 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Mark Freeman <markfreeman@google.com>
This commit is contained in:
parent
e603e9834e
commit
68c6a73380
10 changed files with 98 additions and 30 deletions
|
@ -10,16 +10,11 @@ import (
|
|||
"syscall"
|
||||
)
|
||||
|
||||
func supportCopyFileRange() bool {
|
||||
return isKernelVersionGE53()
|
||||
}
|
||||
|
||||
var isKernelVersionGE53 = sync.OnceValue(func() bool {
|
||||
major, minor := unix.KernelVersion()
|
||||
var supportCopyFileRange = sync.OnceValue(func() bool {
|
||||
// copy_file_range(2) is broken in various ways on kernels older than 5.3,
|
||||
// see https://go.dev/issue/42400 and
|
||||
// https://man7.org/linux/man-pages/man2/copy_file_range.2.html#VERSIONS
|
||||
return major > 5 || (major == 5 && minor >= 3)
|
||||
return unix.KernelVersionGE(5, 3)
|
||||
})
|
||||
|
||||
// For best performance, call copy_file_range() with the largest len value
|
||||
|
|
|
@ -42,7 +42,9 @@ func KernelVersion() (major, minor int) {
|
|||
// This function will examine both the kernel version and the availability of the system call.
|
||||
var SupportCopyFileRange = sync.OnceValue(func() bool {
|
||||
// The copy_file_range() function first appeared in FreeBSD 13.0.
|
||||
major, _ := KernelVersion()
|
||||
if !KernelVersionGE(13, 0) {
|
||||
return false
|
||||
}
|
||||
_, err := CopyFileRange(0, nil, 0, nil, 0, 0)
|
||||
return major >= 13 && err != syscall.ENOSYS
|
||||
return err != syscall.ENOSYS
|
||||
})
|
||||
|
|
13
src/internal/syscall/unix/kernel_version_ge.go
Normal file
13
src/internal/syscall/unix/kernel_version_ge.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2025 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 unix
|
||||
|
||||
// KernelVersionGE checks if the running kernel version
|
||||
// is greater than or equal to the provided version.
|
||||
func KernelVersionGE(x, y int) bool {
|
||||
xx, yy := KernelVersion()
|
||||
|
||||
return xx > x || (xx == x && yy >= y)
|
||||
}
|
67
src/internal/syscall/unix/kernel_version_ge_test.go
Normal file
67
src/internal/syscall/unix/kernel_version_ge_test.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2025 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 unix_test
|
||||
|
||||
import (
|
||||
"internal/syscall/unix"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestKernelVersionGE(t *testing.T) {
|
||||
major, minor := unix.KernelVersion()
|
||||
t.Logf("Running on kernel %d.%d", major, minor)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
x, y int
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "current version equals itself",
|
||||
x: major,
|
||||
y: minor,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "older major version",
|
||||
x: major - 1,
|
||||
y: 0,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "same major, older minor version",
|
||||
x: major,
|
||||
y: minor - 1,
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "newer major version",
|
||||
x: major + 1,
|
||||
y: 0,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "same major, newer minor version",
|
||||
x: major,
|
||||
y: minor + 1,
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "min version (0.0)",
|
||||
x: 0,
|
||||
y: 0,
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := unix.KernelVersionGE(tt.x, tt.y)
|
||||
if got != tt.want {
|
||||
t.Errorf("KernelVersionGE(%d, %d): got %v, want %v", tt.x, tt.y, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -77,11 +77,10 @@ var SupportSockNonblockCloexec = sync.OnceValue(func() bool {
|
|||
}
|
||||
if err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL {
|
||||
// Something wrong with socket(), fall back to checking the kernel version.
|
||||
major, minor := KernelVersion()
|
||||
if runtime.GOOS == "illumos" {
|
||||
return major > 5 || (major == 5 && minor >= 11) // minimal requirement is SunOS 5.11
|
||||
return KernelVersionGE(5, 11) // Minimal requirement is SunOS 5.11.
|
||||
}
|
||||
return major > 11 || (major == 11 && minor >= 4)
|
||||
return KernelVersionGE(11, 4)
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
@ -101,6 +100,5 @@ var SupportAccept4 = sync.OnceValue(func() bool {
|
|||
// SupportTCPKeepAliveIdleIntvlCNT determines whether the TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT
|
||||
// are available by checking the kernel version for Solaris 11.4.
|
||||
var SupportTCPKeepAliveIdleIntvlCNT = sync.OnceValue(func() bool {
|
||||
major, minor := KernelVersion()
|
||||
return major > 11 || (major == 11 && minor >= 4)
|
||||
return KernelVersionGE(11, 4)
|
||||
})
|
||||
|
|
|
@ -53,9 +53,8 @@ func initMPTCPavailable() {
|
|||
mptcpAvailable = true
|
||||
}
|
||||
|
||||
major, minor := unix.KernelVersion()
|
||||
// SOL_MPTCP only supported from kernel 5.16
|
||||
hasSOLMPTCP = major > 5 || (major == 5 && minor >= 16)
|
||||
// SOL_MPTCP only supported from kernel 5.16.
|
||||
hasSOLMPTCP = unix.KernelVersionGE(5, 16)
|
||||
}
|
||||
|
||||
func (sd *sysDialer) dialMPTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
|
||||
|
|
|
@ -18,9 +18,8 @@ import (
|
|||
//
|
||||
// See issue 5030 and 41470.
|
||||
func maxAckBacklog(n int) int {
|
||||
major, minor := unix.KernelVersion()
|
||||
size := 16
|
||||
if major > 4 || (major == 4 && minor >= 1) {
|
||||
if unix.KernelVersionGE(4, 1) {
|
||||
size = 32
|
||||
}
|
||||
|
||||
|
|
|
@ -11,13 +11,12 @@ import (
|
|||
|
||||
func TestMaxAckBacklog(t *testing.T) {
|
||||
n := 196602
|
||||
major, minor := unix.KernelVersion()
|
||||
backlog := maxAckBacklog(n)
|
||||
expected := 1<<16 - 1
|
||||
if major > 4 || (major == 4 && minor >= 1) {
|
||||
if unix.KernelVersionGE(4, 1) {
|
||||
expected = n
|
||||
}
|
||||
if backlog != expected {
|
||||
t.Fatalf(`Kernel version: "%d.%d", sk_max_ack_backlog mismatch, got %d, want %d`, major, minor, backlog, expected)
|
||||
t.Fatalf(`sk_max_ack_backlog mismatch, got %d, want %d`, backlog, expected)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ func TestFindExecutableVsNoexec(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
// This test case relies on faccessat2(2) syscall, which appeared in Linux v5.8.
|
||||
if major, minor := unix.KernelVersion(); major < 5 || (major == 5 && minor < 8) {
|
||||
if !unix.KernelVersionGE(5, 8) {
|
||||
t.Skip("requires Linux kernel v5.8 with faccessat2(2) syscall")
|
||||
}
|
||||
|
||||
|
|
|
@ -117,10 +117,6 @@ func TestCPUProfileMultithreadMagnitude(t *testing.T) {
|
|||
t.Skip("issue 35057 is only confirmed on Linux")
|
||||
}
|
||||
|
||||
// Linux [5.9,5.16) has a kernel bug that can break CPU timers on newly
|
||||
// created threads, breaking our CPU accounting.
|
||||
major, minor := unix.KernelVersion()
|
||||
t.Logf("Running on Linux %d.%d", major, minor)
|
||||
defer func() {
|
||||
if t.Failed() {
|
||||
t.Logf("Failure of this test may indicate that your system suffers from a known Linux kernel bug fixed on newer kernels. See https://golang.org/issue/49065.")
|
||||
|
@ -131,9 +127,9 @@ func TestCPUProfileMultithreadMagnitude(t *testing.T) {
|
|||
// it enabled to potentially warn users that they are on a broken
|
||||
// kernel.
|
||||
if testenv.Builder() != "" && (runtime.GOARCH == "386" || runtime.GOARCH == "amd64") {
|
||||
have59 := major > 5 || (major == 5 && minor >= 9)
|
||||
have516 := major > 5 || (major == 5 && minor >= 16)
|
||||
if have59 && !have516 {
|
||||
// Linux [5.9,5.16) has a kernel bug that can break CPU timers on newly
|
||||
// created threads, breaking our CPU accounting.
|
||||
if unix.KernelVersionGE(5, 9) && !unix.KernelVersionGE(5, 16) {
|
||||
testenv.SkipFlaky(t, 49065)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue