mirror of
https://github.com/golang/go
synced 2024-11-18 06:14:46 -07:00
internal/poll: disable splice on old linux versions
The splice syscall is buggy prior to linux 2.6.29. Instead of returning 0 when reading a closed socket, it returns EAGAIN. While it is possible to detect this (HAProxy falls back to recv), it is simpiler to avoid using splice all together. the "fcntl(fd, F_GETPIPE_SZ)" syscall is used detect buggy versions of splice as the syscall returns EINVAL on versions prior to 2.6.35. Fixes #25486 Change-Id: I860c029f13de2b09e95a7ba39b76ac7fca91a195 Reviewed-on: https://go-review.googlesource.com/113999 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
132900982c
commit
92bdfab795
@ -4,7 +4,11 @@
|
|||||||
|
|
||||||
package poll
|
package poll
|
||||||
|
|
||||||
import "syscall"
|
import (
|
||||||
|
"sync/atomic"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// spliceNonblock makes calls to splice(2) non-blocking.
|
// spliceNonblock makes calls to splice(2) non-blocking.
|
||||||
@ -134,43 +138,38 @@ func splice(out int, in int, max int, flags int) (int, error) {
|
|||||||
return int(n), err
|
return int(n), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var disableSplice unsafe.Pointer
|
||||||
|
|
||||||
// newTempPipe sets up a temporary pipe for a splice operation.
|
// newTempPipe sets up a temporary pipe for a splice operation.
|
||||||
func newTempPipe() (prfd, pwfd int, sc string, err error) {
|
func newTempPipe() (prfd, pwfd int, sc string, err error) {
|
||||||
|
p := (*bool)(atomic.LoadPointer(&disableSplice))
|
||||||
|
if p != nil && *p {
|
||||||
|
return -1, -1, "splice", syscall.EINVAL
|
||||||
|
}
|
||||||
|
|
||||||
var fds [2]int
|
var fds [2]int
|
||||||
|
// pipe2 was added in 2.6.27 and our minimum requirement is 2.6.23, so it
|
||||||
|
// might not be implemented. Falling back to pipe is possible, but prior to
|
||||||
|
// 2.6.29 splice returns -EAGAIN instead of 0 when the connection is
|
||||||
|
// closed.
|
||||||
const flags = syscall.O_CLOEXEC | syscall.O_NONBLOCK
|
const flags = syscall.O_CLOEXEC | syscall.O_NONBLOCK
|
||||||
if err := syscall.Pipe2(fds[:], flags); err != nil {
|
if err := syscall.Pipe2(fds[:], flags); err != nil {
|
||||||
// pipe2 was added in 2.6.27 and our minimum requirement
|
|
||||||
// is 2.6.23, so it might not be implemented.
|
|
||||||
if err == syscall.ENOSYS {
|
|
||||||
return newTempPipeFallback(fds[:])
|
|
||||||
}
|
|
||||||
return -1, -1, "pipe2", err
|
return -1, -1, "pipe2", err
|
||||||
}
|
}
|
||||||
return fds[0], fds[1], "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newTempPipeFallback is a fallback for newTempPipe, for systems
|
if p == nil {
|
||||||
// which do not support pipe2.
|
p = new(bool)
|
||||||
func newTempPipeFallback(fds []int) (prfd, pwfd int, sc string, err error) {
|
defer atomic.StorePointer(&disableSplice, unsafe.Pointer(p))
|
||||||
syscall.ForkLock.RLock()
|
|
||||||
defer syscall.ForkLock.RUnlock()
|
// F_GETPIPE_SZ was added in 2.6.35, which does not have the -EAGAIN bug.
|
||||||
if err := syscall.Pipe(fds); err != nil {
|
if _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fds[0]), syscall.F_GETPIPE_SZ, 0); errno != 0 {
|
||||||
return -1, -1, "pipe", err
|
*p = true
|
||||||
|
destroyTempPipe(fds[0], fds[1])
|
||||||
|
return -1, -1, "fcntl", errno
|
||||||
|
}
|
||||||
}
|
}
|
||||||
prfd, pwfd = fds[0], fds[1]
|
|
||||||
syscall.CloseOnExec(prfd)
|
return fds[0], fds[1], "", nil
|
||||||
syscall.CloseOnExec(pwfd)
|
|
||||||
if err := syscall.SetNonblock(prfd, true); err != nil {
|
|
||||||
CloseFunc(prfd)
|
|
||||||
CloseFunc(pwfd)
|
|
||||||
return -1, -1, "setnonblock", err
|
|
||||||
}
|
|
||||||
if err := syscall.SetNonblock(pwfd, true); err != nil {
|
|
||||||
CloseFunc(prfd)
|
|
||||||
CloseFunc(pwfd)
|
|
||||||
return -1, -1, "setnonblock", err
|
|
||||||
}
|
|
||||||
return prfd, pwfd, "", nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// destroyTempPipe destroys a temporary pipe.
|
// destroyTempPipe destroys a temporary pipe.
|
||||||
|
Loading…
Reference in New Issue
Block a user