mirror of
https://github.com/golang/go
synced 2024-11-18 10:54:40 -07:00
internal/syscall/unix: consolidate kernelVersion implementations
Currently, there are 3 functions returning Linux kernel version numbers.
Two of them are identical:
- in net, initially added by commit 0a9dd47dd817904e;
- in internal/poll, initially added by commit 1c7650aa93bd53;
(both were later fixed by commit 66c0264506
).
The third one is a more complex, regexp-based implementation in
runtime/pprof, which is only used for a test.
Instead of adding one more, let's consolidate existing ones.
Remove the complex implementation, and move the simple one into
internal/syscall/unix. Use it from all the three places mentioned above.
Change-Id: I4a34d9ca47257743c16def30e4dd634e36056091
Reviewed-on: https://go-review.googlesource.com/c/go/+/424896
Run-TryBot: Ian Lance Taylor <iant@google.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Run-TryBot: Kirill Kolyshkin <kolyshkin@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
2392b7061c
commit
a73506cff5
@ -17,46 +17,11 @@ var (
|
||||
|
||||
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) {
|
||||
kernelVersion53Once.Do(func() {
|
||||
major, minor := kernelVersion()
|
||||
major, minor := unix.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
|
||||
|
49
src/internal/syscall/unix/kernel_version_linux.go
Normal file
49
src/internal/syscall/unix/kernel_version_linux.go
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2022 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
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// KernelVersion returns major and minor kernel version numbers, parsed from
|
||||
// the syscall.Uname's Release field, or 0, 0 if the version can't be obtained
|
||||
// or parsed.
|
||||
//
|
||||
// Currently only implemented for Linux.
|
||||
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
|
||||
}
|
11
src/internal/syscall/unix/kernel_version_other.go
Normal file
11
src/internal/syscall/unix/kernel_version_other.go
Normal file
@ -0,0 +1,11 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
//go:build !linux
|
||||
|
||||
package unix
|
||||
|
||||
func KernelVersion() (major int, minor int) {
|
||||
return 0, 0
|
||||
}
|
@ -4,42 +4,10 @@
|
||||
|
||||
package net
|
||||
|
||||
import "syscall"
|
||||
|
||||
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 c >= '0' && 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
|
||||
}
|
||||
import (
|
||||
"internal/syscall/unix"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Linux stores the backlog as:
|
||||
//
|
||||
@ -50,7 +18,7 @@ func kernelVersion() (major int, minor int) {
|
||||
//
|
||||
// See issue 5030 and 41470.
|
||||
func maxAckBacklog(n int) int {
|
||||
major, minor := kernelVersion()
|
||||
major, minor := unix.KernelVersion()
|
||||
size := 16
|
||||
if major > 4 || (major == 4 && minor >= 1) {
|
||||
size = 32
|
||||
|
@ -5,12 +5,13 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"internal/syscall/unix"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMaxAckBacklog(t *testing.T) {
|
||||
n := 196602
|
||||
major, minor := kernelVersion()
|
||||
major, minor := unix.KernelVersion()
|
||||
backlog := maxAckBacklog(n)
|
||||
expected := 1<<16 - 1
|
||||
if major > 4 || (major == 4 && minor >= 1) {
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"fmt"
|
||||
"internal/abi"
|
||||
"internal/profile"
|
||||
"internal/syscall/unix"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"math"
|
||||
@ -116,11 +117,8 @@ func TestCPUProfileMultithreadMagnitude(t *testing.T) {
|
||||
|
||||
// Linux [5.9,5.16) has a kernel bug that can break CPU timers on newly
|
||||
// created threads, breaking our CPU accounting.
|
||||
major, minor, patch, err := linuxKernelVersion()
|
||||
if err != nil {
|
||||
t.Errorf("Error determining kernel version: %v", err)
|
||||
}
|
||||
t.Logf("Running on Linux %d.%d.%d", major, minor, patch)
|
||||
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.")
|
||||
|
@ -1,61 +0,0 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
//go:build linux
|
||||
|
||||
package pprof
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var versionRe = regexp.MustCompile(`^(\d+)(?:\.(\d+)(?:\.(\d+))).*$`)
|
||||
|
||||
func linuxKernelVersion() (major, minor, patch int, err error) {
|
||||
var uname syscall.Utsname
|
||||
if err := syscall.Uname(&uname); err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
|
||||
buf := make([]byte, 0, len(uname.Release))
|
||||
for _, b := range uname.Release {
|
||||
if b == 0 {
|
||||
break
|
||||
}
|
||||
buf = append(buf, byte(b))
|
||||
}
|
||||
rl := string(buf)
|
||||
|
||||
m := versionRe.FindStringSubmatch(rl)
|
||||
if m == nil {
|
||||
return 0, 0, 0, fmt.Errorf("error matching version number in %q", rl)
|
||||
}
|
||||
|
||||
v, err := strconv.ParseInt(m[1], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, 0, fmt.Errorf("error parsing major version %q in %s: %w", m[1], rl, err)
|
||||
}
|
||||
major = int(v)
|
||||
|
||||
if len(m) >= 3 {
|
||||
v, err := strconv.ParseInt(m[2], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, 0, fmt.Errorf("error parsing minor version %q in %s: %w", m[2], rl, err)
|
||||
}
|
||||
minor = int(v)
|
||||
}
|
||||
|
||||
if len(m) >= 4 {
|
||||
v, err := strconv.ParseInt(m[3], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, 0, fmt.Errorf("error parsing patch version %q in %s: %w", m[3], rl, err)
|
||||
}
|
||||
patch = int(v)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
//go:build !linux
|
||||
|
||||
package pprof
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
func linuxKernelVersion() (major, minor, patch int, err error) {
|
||||
return 0, 0, 0, errors.New("not running on linux")
|
||||
}
|
Loading…
Reference in New Issue
Block a user