1
0
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:
Kir Kolyshkin 2022-08-18 13:43:47 -07:00 committed by Gopher Robot
parent 2392b7061c
commit a73506cff5
8 changed files with 71 additions and 155 deletions

View File

@ -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

View 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
}

View 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
}

View File

@ -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

View File

@ -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) {

View File

@ -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.")

View File

@ -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
}

View File

@ -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")
}