mirror of
https://github.com/golang/go
synced 2024-11-15 06:50:32 -07:00
internal/poll: handle (0, EINVAL) return from sendfile on Solaris
Also check for GOOS=illumos as well as GOOS=solaris. Change-Id: I887e6cddc1b8ad0f4624c9491e089c6bb8bce70e Reviewed-on: https://go-review.googlesource.com/c/go/+/622977 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Commit-Queue: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com>
This commit is contained in:
parent
76a8409eb8
commit
0fd414c652
@ -36,11 +36,9 @@ func SendFile(dstFD *FD, src int, size int64) (n int64, err error, handled bool)
|
|||||||
return sendFile(dstFD, src, nil, size)
|
return sendFile(dstFD, src, nil, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Darwin/FreeBSD/DragonFly/Solaris's sendfile implementation
|
// Non-Linux sendfile implementations don't use the current position of the source file,
|
||||||
// doesn't use the current position of the file --
|
// so we need to look up the position, pass it explicitly, and adjust it after
|
||||||
// if you pass it offset 0, it starts from offset 0.
|
// sendfile returns.
|
||||||
// There's no way to tell it "start from current position",
|
|
||||||
// so we have to manage that explicitly.
|
|
||||||
start, err := ignoringEINTR2(func() (int64, error) {
|
start, err := ignoringEINTR2(func() (int64, error) {
|
||||||
return syscall.Seek(src, 0, io.SeekCurrent)
|
return syscall.Seek(src, 0, io.SeekCurrent)
|
||||||
})
|
})
|
||||||
@ -48,36 +46,23 @@ func SendFile(dstFD *FD, src int, size int64) (n int64, err error, handled bool)
|
|||||||
return 0, err, false
|
return 0, err, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Solaris requires us to pass a length to send,
|
|
||||||
// rather than accepting 0 as "send everything".
|
|
||||||
//
|
|
||||||
// Seek to the end of the source file to find its length.
|
|
||||||
//
|
|
||||||
// Important: If we ever remove this block
|
|
||||||
// (because Solaris has added a way to send everything, or we discovered a
|
|
||||||
// previously-unknown existing way),
|
|
||||||
// then some of the sendFile function will need updating.
|
|
||||||
//
|
|
||||||
// On Solaris, sendfile can return n>0 and EINVAL when successfully copying to a file.
|
|
||||||
// We ignore the EINVAL in this case.
|
|
||||||
//
|
|
||||||
// On non-Solaris platforms, when size==0 we call sendfile until it returns
|
|
||||||
// n==0 and success, indicating that it has copied the entire source file.
|
|
||||||
// If we were to do this on Solaris, then the final sendfile call could return (0, EINVAL),
|
|
||||||
// which we would treat as an error rather than successful completion of the copy.
|
|
||||||
// This never happens, because when size==0 on Solaris,
|
|
||||||
// we look up the actual file size here.
|
|
||||||
// If we change that, we need to handle the (0, EINVAL) case below.
|
|
||||||
mustReposition := false
|
mustReposition := false
|
||||||
if runtime.GOOS == "solaris" && size == 0 {
|
switch runtime.GOOS {
|
||||||
end, err := ignoringEINTR2(func() (int64, error) {
|
case "solaris", "illumos":
|
||||||
return syscall.Seek(src, 0, io.SeekEnd)
|
// Solaris/illumos requires us to pass a length to send,
|
||||||
})
|
// rather than accepting 0 as "send everything".
|
||||||
if err != nil {
|
//
|
||||||
return 0, err, false
|
// Seek to the end of the source file to find its length.
|
||||||
|
if size == 0 {
|
||||||
|
end, err := ignoringEINTR2(func() (int64, error) {
|
||||||
|
return syscall.Seek(src, 0, io.SeekEnd)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err, false
|
||||||
|
}
|
||||||
|
size = end - start
|
||||||
|
mustReposition = true
|
||||||
}
|
}
|
||||||
size = end - start
|
|
||||||
mustReposition = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pos := start
|
pos := start
|
||||||
@ -115,6 +100,22 @@ func sendFile(dstFD *FD, src int, offset *int64, size int64) (written int64, err
|
|||||||
if n > 0 {
|
if n > 0 {
|
||||||
written += int64(n)
|
written += int64(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "solaris", "illumos":
|
||||||
|
// A quirk on Solaris/illumos: sendfile() claims to support out_fd
|
||||||
|
// as a regular file but returns EINVAL when the out_fd
|
||||||
|
// is not a socket of SOCK_STREAM, while it actually sends
|
||||||
|
// out data anyway and updates the file offset.
|
||||||
|
//
|
||||||
|
// We ignore EINVAL if any sendfile call returned n > 0,
|
||||||
|
// to handle the case where the last call returns 0 to indicate
|
||||||
|
// no more data to send.
|
||||||
|
if err == syscall.EINVAL && written > 0 {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch err {
|
switch err {
|
||||||
case nil:
|
case nil:
|
||||||
// We're done if sendfile copied no bytes
|
// We're done if sendfile copied no bytes
|
||||||
@ -158,18 +159,11 @@ func sendFileChunk(dst, src int, offset *int64, size int) (n int, err error) {
|
|||||||
case "linux":
|
case "linux":
|
||||||
// The offset is always nil on Linux.
|
// The offset is always nil on Linux.
|
||||||
n, err = syscall.Sendfile(dst, src, offset, size)
|
n, err = syscall.Sendfile(dst, src, offset, size)
|
||||||
case "solaris":
|
case "solaris", "illumos":
|
||||||
// Trust the offset, not the return value from sendfile.
|
// Trust the offset, not the return value from sendfile.
|
||||||
start := *offset
|
start := *offset
|
||||||
n, err = syscall.Sendfile(dst, src, offset, size)
|
n, err = syscall.Sendfile(dst, src, offset, size)
|
||||||
n = int(*offset - start)
|
n = int(*offset - start)
|
||||||
// A quirk on Solaris: sendfile() claims to support out_fd
|
|
||||||
// as a regular file but returns EINVAL when the out_fd
|
|
||||||
// is not a socket of SOCK_STREAM, while it actually sends
|
|
||||||
// out data anyway and updates the file offset.
|
|
||||||
if err == syscall.EINVAL && n > 0 {
|
|
||||||
err = nil
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
start := *offset
|
start := *offset
|
||||||
n, err = syscall.Sendfile(dst, src, offset, size)
|
n, err = syscall.Sendfile(dst, src, offset, size)
|
||||||
|
Loading…
Reference in New Issue
Block a user