Skip to content

Commit e6b3bd9

Browse files
committed
vsock/internal/poll: hard vendoring go/internal/poll@74e384f50d30
Signed-off-by: Koichi Shiraishi <[email protected]>
1 parent c698b4b commit e6b3bd9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+5101
-0
lines changed

vsock/internal/poll/LICENSE

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Copyright (c) 2009 The Go Authors. All rights reserved.
2+
3+
Redistribution and use in source and binary forms, with or without
4+
modification, are permitted provided that the following conditions are
5+
met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above
10+
copyright notice, this list of conditions and the following disclaimer
11+
in the documentation and/or other materials provided with the
12+
distribution.
13+
* Neither the name of Google Inc. nor the names of its
14+
contributors may be used to endorse or promote products derived from
15+
this software without specific prior written permission.
16+
17+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

vsock/internal/poll/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# poll
2+
3+
This package forked and edit from [go/src/internal/poll@74e384f50d30](https://github.com/golang/go/tree/74e384f50d30/src/internal/poll)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package poll
6+
7+
import (
8+
"sync/atomic"
9+
"syscall"
10+
11+
"golang.org/x/sys/unix"
12+
)
13+
14+
var copyFileRangeSupported int32 = -1 // accessed atomically
15+
16+
const maxCopyFileRangeRound = 1 << 30
17+
18+
func kernelVersion() (major int, minor int) {
19+
var uname syscall.Utsname
20+
if err := syscall.Uname(&uname); err != nil {
21+
return
22+
}
23+
24+
rl := uname.Release
25+
var values [2]int
26+
vi := 0
27+
value := 0
28+
for _, c := range rl {
29+
if '0' <= c && c <= '9' {
30+
value = (value * 10) + int(c-'0')
31+
} else {
32+
// Note that we're assuming N.N.N here. If we see anything else we are likely to
33+
// mis-parse it.
34+
values[vi] = value
35+
vi++
36+
if vi >= len(values) {
37+
break
38+
}
39+
value = 0
40+
}
41+
}
42+
switch vi {
43+
case 0:
44+
return 0, 0
45+
case 1:
46+
return values[0], 0
47+
case 2:
48+
return values[0], values[1]
49+
}
50+
return
51+
}
52+
53+
// CopyFileRange copies at most remain bytes of data from src to dst, using
54+
// the copy_file_range system call. dst and src must refer to regular files.
55+
func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err error) {
56+
if supported := atomic.LoadInt32(&copyFileRangeSupported); supported == 0 {
57+
return 0, false, nil
58+
} else if supported == -1 {
59+
major, minor := kernelVersion()
60+
if major > 5 || (major == 5 && minor >= 3) {
61+
atomic.StoreInt32(&copyFileRangeSupported, 1)
62+
} else {
63+
// copy_file_range(2) is broken in various ways on kernels older than 5.3,
64+
// see issue #42400 and
65+
// https://man7.org/linux/man-pages/man2/copy_file_range.2.html#VERSIONS
66+
atomic.StoreInt32(&copyFileRangeSupported, 0)
67+
return 0, false, nil
68+
}
69+
}
70+
for remain > 0 {
71+
max := remain
72+
if max > maxCopyFileRangeRound {
73+
max = maxCopyFileRangeRound
74+
}
75+
n, err := copyFileRange(dst, src, int(max))
76+
switch err {
77+
case syscall.ENOSYS:
78+
// copy_file_range(2) was introduced in Linux 4.5.
79+
// Go supports Linux >= 2.6.33, so the system call
80+
// may not be present.
81+
//
82+
// If we see ENOSYS, we have certainly not transferred
83+
// any data, so we can tell the caller that we
84+
// couldn't handle the transfer and let them fall
85+
// back to more generic code.
86+
//
87+
// Seeing ENOSYS also means that we will not try to
88+
// use copy_file_range(2) again.
89+
atomic.StoreInt32(&copyFileRangeSupported, 0)
90+
return 0, false, nil
91+
case syscall.EXDEV, syscall.EINVAL, syscall.EIO, syscall.EOPNOTSUPP, syscall.EPERM:
92+
// Prior to Linux 5.3, it was not possible to
93+
// copy_file_range across file systems. Similarly to
94+
// the ENOSYS case above, if we see EXDEV, we have
95+
// not transferred any data, and we can let the caller
96+
// fall back to generic code.
97+
//
98+
// As for EINVAL, that is what we see if, for example,
99+
// dst or src refer to a pipe rather than a regular
100+
// file. This is another case where no data has been
101+
// transferred, so we consider it unhandled.
102+
//
103+
// If src and dst are on CIFS, we can see EIO.
104+
// See issue #42334.
105+
//
106+
// If the file is on NFS, we can see EOPNOTSUPP.
107+
// See issue #40731.
108+
//
109+
// If the process is running inside a Docker container,
110+
// we might see EPERM instead of ENOSYS. See issue
111+
// #40893. Since EPERM might also be a legitimate error,
112+
// don't mark copy_file_range(2) as unsupported.
113+
return 0, false, nil
114+
case nil:
115+
if n == 0 {
116+
// If we did not read any bytes at all,
117+
// then this file may be in a file system
118+
// where copy_file_range silently fails.
119+
// https://lore.kernel.org/linux-fsdevel/[email protected]/T/#m05753578c7f7882f6e9ffe01f981bc223edef2b0
120+
if written == 0 {
121+
return 0, false, nil
122+
}
123+
// Otherwise src is at EOF, which means
124+
// we are done.
125+
return written, true, nil
126+
}
127+
remain -= n
128+
written += n
129+
default:
130+
return written, true, err
131+
}
132+
}
133+
return written, true, nil
134+
}
135+
136+
// copyFileRange performs one round of copy_file_range(2).
137+
func copyFileRange(dst, src *FD, max int) (written int64, err error) {
138+
// The signature of copy_file_range(2) is:
139+
//
140+
// ssize_t copy_file_range(int fd_in, loff_t *off_in,
141+
// int fd_out, loff_t *off_out,
142+
// size_t len, unsigned int flags);
143+
//
144+
// Note that in the call to unix.CopyFileRange below, we use nil
145+
// values for off_in and off_out. For the system call, this means
146+
// "use and update the file offsets". That is why we must acquire
147+
// locks for both file descriptors (and why this whole machinery is
148+
// in the internal/poll package to begin with).
149+
if err := dst.writeLock(); err != nil {
150+
return 0, err
151+
}
152+
defer dst.writeUnlock()
153+
if err := src.readLock(); err != nil {
154+
return 0, err
155+
}
156+
defer src.readUnlock()
157+
var n int
158+
for {
159+
n, err = unix.CopyFileRange(src.Sysfd, nil, dst.Sysfd, nil, max, 0)
160+
if err != syscall.EINTR {
161+
break
162+
}
163+
}
164+
return int64(n), err
165+
}

vsock/internal/poll/errno_unix.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
6+
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
7+
8+
package poll
9+
10+
import "syscall"
11+
12+
// Do the interface allocations only once for common
13+
// Errno values.
14+
var (
15+
errEAGAIN error = syscall.EAGAIN
16+
errEINVAL error = syscall.EINVAL
17+
errENOENT error = syscall.ENOENT
18+
)
19+
20+
// errnoErr returns common boxed Errno values, to prevent
21+
// allocations at runtime.
22+
func errnoErr(e syscall.Errno) error {
23+
switch e {
24+
case 0:
25+
return nil
26+
case syscall.EAGAIN:
27+
return errEAGAIN
28+
case syscall.EINVAL:
29+
return errEINVAL
30+
case syscall.ENOENT:
31+
return errENOENT
32+
}
33+
return e
34+
}

vsock/internal/poll/errno_windows.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build windows
6+
// +build windows
7+
8+
package poll
9+
10+
import "syscall"
11+
12+
// Do the interface allocations only once for common
13+
// Errno values.
14+
15+
var (
16+
errERROR_IO_PENDING error = syscall.Errno(syscall.ERROR_IO_PENDING)
17+
)
18+
19+
// ErrnoErr returns common boxed Errno values, to prevent
20+
// allocations at runtime.
21+
func errnoErr(e syscall.Errno) error {
22+
switch e {
23+
case 0:
24+
return nil
25+
case syscall.ERROR_IO_PENDING:
26+
return errERROR_IO_PENDING
27+
}
28+
// TODO: add more here, after collecting data on the common
29+
// error values see on Windows. (perhaps when running
30+
// all.bat?)
31+
return e
32+
}
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package poll_test
6+
7+
import (
8+
"errors"
9+
"os"
10+
"syscall"
11+
12+
"github.com/go-hypervisor/virtio/vsock/internal/poll"
13+
)
14+
15+
func badStateFile() (*os.File, error) {
16+
if os.Getuid() != 0 {
17+
return nil, errors.New("must be root")
18+
}
19+
// Using OpenFile for a device file is an easy way to make a
20+
// file attached to the runtime-integrated network poller and
21+
// configured in halfway.
22+
return os.OpenFile("/dev/net/tun", os.O_RDWR, 0)
23+
}
24+
25+
func isBadStateFileError(err error) (string, bool) {
26+
switch err {
27+
case poll.ErrNotPollable, syscall.EBADFD:
28+
return "", true
29+
default:
30+
return "not pollable or file in bad state error", false
31+
}
32+
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build !linux
6+
// +build !linux
7+
8+
package poll_test
9+
10+
import (
11+
"errors"
12+
"os"
13+
"runtime"
14+
)
15+
16+
func badStateFile() (*os.File, error) {
17+
return nil, errors.New("not supported on " + runtime.GOOS)
18+
}
19+
20+
func isBadStateFileError(err error) (string, bool) {
21+
return "", false
22+
}

vsock/internal/poll/error_test.go

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2019 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package poll_test
6+
7+
import (
8+
"fmt"
9+
"io/fs"
10+
"net"
11+
"os"
12+
"testing"
13+
"time"
14+
)
15+
16+
func TestReadError(t *testing.T) {
17+
t.Run("ErrNotPollable", func(t *testing.T) {
18+
f, err := badStateFile()
19+
if err != nil {
20+
t.Skip(err)
21+
}
22+
defer f.Close()
23+
24+
// Give scheduler a chance to have two separated
25+
// goroutines: an event poller and an event waiter.
26+
time.Sleep(100 * time.Millisecond)
27+
28+
var b [1]byte
29+
_, err = f.Read(b[:])
30+
if perr := parseReadError(err, isBadStateFileError); perr != nil {
31+
t.Fatal(perr)
32+
}
33+
})
34+
}
35+
36+
func parseReadError(nestedErr error, verify func(error) (string, bool)) error {
37+
err := nestedErr
38+
if nerr, ok := err.(*net.OpError); ok {
39+
err = nerr.Err
40+
}
41+
if nerr, ok := err.(*fs.PathError); ok {
42+
err = nerr.Err
43+
}
44+
if nerr, ok := err.(*os.SyscallError); ok {
45+
err = nerr.Err
46+
}
47+
if s, ok := verify(err); !ok {
48+
return fmt.Errorf("got %v; want %s", nestedErr, s)
49+
}
50+
return nil
51+
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Export guts for testing on linux.
6+
// Since testing imports os and os imports internal/poll,
7+
// the internal/poll tests can not be in package poll.
8+
9+
package poll
10+
11+
var (
12+
GetPipe = getPipe
13+
PutPipe = putPipe
14+
NewPipe = newPipe
15+
DestroyPipe = destroyPipe
16+
)
17+
18+
func GetPipeFds(p *SplicePipe) (int, int) {
19+
return p.rfd, p.wfd
20+
}
21+
22+
type SplicePipe = splicePipe

0 commit comments

Comments
 (0)