From: Andy Pan Date: Tue, 29 Oct 2024 04:27:30 +0000 (+0800) Subject: internal/poll: confine runtime OS-checks to sendFileChunk X-Git-Tag: go1.24rc1~516 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=91ec6b6321395ba787a9b4c0ae1055ab45382435;p=gostls13.git internal/poll: confine runtime OS-checks to sendFileChunk Ref: https://ci.chromium.org/ui/p/golang/builders/ci/gotip-solaris-amd64/b8732788420094473425/overview https://build.golang.org/log/80a05c426ceaebd0906eae80e5a3afd7e92d2f41 Change-Id: I207c0043ce729be7bbba39cf376b6d39440e7f26 Reviewed-on: https://go-review.googlesource.com/c/go/+/623055 Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor --- diff --git a/src/internal/poll/sendfile_unix.go b/src/internal/poll/sendfile_unix.go index dc81c4ad89..1426a1229b 100644 --- a/src/internal/poll/sendfile_unix.go +++ b/src/internal/poll/sendfile_unix.go @@ -80,26 +80,10 @@ func sendFile(dstFD *FD, src int, offset *int64, size int64) (written int64, err chunk = int(min(size-written, int64(chunk))) } var n int - n, err = sendFileChunk(dst, src, offset, chunk) + n, err = sendFileChunk(dst, src, offset, chunk, written) if n > 0 { 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 { case nil: // We're done if sendfile copied no bytes @@ -123,8 +107,8 @@ func sendFile(dstFD *FD, src int, offset *int64, size int64) (written int64, err return written, err, true } case syscall.EINTR: - // Ignore. - case syscall.ENOSYS, syscall.EINVAL, syscall.EOPNOTSUPP: + // Retry. + case syscall.ENOSYS, syscall.EOPNOTSUPP, syscall.EINVAL: // ENOSYS indicates no kernel support for sendfile. // EINVAL indicates a FD type which does not support sendfile. // @@ -138,7 +122,7 @@ func sendFile(dstFD *FD, src int, offset *int64, size int64) (written int64, err } } -func sendFileChunk(dst, src int, offset *int64, size int) (n int, err error) { +func sendFileChunk(dst, src int, offset *int64, size int, written int64) (n int, err error) { switch runtime.GOOS { case "linux": // The offset is always nil on Linux. @@ -148,6 +132,21 @@ func sendFileChunk(dst, src int, offset *int64, size int) (n int, err error) { start := *offset n, err = syscall.Sendfile(dst, src, offset, size) n = int(*offset - start) + // 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. + // + // Another quirk: sendfile transfers data and returns EINVAL when being + // asked to transfer bytes more than the actual file size. For instance, + // the source file is wrapped in an io.LimitedReader with larger size + // than the actual file size. + // + // To handle these cases we ignore EINVAL if any call to sendfile was + // able to send data. + if err == syscall.EINVAL && (n > 0 || written > 0) { + err = nil + } default: start := *offset n, err = syscall.Sendfile(dst, src, offset, size)