Commit 1bf5796c authored by Ben Burkert's avatar Ben Burkert Committed by Tobias Klauser

internal/poll: fall back on unsupported splice from unix socket

Gracefully fallback to a userspace copy when the kernel does not support
splice(2) on a unix domain socket. EINVAL is returned by the splice
syscall if it does not support unix domain sockets. Keeping the handled
return value as false when the first splice call fails with EINVAL will
cause the caller to fall back to a userspace copy.

Fixes #27513

Change-Id: I4b10c1900ba3c096cb32edb7c8a6044f468efb52
Reviewed-on: https://go-review.googlesource.com/133575
Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarTobias Klauser <tobias.klauser@gmail.com>
parent 58c6afe0
...@@ -32,8 +32,6 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, ...@@ -32,8 +32,6 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string,
return 0, false, sc, err return 0, false, sc, err
} }
defer destroyTempPipe(prfd, pwfd) defer destroyTempPipe(prfd, pwfd)
// From here on, the operation should be considered handled,
// even if Splice doesn't transfer any data.
var inPipe, n int var inPipe, n int
for err == nil && remain > 0 { for err == nil && remain > 0 {
max := maxSpliceSize max := maxSpliceSize
...@@ -41,6 +39,12 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, ...@@ -41,6 +39,12 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string,
max = int(remain) max = int(remain)
} }
inPipe, err = spliceDrain(pwfd, src, max) inPipe, err = spliceDrain(pwfd, src, max)
// the operation is considered handled if splice returns no error, or
// an error other than EINVAL. An EINVAL means the kernel does not
// support splice for the socket type of dst and/or src. The failed
// syscall does not consume any data so it is safe to fall back to a
// generic copy.
handled = handled || (err != syscall.EINVAL)
// spliceDrain should never return EAGAIN, so if err != nil, // spliceDrain should never return EAGAIN, so if err != nil,
// Splice cannot continue. If inPipe == 0 && err == nil, // Splice cannot continue. If inPipe == 0 && err == nil,
// src is at EOF, and the transfer is complete. // src is at EOF, and the transfer is complete.
...@@ -54,7 +58,7 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, ...@@ -54,7 +58,7 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string,
} }
} }
if err != nil { if err != nil {
return written, true, "splice", err return written, handled, "splice", err
} }
return written, true, "", nil return written, true, "", nil
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment