]> Cypherpunks repositories - gostls13.git/commitdiff
internal/poll: confine runtime OS-checks to sendFileChunk
authorAndy Pan <i@andypan.me>
Tue, 29 Oct 2024 04:27:30 +0000 (12:27 +0800)
committerGopher Robot <gobot@golang.org>
Thu, 31 Oct 2024 23:30:46 +0000 (23:30 +0000)
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 <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>

src/internal/poll/sendfile_unix.go

index dc81c4ad897a2bcc904a62c10df90b23e2e4c48a..1426a1229b453cfe1a333f64e6b68df0379873ef 100644 (file)
@@ -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)