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
|
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
|
// 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) {
|
||||||
kernelVersion53Once.Do(func() {
|
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,
|
// copy_file_range(2) is broken in various ways on kernels older than 5.3,
|
||||||
// see issue #42400 and
|
// see issue #42400 and
|
||||||
// https://man7.org/linux/man-pages/man2/copy_file_range.2.html#VERSIONS
|
// 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
|
package net
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"internal/syscall/unix"
|
||||||
func kernelVersion() (major int, minor int) {
|
"syscall"
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Linux stores the backlog as:
|
// Linux stores the backlog as:
|
||||||
//
|
//
|
||||||
@ -50,7 +18,7 @@ func kernelVersion() (major int, minor int) {
|
|||||||
//
|
//
|
||||||
// See issue 5030 and 41470.
|
// See issue 5030 and 41470.
|
||||||
func maxAckBacklog(n int) int {
|
func maxAckBacklog(n int) int {
|
||||||
major, minor := kernelVersion()
|
major, minor := unix.KernelVersion()
|
||||||
size := 16
|
size := 16
|
||||||
if major > 4 || (major == 4 && minor >= 1) {
|
if major > 4 || (major == 4 && minor >= 1) {
|
||||||
size = 32
|
size = 32
|
||||||
|
@ -5,12 +5,13 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/syscall/unix"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMaxAckBacklog(t *testing.T) {
|
func TestMaxAckBacklog(t *testing.T) {
|
||||||
n := 196602
|
n := 196602
|
||||||
major, minor := kernelVersion()
|
major, minor := unix.KernelVersion()
|
||||||
backlog := maxAckBacklog(n)
|
backlog := maxAckBacklog(n)
|
||||||
expected := 1<<16 - 1
|
expected := 1<<16 - 1
|
||||||
if major > 4 || (major == 4 && minor >= 1) {
|
if major > 4 || (major == 4 && minor >= 1) {
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"internal/abi"
|
"internal/abi"
|
||||||
"internal/profile"
|
"internal/profile"
|
||||||
|
"internal/syscall/unix"
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"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
|
// Linux [5.9,5.16) has a kernel bug that can break CPU timers on newly
|
||||||
// created threads, breaking our CPU accounting.
|
// created threads, breaking our CPU accounting.
|
||||||
major, minor, patch, err := linuxKernelVersion()
|
major, minor := unix.KernelVersion()
|
||||||
if err != nil {
|
t.Logf("Running on Linux %d.%d", major, minor)
|
||||||
t.Errorf("Error determining kernel version: %v", err)
|
|
||||||
}
|
|
||||||
t.Logf("Running on Linux %d.%d.%d", major, minor, patch)
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if t.Failed() {
|
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.")
|
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