summaryrefslogtreecommitdiffhomepage
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/sentry/fs/gofer/BUILD2
-rw-r--r--pkg/sentry/fs/gofer/socket.go32
-rw-r--r--pkg/sentry/fs/host/BUILD1
-rw-r--r--pkg/sentry/fs/host/socket.go44
-rw-r--r--pkg/sentry/fs/host/socket_test.go8
-rw-r--r--pkg/sentry/socket/netlink/socket.go22
-rw-r--r--pkg/sentry/socket/unix/io.go5
-rw-r--r--pkg/sentry/socket/unix/transport/BUILD1
-rw-r--r--pkg/sentry/socket/unix/transport/connectioned.go43
-rw-r--r--pkg/sentry/socket/unix/transport/connectionless.go31
-rw-r--r--pkg/sentry/socket/unix/transport/queue.go26
-rw-r--r--pkg/sentry/socket/unix/transport/unix.go51
-rw-r--r--pkg/sentry/socket/unix/unix.go32
13 files changed, 146 insertions, 152 deletions
diff --git a/pkg/sentry/fs/gofer/BUILD b/pkg/sentry/fs/gofer/BUILD
index c9e531e40..35ffadd13 100644
--- a/pkg/sentry/fs/gofer/BUILD
+++ b/pkg/sentry/fs/gofer/BUILD
@@ -43,8 +43,8 @@ go_library(
"//pkg/sentry/safemem",
"//pkg/sentry/socket/unix/transport",
"//pkg/sentry/usermem",
+ "//pkg/syserr",
"//pkg/syserror",
- "//pkg/tcpip",
"//pkg/unet",
"//pkg/waiter",
],
diff --git a/pkg/sentry/fs/gofer/socket.go b/pkg/sentry/fs/gofer/socket.go
index 76ce58810..ce6d3d5c3 100644
--- a/pkg/sentry/fs/gofer/socket.go
+++ b/pkg/sentry/fs/gofer/socket.go
@@ -20,7 +20,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs/host"
"gvisor.googlesource.com/gvisor/pkg/sentry/socket/unix/transport"
- "gvisor.googlesource.com/gvisor/pkg/tcpip"
+ "gvisor.googlesource.com/gvisor/pkg/syserr"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
@@ -74,10 +74,10 @@ func unixSockToP9(t transport.SockType) (p9.ConnectFlags, bool) {
}
// BidirectionalConnect implements ConnectableEndpoint.BidirectionalConnect.
-func (e *endpoint) BidirectionalConnect(ce transport.ConnectingEndpoint, returnConnect func(transport.Receiver, transport.ConnectedEndpoint)) *tcpip.Error {
+func (e *endpoint) BidirectionalConnect(ce transport.ConnectingEndpoint, returnConnect func(transport.Receiver, transport.ConnectedEndpoint)) *syserr.Error {
cf, ok := unixSockToP9(ce.Type())
if !ok {
- return tcpip.ErrConnectionRefused
+ return syserr.ErrConnectionRefused
}
// No lock ordering required as only the ConnectingEndpoint has a mutex.
@@ -86,24 +86,24 @@ func (e *endpoint) BidirectionalConnect(ce transport.ConnectingEndpoint, returnC
// Check connecting state.
if ce.Connected() {
ce.Unlock()
- return tcpip.ErrAlreadyConnected
+ return syserr.ErrAlreadyConnected
}
if ce.Listening() {
ce.Unlock()
- return tcpip.ErrInvalidEndpointState
+ return syserr.ErrInvalidEndpointState
}
hostFile, err := e.file.Connect(cf)
if err != nil {
ce.Unlock()
- return tcpip.ErrConnectionRefused
+ return syserr.ErrConnectionRefused
}
- c, terr := host.NewConnectedEndpoint(hostFile, ce.WaiterQueue(), e.path)
- if terr != nil {
+ c, serr := host.NewConnectedEndpoint(hostFile, ce.WaiterQueue(), e.path)
+ if serr != nil {
ce.Unlock()
- log.Warningf("Gofer returned invalid host socket for BidirectionalConnect; file %+v flags %+v: %v", e.file, cf, terr)
- return terr
+ log.Warningf("Gofer returned invalid host socket for BidirectionalConnect; file %+v flags %+v: %v", e.file, cf, serr)
+ return serr
}
returnConnect(c, c)
@@ -115,16 +115,16 @@ func (e *endpoint) BidirectionalConnect(ce transport.ConnectingEndpoint, returnC
// UnidirectionalConnect implements
// transport.BoundEndpoint.UnidirectionalConnect.
-func (e *endpoint) UnidirectionalConnect() (transport.ConnectedEndpoint, *tcpip.Error) {
+func (e *endpoint) UnidirectionalConnect() (transport.ConnectedEndpoint, *syserr.Error) {
hostFile, err := e.file.Connect(p9.DgramSocket)
if err != nil {
- return nil, tcpip.ErrConnectionRefused
+ return nil, syserr.ErrConnectionRefused
}
- c, terr := host.NewConnectedEndpoint(hostFile, &waiter.Queue{}, e.path)
- if terr != nil {
- log.Warningf("Gofer returned invalid host socket for UnidirectionalConnect; file %+v: %v", e.file, terr)
- return nil, terr
+ c, serr := host.NewConnectedEndpoint(hostFile, &waiter.Queue{}, e.path)
+ if serr != nil {
+ log.Warningf("Gofer returned invalid host socket for UnidirectionalConnect; file %+v: %v", e.file, serr)
+ return nil, serr
}
c.Init()
diff --git a/pkg/sentry/fs/host/BUILD b/pkg/sentry/fs/host/BUILD
index d1eb9bd64..89d7b2fe7 100644
--- a/pkg/sentry/fs/host/BUILD
+++ b/pkg/sentry/fs/host/BUILD
@@ -49,7 +49,6 @@ go_library(
"//pkg/syserr",
"//pkg/syserror",
"//pkg/tcpip",
- "//pkg/tcpip/link/rawfile",
"//pkg/unet",
"//pkg/waiter",
"//pkg/waiter/fdnotifier",
diff --git a/pkg/sentry/fs/host/socket.go b/pkg/sentry/fs/host/socket.go
index af53bf533..506be3056 100644
--- a/pkg/sentry/fs/host/socket.go
+++ b/pkg/sentry/fs/host/socket.go
@@ -30,7 +30,6 @@ import (
"gvisor.googlesource.com/gvisor/pkg/syserr"
"gvisor.googlesource.com/gvisor/pkg/syserror"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
- "gvisor.googlesource.com/gvisor/pkg/tcpip/link/rawfile"
"gvisor.googlesource.com/gvisor/pkg/unet"
"gvisor.googlesource.com/gvisor/pkg/waiter"
"gvisor.googlesource.com/gvisor/pkg/waiter/fdnotifier"
@@ -83,33 +82,33 @@ type ConnectedEndpoint struct {
// init performs initialization required for creating new ConnectedEndpoints and
// for restoring them.
-func (c *ConnectedEndpoint) init() *tcpip.Error {
+func (c *ConnectedEndpoint) init() *syserr.Error {
family, err := syscall.GetsockoptInt(c.file.FD(), syscall.SOL_SOCKET, syscall.SO_DOMAIN)
if err != nil {
- return translateError(err)
+ return syserr.FromError(err)
}
if family != syscall.AF_UNIX {
// We only allow Unix sockets.
- return tcpip.ErrInvalidEndpointState
+ return syserr.ErrInvalidEndpointState
}
stype, err := syscall.GetsockoptInt(c.file.FD(), syscall.SOL_SOCKET, syscall.SO_TYPE)
if err != nil {
- return translateError(err)
+ return syserr.FromError(err)
}
if err := syscall.SetNonblock(c.file.FD(), true); err != nil {
- return translateError(err)
+ return syserr.FromError(err)
}
sndbuf, err := syscall.GetsockoptInt(c.file.FD(), syscall.SOL_SOCKET, syscall.SO_SNDBUF)
if err != nil {
- return translateError(err)
+ return syserr.FromError(err)
}
if sndbuf > maxSendBufferSize {
log.Warningf("Socket send buffer too large: %d", sndbuf)
- return tcpip.ErrInvalidEndpointState
+ return syserr.ErrInvalidEndpointState
}
c.stype = transport.SockType(stype)
@@ -124,7 +123,7 @@ func (c *ConnectedEndpoint) init() *tcpip.Error {
// The caller is responsible for calling Init(). Additionaly, Release needs to
// be called twice because ConnectedEndpoint is both a transport.Receiver and
// transport.ConnectedEndpoint.
-func NewConnectedEndpoint(file *fd.FD, queue *waiter.Queue, path string) (*ConnectedEndpoint, *tcpip.Error) {
+func NewConnectedEndpoint(file *fd.FD, queue *waiter.Queue, path string) (*ConnectedEndpoint, *syserr.Error) {
e := ConnectedEndpoint{
path: path,
queue: queue,
@@ -160,7 +159,7 @@ func NewSocketWithDirent(ctx context.Context, d *fs.Dirent, f *fd.FD, flags fs.F
e, err := NewConnectedEndpoint(f2, &q, "" /* path */)
if err != nil {
f2.Release()
- return nil, syserr.TranslateNetstackError(err).ToError()
+ return nil, err.ToError()
}
// Take ownship of the FD.
@@ -194,7 +193,7 @@ func newSocket(ctx context.Context, orgfd int, saveable bool) (*fs.File, error)
} else {
f.Release()
}
- return nil, syserr.TranslateNetstackError(err).ToError()
+ return nil, err.ToError()
}
e.srfd = srfd
@@ -206,15 +205,15 @@ func newSocket(ctx context.Context, orgfd int, saveable bool) (*fs.File, error)
}
// Send implements transport.ConnectedEndpoint.Send.
-func (c *ConnectedEndpoint) Send(data [][]byte, controlMessages transport.ControlMessages, from tcpip.FullAddress) (uintptr, bool, *tcpip.Error) {
+func (c *ConnectedEndpoint) Send(data [][]byte, controlMessages transport.ControlMessages, from tcpip.FullAddress) (uintptr, bool, *syserr.Error) {
c.mu.RLock()
defer c.mu.RUnlock()
if c.writeClosed {
- return 0, false, tcpip.ErrClosedForSend
+ return 0, false, syserr.ErrClosedForSend
}
if !controlMessages.Empty() {
- return 0, false, tcpip.ErrInvalidEndpointState
+ return 0, false, syserr.ErrInvalidEndpointState
}
// Since stream sockets don't preserve message boundaries, we can write
@@ -236,7 +235,7 @@ func (c *ConnectedEndpoint) Send(data [][]byte, controlMessages transport.Contro
// There is no need for the callee to call SendNotify because fdWriteVec
// uses the host's sendmsg(2) and the host kernel's queue.
- return n, false, translateError(err)
+ return n, false, syserr.FromError(err)
}
// SendNotify implements transport.ConnectedEndpoint.SendNotify.
@@ -283,11 +282,11 @@ func (c *ConnectedEndpoint) EventUpdate() {
}
// Recv implements transport.Receiver.Recv.
-func (c *ConnectedEndpoint) Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (uintptr, uintptr, transport.ControlMessages, tcpip.FullAddress, bool, *tcpip.Error) {
+func (c *ConnectedEndpoint) Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (uintptr, uintptr, transport.ControlMessages, tcpip.FullAddress, bool, *syserr.Error) {
c.mu.RLock()
defer c.mu.RUnlock()
if c.readClosed {
- return 0, 0, transport.ControlMessages{}, tcpip.FullAddress{}, false, tcpip.ErrClosedForReceive
+ return 0, 0, transport.ControlMessages{}, tcpip.FullAddress{}, false, syserr.ErrClosedForReceive
}
var cm unet.ControlMessage
@@ -305,7 +304,7 @@ func (c *ConnectedEndpoint) Recv(data [][]byte, creds bool, numRights uintptr, p
err = nil
}
if err != nil {
- return 0, 0, transport.ControlMessages{}, tcpip.FullAddress{}, false, translateError(err)
+ return 0, 0, transport.ControlMessages{}, tcpip.FullAddress{}, false, syserr.FromError(err)
}
// There is no need for the callee to call RecvNotify because fdReadVec uses
@@ -323,7 +322,7 @@ func (c *ConnectedEndpoint) Recv(data [][]byte, creds bool, numRights uintptr, p
fds, err := cm.ExtractFDs()
if err != nil {
- return 0, 0, transport.ControlMessages{}, tcpip.FullAddress{}, false, translateError(err)
+ return 0, 0, transport.ControlMessages{}, tcpip.FullAddress{}, false, syserr.FromError(err)
}
if len(fds) == 0 {
@@ -389,10 +388,3 @@ func (c *ConnectedEndpoint) RecvMaxQueueSize() int64 {
func (c *ConnectedEndpoint) Release() {
c.ref.DecRefWithDestructor(c.close)
}
-
-func translateError(err error) *tcpip.Error {
- if err == nil {
- return nil
- }
- return rawfile.TranslateErrno(err.(syscall.Errno))
-}
diff --git a/pkg/sentry/fs/host/socket_test.go b/pkg/sentry/fs/host/socket_test.go
index e9a88b124..17bf397ef 100644
--- a/pkg/sentry/fs/host/socket_test.go
+++ b/pkg/sentry/fs/host/socket_test.go
@@ -199,15 +199,15 @@ func TestListen(t *testing.T) {
func TestSend(t *testing.T) {
e := ConnectedEndpoint{writeClosed: true}
- if _, _, err := e.Send(nil, transport.ControlMessages{}, tcpip.FullAddress{}); err != tcpip.ErrClosedForSend {
- t.Errorf("Got %#v.Send() = %v, want = %v", e, err, tcpip.ErrClosedForSend)
+ if _, _, err := e.Send(nil, transport.ControlMessages{}, tcpip.FullAddress{}); err != syserr.ErrClosedForSend {
+ t.Errorf("Got %#v.Send() = %v, want = %v", e, err, syserr.ErrClosedForSend)
}
}
func TestRecv(t *testing.T) {
e := ConnectedEndpoint{readClosed: true}
- if _, _, _, _, _, err := e.Recv(nil, false, 0, false); err != tcpip.ErrClosedForReceive {
- t.Errorf("Got %#v.Recv() = %v, want = %v", e, err, tcpip.ErrClosedForReceive)
+ if _, _, _, _, _, err := e.Recv(nil, false, 0, false); err != syserr.ErrClosedForReceive {
+ t.Errorf("Got %#v.Recv() = %v, want = %v", e, err, syserr.ErrClosedForReceive)
}
}
diff --git a/pkg/sentry/socket/netlink/socket.go b/pkg/sentry/socket/netlink/socket.go
index 4d4130a4c..f901cfa0b 100644
--- a/pkg/sentry/socket/netlink/socket.go
+++ b/pkg/sentry/socket/netlink/socket.go
@@ -109,16 +109,16 @@ func NewSocket(t *kernel.Task, protocol Protocol) (*Socket, *syserr.Error) {
// Bind the endpoint for good measure so we can connect to it. The
// bound address will never be exposed.
- if terr := ep.Bind(tcpip.FullAddress{Addr: "dummy"}, nil); terr != nil {
+ if err := ep.Bind(tcpip.FullAddress{Addr: "dummy"}, nil); err != nil {
ep.Close()
- return nil, syserr.TranslateNetstackError(terr)
+ return nil, err
}
// Create a connection from which the kernel can write messages.
- connection, terr := ep.(transport.BoundEndpoint).UnidirectionalConnect()
- if terr != nil {
+ connection, err := ep.(transport.BoundEndpoint).UnidirectionalConnect()
+ if err != nil {
ep.Close()
- return nil, syserr.TranslateNetstackError(terr)
+ return nil, err
}
return &Socket{
@@ -424,11 +424,11 @@ func (s *Socket) sendResponse(ctx context.Context, ms *MessageSet) *syserr.Error
if len(bufs) > 0 {
// RecvMsg never receives the address, so we don't need to send
// one.
- _, notify, terr := s.connection.Send(bufs, transport.ControlMessages{}, tcpip.FullAddress{})
+ _, notify, err := s.connection.Send(bufs, transport.ControlMessages{}, tcpip.FullAddress{})
// If the buffer is full, we simply drop messages, just like
// Linux.
- if terr != nil && terr != tcpip.ErrWouldBlock {
- return syserr.TranslateNetstackError(terr)
+ if err != nil && err != syserr.ErrWouldBlock {
+ return err
}
if notify {
s.connection.SendNotify()
@@ -448,9 +448,9 @@ func (s *Socket) sendResponse(ctx context.Context, ms *MessageSet) *syserr.Error
PortID: uint32(ms.PortID),
})
- _, notify, terr := s.connection.Send([][]byte{m.Finalize()}, transport.ControlMessages{}, tcpip.FullAddress{})
- if terr != nil && terr != tcpip.ErrWouldBlock {
- return syserr.TranslateNetstackError(terr)
+ _, notify, err := s.connection.Send([][]byte{m.Finalize()}, transport.ControlMessages{}, tcpip.FullAddress{})
+ if err != nil && err != syserr.ErrWouldBlock {
+ return err
}
if notify {
s.connection.SendNotify()
diff --git a/pkg/sentry/socket/unix/io.go b/pkg/sentry/socket/unix/io.go
index 7d6434696..7d80e4393 100644
--- a/pkg/sentry/socket/unix/io.go
+++ b/pkg/sentry/socket/unix/io.go
@@ -17,7 +17,6 @@ package unix
import (
"gvisor.googlesource.com/gvisor/pkg/sentry/safemem"
"gvisor.googlesource.com/gvisor/pkg/sentry/socket/unix/transport"
- "gvisor.googlesource.com/gvisor/pkg/syserr"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
)
@@ -40,7 +39,7 @@ func (w *EndpointWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error)
return safemem.FromVecWriterFunc{func(bufs [][]byte) (int64, error) {
n, err := w.Endpoint.SendMsg(bufs, w.Control, w.To)
if err != nil {
- return int64(n), syserr.TranslateNetstackError(err).ToError()
+ return int64(n), err.ToError()
}
return int64(n), nil
}}.WriteFromBlocks(srcs)
@@ -82,7 +81,7 @@ func (r *EndpointReader) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) {
r.Control = c
r.MsgSize = ms
if err != nil {
- return int64(n), syserr.TranslateNetstackError(err).ToError()
+ return int64(n), err.ToError()
}
return int64(n), nil
}}.ReadToBlocks(dsts)
diff --git a/pkg/sentry/socket/unix/transport/BUILD b/pkg/sentry/socket/unix/transport/BUILD
index 5bc01e3c8..5a90837bc 100644
--- a/pkg/sentry/socket/unix/transport/BUILD
+++ b/pkg/sentry/socket/unix/transport/BUILD
@@ -30,6 +30,7 @@ go_library(
deps = [
"//pkg/ilist",
"//pkg/refs",
+ "//pkg/syserr",
"//pkg/tcpip",
"//pkg/tcpip/buffer",
"//pkg/waiter",
diff --git a/pkg/sentry/socket/unix/transport/connectioned.go b/pkg/sentry/socket/unix/transport/connectioned.go
index 83b50459f..7cfbbfe8a 100644
--- a/pkg/sentry/socket/unix/transport/connectioned.go
+++ b/pkg/sentry/socket/unix/transport/connectioned.go
@@ -17,6 +17,7 @@ package transport
import (
"sync"
+ "gvisor.googlesource.com/gvisor/pkg/syserr"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
@@ -236,14 +237,14 @@ func (e *connectionedEndpoint) Close() {
}
// BidirectionalConnect implements BoundEndpoint.BidirectionalConnect.
-func (e *connectionedEndpoint) BidirectionalConnect(ce ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *tcpip.Error {
+func (e *connectionedEndpoint) BidirectionalConnect(ce ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *syserr.Error {
if ce.Type() != e.stype {
- return tcpip.ErrConnectionRefused
+ return syserr.ErrConnectionRefused
}
// Check if ce is e to avoid a deadlock.
if ce, ok := ce.(*connectionedEndpoint); ok && ce == e {
- return tcpip.ErrInvalidEndpointState
+ return syserr.ErrInvalidEndpointState
}
// Do a dance to safely acquire locks on both endpoints.
@@ -259,19 +260,19 @@ func (e *connectionedEndpoint) BidirectionalConnect(ce ConnectingEndpoint, retur
if ce.Connected() {
e.Unlock()
ce.Unlock()
- return tcpip.ErrAlreadyConnected
+ return syserr.ErrAlreadyConnected
}
if ce.Listening() {
e.Unlock()
ce.Unlock()
- return tcpip.ErrInvalidEndpointState
+ return syserr.ErrInvalidEndpointState
}
// Check bound state.
if !e.Listening() {
e.Unlock()
ce.Unlock()
- return tcpip.ErrConnectionRefused
+ return syserr.ErrConnectionRefused
}
// Create a newly bound connectionedEndpoint.
@@ -327,18 +328,18 @@ func (e *connectionedEndpoint) BidirectionalConnect(ce ConnectingEndpoint, retur
ne.Close()
e.Unlock()
ce.Unlock()
- return tcpip.ErrConnectionRefused
+ return syserr.ErrConnectionRefused
}
}
// UnidirectionalConnect implements BoundEndpoint.UnidirectionalConnect.
-func (e *connectionedEndpoint) UnidirectionalConnect() (ConnectedEndpoint, *tcpip.Error) {
- return nil, tcpip.ErrConnectionRefused
+func (e *connectionedEndpoint) UnidirectionalConnect() (ConnectedEndpoint, *syserr.Error) {
+ return nil, syserr.ErrConnectionRefused
}
// Connect attempts to directly connect to another Endpoint.
// Implements Endpoint.Connect.
-func (e *connectionedEndpoint) Connect(server BoundEndpoint) *tcpip.Error {
+func (e *connectionedEndpoint) Connect(server BoundEndpoint) *syserr.Error {
returnConnect := func(r Receiver, ce ConnectedEndpoint) {
e.receiver = r
e.connected = ce
@@ -348,14 +349,14 @@ func (e *connectionedEndpoint) Connect(server BoundEndpoint) *tcpip.Error {
}
// Listen starts listening on the connection.
-func (e *connectionedEndpoint) Listen(backlog int) *tcpip.Error {
+func (e *connectionedEndpoint) Listen(backlog int) *syserr.Error {
e.Lock()
defer e.Unlock()
if e.Listening() {
// Adjust the size of the channel iff we can fix existing
// pending connections into the new one.
if len(e.acceptedChan) > backlog {
- return tcpip.ErrInvalidEndpointState
+ return syserr.ErrInvalidEndpointState
}
origChan := e.acceptedChan
e.acceptedChan = make(chan *connectionedEndpoint, backlog)
@@ -366,7 +367,7 @@ func (e *connectionedEndpoint) Listen(backlog int) *tcpip.Error {
return nil
}
if !e.isBound() {
- return tcpip.ErrInvalidEndpointState
+ return syserr.ErrInvalidEndpointState
}
// Normal case.
@@ -375,12 +376,12 @@ func (e *connectionedEndpoint) Listen(backlog int) *tcpip.Error {
}
// Accept accepts a new connection.
-func (e *connectionedEndpoint) Accept() (Endpoint, *tcpip.Error) {
+func (e *connectionedEndpoint) Accept() (Endpoint, *syserr.Error) {
e.Lock()
defer e.Unlock()
if !e.Listening() {
- return nil, tcpip.ErrInvalidEndpointState
+ return nil, syserr.ErrInvalidEndpointState
}
select {
@@ -389,7 +390,7 @@ func (e *connectionedEndpoint) Accept() (Endpoint, *tcpip.Error) {
default:
// Nothing left.
- return nil, tcpip.ErrWouldBlock
+ return nil, syserr.ErrWouldBlock
}
}
@@ -401,15 +402,15 @@ func (e *connectionedEndpoint) Accept() (Endpoint, *tcpip.Error) {
//
// Bind will fail only if the socket is connected, bound or the passed address
// is invalid (the empty string).
-func (e *connectionedEndpoint) Bind(addr tcpip.FullAddress, commit func() *tcpip.Error) *tcpip.Error {
+func (e *connectionedEndpoint) Bind(addr tcpip.FullAddress, commit func() *syserr.Error) *syserr.Error {
e.Lock()
defer e.Unlock()
if e.isBound() || e.Listening() {
- return tcpip.ErrAlreadyBound
+ return syserr.ErrAlreadyBound
}
if addr.Addr == "" {
// The empty string is not permitted.
- return tcpip.ErrBadLocalAddress
+ return syserr.ErrBadLocalAddress
}
if commit != nil {
if err := commit(); err != nil {
@@ -424,11 +425,11 @@ func (e *connectionedEndpoint) Bind(addr tcpip.FullAddress, commit func() *tcpip
// SendMsg writes data and a control message to the endpoint's peer.
// This method does not block if the data cannot be written.
-func (e *connectionedEndpoint) SendMsg(data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *tcpip.Error) {
+func (e *connectionedEndpoint) SendMsg(data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *syserr.Error) {
// Stream sockets do not support specifying the endpoint. Seqpacket
// sockets ignore the passed endpoint.
if e.stype == SockStream && to != nil {
- return 0, tcpip.ErrNotSupported
+ return 0, syserr.ErrNotSupported
}
return e.baseEndpoint.SendMsg(data, c, to)
}
diff --git a/pkg/sentry/socket/unix/transport/connectionless.go b/pkg/sentry/socket/unix/transport/connectionless.go
index 376e4abb2..f432a9717 100644
--- a/pkg/sentry/socket/unix/transport/connectionless.go
+++ b/pkg/sentry/socket/unix/transport/connectionless.go
@@ -15,6 +15,7 @@
package transport
import (
+ "gvisor.googlesource.com/gvisor/pkg/syserr"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
@@ -70,21 +71,21 @@ func (e *connectionlessEndpoint) Close() {
}
// BidirectionalConnect implements BoundEndpoint.BidirectionalConnect.
-func (e *connectionlessEndpoint) BidirectionalConnect(ce ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *tcpip.Error {
- return tcpip.ErrConnectionRefused
+func (e *connectionlessEndpoint) BidirectionalConnect(ce ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *syserr.Error {
+ return syserr.ErrConnectionRefused
}
// UnidirectionalConnect implements BoundEndpoint.UnidirectionalConnect.
-func (e *connectionlessEndpoint) UnidirectionalConnect() (ConnectedEndpoint, *tcpip.Error) {
+func (e *connectionlessEndpoint) UnidirectionalConnect() (ConnectedEndpoint, *syserr.Error) {
e.Lock()
r := e.receiver
e.Unlock()
if r == nil {
- return nil, tcpip.ErrConnectionRefused
+ return nil, syserr.ErrConnectionRefused
}
q := r.(*queueReceiver).readQueue
if !q.TryIncRef() {
- return nil, tcpip.ErrConnectionRefused
+ return nil, syserr.ErrConnectionRefused
}
return &connectedEndpoint{
endpoint: e,
@@ -94,14 +95,14 @@ func (e *connectionlessEndpoint) UnidirectionalConnect() (ConnectedEndpoint, *tc
// SendMsg writes data and a control message to the specified endpoint.
// This method does not block if the data cannot be written.
-func (e *connectionlessEndpoint) SendMsg(data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *tcpip.Error) {
+func (e *connectionlessEndpoint) SendMsg(data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *syserr.Error) {
if to == nil {
return e.baseEndpoint.SendMsg(data, c, nil)
}
connected, err := to.UnidirectionalConnect()
if err != nil {
- return 0, tcpip.ErrInvalidEndpointState
+ return 0, syserr.ErrInvalidEndpointState
}
defer connected.Release()
@@ -122,7 +123,7 @@ func (e *connectionlessEndpoint) Type() SockType {
}
// Connect attempts to connect directly to server.
-func (e *connectionlessEndpoint) Connect(server BoundEndpoint) *tcpip.Error {
+func (e *connectionlessEndpoint) Connect(server BoundEndpoint) *syserr.Error {
connected, err := server.UnidirectionalConnect()
if err != nil {
return err
@@ -136,13 +137,13 @@ func (e *connectionlessEndpoint) Connect(server BoundEndpoint) *tcpip.Error {
}
// Listen starts listening on the connection.
-func (e *connectionlessEndpoint) Listen(int) *tcpip.Error {
- return tcpip.ErrNotSupported
+func (e *connectionlessEndpoint) Listen(int) *syserr.Error {
+ return syserr.ErrNotSupported
}
// Accept accepts a new connection.
-func (e *connectionlessEndpoint) Accept() (Endpoint, *tcpip.Error) {
- return nil, tcpip.ErrNotSupported
+func (e *connectionlessEndpoint) Accept() (Endpoint, *syserr.Error) {
+ return nil, syserr.ErrNotSupported
}
// Bind binds the connection.
@@ -153,15 +154,15 @@ func (e *connectionlessEndpoint) Accept() (Endpoint, *tcpip.Error) {
//
// Bind will fail only if the socket is connected, bound or the passed address
// is invalid (the empty string).
-func (e *connectionlessEndpoint) Bind(addr tcpip.FullAddress, commit func() *tcpip.Error) *tcpip.Error {
+func (e *connectionlessEndpoint) Bind(addr tcpip.FullAddress, commit func() *syserr.Error) *syserr.Error {
e.Lock()
defer e.Unlock()
if e.isBound() {
- return tcpip.ErrAlreadyBound
+ return syserr.ErrAlreadyBound
}
if addr.Addr == "" {
// The empty string is not permitted.
- return tcpip.ErrBadLocalAddress
+ return syserr.ErrBadLocalAddress
}
if commit != nil {
if err := commit(); err != nil {
diff --git a/pkg/sentry/socket/unix/transport/queue.go b/pkg/sentry/socket/unix/transport/queue.go
index 72aa409ab..05d1bdeef 100644
--- a/pkg/sentry/socket/unix/transport/queue.go
+++ b/pkg/sentry/socket/unix/transport/queue.go
@@ -18,7 +18,7 @@ import (
"sync"
"gvisor.googlesource.com/gvisor/pkg/refs"
- "gvisor.googlesource.com/gvisor/pkg/tcpip"
+ "gvisor.googlesource.com/gvisor/pkg/syserr"
"gvisor.googlesource.com/gvisor/pkg/waiter"
)
@@ -110,12 +110,12 @@ func (q *queue) IsWritable() bool {
//
// If notify is true, ReaderQueue.Notify must be called:
// q.ReaderQueue.Notify(waiter.EventIn)
-func (q *queue) Enqueue(e *message, truncate bool) (l int64, notify bool, err *tcpip.Error) {
+func (q *queue) Enqueue(e *message, truncate bool) (l int64, notify bool, err *syserr.Error) {
q.mu.Lock()
if q.closed {
q.mu.Unlock()
- return 0, false, tcpip.ErrClosedForSend
+ return 0, false, syserr.ErrClosedForSend
}
free := q.limit - q.used
@@ -126,24 +126,24 @@ func (q *queue) Enqueue(e *message, truncate bool) (l int64, notify bool, err *t
if free == 0 {
// Message can't fit right now.
q.mu.Unlock()
- return 0, false, tcpip.ErrWouldBlock
+ return 0, false, syserr.ErrWouldBlock
}
e.Truncate(free)
l = e.Length()
- err = tcpip.ErrWouldBlock
+ err = syserr.ErrWouldBlock
}
if l > q.limit {
// Message is too big to ever fit.
q.mu.Unlock()
- return 0, false, tcpip.ErrMessageTooLong
+ return 0, false, syserr.ErrMessageTooLong
}
if l > free {
// Message can't fit right now.
q.mu.Unlock()
- return 0, false, tcpip.ErrWouldBlock
+ return 0, false, syserr.ErrWouldBlock
}
notify = q.dataList.Front() == nil
@@ -159,13 +159,13 @@ func (q *queue) Enqueue(e *message, truncate bool) (l int64, notify bool, err *t
//
// If notify is true, WriterQueue.Notify must be called:
// q.WriterQueue.Notify(waiter.EventOut)
-func (q *queue) Dequeue() (e *message, notify bool, err *tcpip.Error) {
+func (q *queue) Dequeue() (e *message, notify bool, err *syserr.Error) {
q.mu.Lock()
if q.dataList.Front() == nil {
- err := tcpip.ErrWouldBlock
+ err := syserr.ErrWouldBlock
if q.closed {
- err = tcpip.ErrClosedForReceive
+ err = syserr.ErrClosedForReceive
}
q.mu.Unlock()
@@ -186,14 +186,14 @@ func (q *queue) Dequeue() (e *message, notify bool, err *tcpip.Error) {
}
// Peek returns the first entry in the data queue, if one exists.
-func (q *queue) Peek() (*message, *tcpip.Error) {
+func (q *queue) Peek() (*message, *syserr.Error) {
q.mu.Lock()
defer q.mu.Unlock()
if q.dataList.Front() == nil {
- err := tcpip.ErrWouldBlock
+ err := syserr.ErrWouldBlock
if q.closed {
- err = tcpip.ErrClosedForReceive
+ err = syserr.ErrClosedForReceive
}
return nil, err
}
diff --git a/pkg/sentry/socket/unix/transport/unix.go b/pkg/sentry/socket/unix/transport/unix.go
index 765cca27a..e98096d7b 100644
--- a/pkg/sentry/socket/unix/transport/unix.go
+++ b/pkg/sentry/socket/unix/transport/unix.go
@@ -19,6 +19,7 @@ import (
"sync"
"sync/atomic"
+ "gvisor.googlesource.com/gvisor/pkg/syserr"
"gvisor.googlesource.com/gvisor/pkg/tcpip"
"gvisor.googlesource.com/gvisor/pkg/tcpip/buffer"
"gvisor.googlesource.com/gvisor/pkg/waiter"
@@ -129,13 +130,13 @@ type Endpoint interface {
//
// msgLen is the length of the read message consumed for datagram Endpoints.
// msgLen is always the same as recvLen for stream Endpoints.
- RecvMsg(data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (recvLen, msgLen uintptr, cm ControlMessages, err *tcpip.Error)
+ RecvMsg(data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (recvLen, msgLen uintptr, cm ControlMessages, err *syserr.Error)
// SendMsg writes data and a control message to the endpoint's peer.
// This method does not block if the data cannot be written.
//
// SendMsg does not take ownership of any of its arguments on error.
- SendMsg([][]byte, ControlMessages, BoundEndpoint) (uintptr, *tcpip.Error)
+ SendMsg([][]byte, ControlMessages, BoundEndpoint) (uintptr, *syserr.Error)
// Connect connects this endpoint directly to another.
//
@@ -143,22 +144,22 @@ type Endpoint interface {
// endpoint passed in as a parameter.
//
// The error codes are the same as Connect.
- Connect(server BoundEndpoint) *tcpip.Error
+ Connect(server BoundEndpoint) *syserr.Error
// Shutdown closes the read and/or write end of the endpoint connection
// to its peer.
- Shutdown(flags tcpip.ShutdownFlags) *tcpip.Error
+ Shutdown(flags tcpip.ShutdownFlags) *syserr.Error
// Listen puts the endpoint in "listen" mode, which allows it to accept
// new connections.
- Listen(backlog int) *tcpip.Error
+ Listen(backlog int) *syserr.Error
// Accept returns a new endpoint if a peer has established a connection
// to an endpoint previously set to listen mode. This method does not
// block if no new connections are available.
//
// The returned Queue is the wait queue for the newly created endpoint.
- Accept() (Endpoint, *tcpip.Error)
+ Accept() (Endpoint, *syserr.Error)
// Bind binds the endpoint to a specific local address and port.
// Specifying a NIC is optional.
@@ -166,7 +167,7 @@ type Endpoint interface {
// An optional commit function will be executed atomically with respect
// to binding the endpoint. If this returns an error, the bind will not
// occur and the error will be propagated back to the caller.
- Bind(address tcpip.FullAddress, commit func() *tcpip.Error) *tcpip.Error
+ Bind(address tcpip.FullAddress, commit func() *syserr.Error) *syserr.Error
// Type return the socket type, typically either SockStream, SockDgram
// or SockSeqpacket.
@@ -218,9 +219,9 @@ type BoundEndpoint interface {
// be unconnected and not listening and the BoundEndpoint whose
// BidirectionalConnect method is being called must be listening.
//
- // This method will return tcpip.ErrConnectionRefused on endpoints with a
+ // This method will return syserr.ErrConnectionRefused on endpoints with a
// type that isn't SockStream or SockSeqpacket.
- BidirectionalConnect(ep ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *tcpip.Error
+ BidirectionalConnect(ep ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *syserr.Error
// UnidirectionalConnect establishes a write-only connection to a unix
// endpoint.
@@ -228,9 +229,9 @@ type BoundEndpoint interface {
// An endpoint which calls UnidirectionalConnect and supports it itself must
// not hold its own lock when calling UnidirectionalConnect.
//
- // This method will return tcpip.ErrConnectionRefused on a non-SockDgram
+ // This method will return syserr.ErrConnectionRefused on a non-SockDgram
// endpoint.
- UnidirectionalConnect() (ConnectedEndpoint, *tcpip.Error)
+ UnidirectionalConnect() (ConnectedEndpoint, *syserr.Error)
// Release releases any resources held by the BoundEndpoint. It must be
// called before dropping all references to a BoundEndpoint returned by a
@@ -287,7 +288,7 @@ type Receiver interface {
// See Endpoint.RecvMsg for documentation on shared arguments.
//
// notify indicates if RecvNotify should be called.
- Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (recvLen, msgLen uintptr, cm ControlMessages, source tcpip.FullAddress, notify bool, err *tcpip.Error)
+ Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (recvLen, msgLen uintptr, cm ControlMessages, source tcpip.FullAddress, notify bool, err *syserr.Error)
// RecvNotify notifies the Receiver of a successful Recv. This must not be
// called while holding any endpoint locks.
@@ -327,10 +328,10 @@ type queueReceiver struct {
}
// Recv implements Receiver.Recv.
-func (q *queueReceiver) Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (uintptr, uintptr, ControlMessages, tcpip.FullAddress, bool, *tcpip.Error) {
+func (q *queueReceiver) Recv(data [][]byte, creds bool, numRights uintptr, peek bool) (uintptr, uintptr, ControlMessages, tcpip.FullAddress, bool, *syserr.Error) {
var m *message
var notify bool
- var err *tcpip.Error
+ var err *syserr.Error
if peek {
m, err = q.readQueue.Peek()
} else {
@@ -439,7 +440,7 @@ func (q *streamQueueReceiver) RecvMaxQueueSize() int64 {
}
// Recv implements Receiver.Recv.
-func (q *streamQueueReceiver) Recv(data [][]byte, wantCreds bool, numRights uintptr, peek bool) (uintptr, uintptr, ControlMessages, tcpip.FullAddress, bool, *tcpip.Error) {
+func (q *streamQueueReceiver) Recv(data [][]byte, wantCreds bool, numRights uintptr, peek bool) (uintptr, uintptr, ControlMessages, tcpip.FullAddress, bool, *syserr.Error) {
q.mu.Lock()
defer q.mu.Unlock()
@@ -560,9 +561,9 @@ type ConnectedEndpoint interface {
//
// notify indicates if SendNotify should be called.
//
- // tcpip.ErrWouldBlock can be returned along with a partial write if
+ // syserr.ErrWouldBlock can be returned along with a partial write if
// the caller should block to send the rest of the data.
- Send(data [][]byte, controlMessages ControlMessages, from tcpip.FullAddress) (n uintptr, notify bool, err *tcpip.Error)
+ Send(data [][]byte, controlMessages ControlMessages, from tcpip.FullAddress) (n uintptr, notify bool, err *syserr.Error)
// SendNotify notifies the ConnectedEndpoint of a successful Send. This
// must not be called while holding any endpoint locks.
@@ -630,7 +631,7 @@ func (e *connectedEndpoint) GetLocalAddress() (tcpip.FullAddress, *tcpip.Error)
}
// Send implements ConnectedEndpoint.Send.
-func (e *connectedEndpoint) Send(data [][]byte, controlMessages ControlMessages, from tcpip.FullAddress) (uintptr, bool, *tcpip.Error) {
+func (e *connectedEndpoint) Send(data [][]byte, controlMessages ControlMessages, from tcpip.FullAddress) (uintptr, bool, *syserr.Error) {
var l int64
for _, d := range data {
l += int64(len(d))
@@ -774,12 +775,12 @@ func (e *baseEndpoint) Connected() bool {
}
// RecvMsg reads data and a control message from the endpoint.
-func (e *baseEndpoint) RecvMsg(data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (uintptr, uintptr, ControlMessages, *tcpip.Error) {
+func (e *baseEndpoint) RecvMsg(data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (uintptr, uintptr, ControlMessages, *syserr.Error) {
e.Lock()
if e.receiver == nil {
e.Unlock()
- return 0, 0, ControlMessages{}, tcpip.ErrNotConnected
+ return 0, 0, ControlMessages{}, syserr.ErrNotConnected
}
recvLen, msgLen, cms, a, notify, err := e.receiver.Recv(data, creds, numRights, peek)
@@ -800,15 +801,15 @@ func (e *baseEndpoint) RecvMsg(data [][]byte, creds bool, numRights uintptr, pee
// SendMsg writes data and a control message to the endpoint's peer.
// This method does not block if the data cannot be written.
-func (e *baseEndpoint) SendMsg(data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *tcpip.Error) {
+func (e *baseEndpoint) SendMsg(data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *syserr.Error) {
e.Lock()
if !e.Connected() {
e.Unlock()
- return 0, tcpip.ErrNotConnected
+ return 0, syserr.ErrNotConnected
}
if to != nil {
e.Unlock()
- return 0, tcpip.ErrAlreadyConnected
+ return 0, syserr.ErrAlreadyConnected
}
n, notify, err := e.connected.Send(data, c, tcpip.FullAddress{Addr: tcpip.Address(e.path)})
@@ -901,11 +902,11 @@ func (e *baseEndpoint) GetSockOpt(opt interface{}) *tcpip.Error {
// Shutdown closes the read and/or write end of the endpoint connection to its
// peer.
-func (e *baseEndpoint) Shutdown(flags tcpip.ShutdownFlags) *tcpip.Error {
+func (e *baseEndpoint) Shutdown(flags tcpip.ShutdownFlags) *syserr.Error {
e.Lock()
if !e.Connected() {
e.Unlock()
- return tcpip.ErrNotConnected
+ return syserr.ErrNotConnected
}
if flags&tcpip.ShutdownRead != 0 {
diff --git a/pkg/sentry/socket/unix/unix.go b/pkg/sentry/socket/unix/unix.go
index 3543dd81f..334169372 100644
--- a/pkg/sentry/socket/unix/unix.go
+++ b/pkg/sentry/socket/unix/unix.go
@@ -147,7 +147,7 @@ func (s *SocketOperations) GetSockOpt(t *kernel.Task, level, name, outLen int) (
// Listen implements the linux syscall listen(2) for sockets backed by
// a transport.Endpoint.
func (s *SocketOperations) Listen(t *kernel.Task, backlog int) *syserr.Error {
- return syserr.TranslateNetstackError(s.ep.Listen(backlog))
+ return s.ep.Listen(backlog)
}
// blockingAccept implements a blocking version of accept(2), that is, if no
@@ -161,8 +161,8 @@ func (s *SocketOperations) blockingAccept(t *kernel.Task) (transport.Endpoint, *
// Try to accept the connection; if it fails, then wait until we get a
// notification.
for {
- if ep, err := s.ep.Accept(); err != tcpip.ErrWouldBlock {
- return ep, syserr.TranslateNetstackError(err)
+ if ep, err := s.ep.Accept(); err != syserr.ErrWouldBlock {
+ return ep, err
}
if err := t.Block(ch); err != nil {
@@ -177,8 +177,8 @@ func (s *SocketOperations) Accept(t *kernel.Task, peerRequested bool, flags int,
// Issue the accept request to get the new endpoint.
ep, err := s.ep.Accept()
if err != nil {
- if err != tcpip.ErrWouldBlock || !blocking {
- return 0, nil, 0, syserr.TranslateNetstackError(err)
+ if err != syserr.ErrWouldBlock || !blocking {
+ return 0, nil, 0, err
}
var err *syserr.Error
@@ -232,15 +232,15 @@ func (s *SocketOperations) Bind(t *kernel.Task, sockaddr []byte) *syserr.Error {
return syserr.ErrInvalidArgument
}
- return syserr.TranslateNetstackError(s.ep.Bind(tcpip.FullAddress{Addr: tcpip.Address(p)}, func() *tcpip.Error {
+ return s.ep.Bind(tcpip.FullAddress{Addr: tcpip.Address(p)}, func() *syserr.Error {
// Is it abstract?
if p[0] == 0 {
if t.IsNetworkNamespaced() {
- return tcpip.ErrInvalidEndpointState
+ return syserr.ErrInvalidEndpointState
}
if err := t.AbstractSockets().Bind(p[1:], bep, s); err != nil {
- // tcpip.ErrPortInUse corresponds to EADDRINUSE.
- return tcpip.ErrPortInUse
+ // syserr.ErrPortInUse corresponds to EADDRINUSE.
+ return syserr.ErrPortInUse
}
} else {
// The parent and name.
@@ -269,7 +269,7 @@ func (s *SocketOperations) Bind(t *kernel.Task, sockaddr []byte) *syserr.Error {
d, err = t.MountNamespace().FindInode(t, root, cwd, subPath, fs.DefaultTraversalLimit)
if err != nil {
// No path available.
- return tcpip.ErrNoSuchFile
+ return syserr.ErrNoSuchFile
}
defer d.DecRef()
name = p[lastSlash+1:]
@@ -278,13 +278,13 @@ func (s *SocketOperations) Bind(t *kernel.Task, sockaddr []byte) *syserr.Error {
// Create the socket.
childDir, err := d.Bind(t, t.FSContext().RootDirectory(), name, bep, fs.FilePermissions{User: fs.PermMask{Read: true}})
if err != nil {
- return tcpip.ErrPortInUse
+ return syserr.ErrPortInUse
}
childDir.DecRef()
}
return nil
- }))
+ })
}
// extractEndpoint retrieves the transport.BoundEndpoint associated with a Unix
@@ -341,7 +341,7 @@ func (s *SocketOperations) Connect(t *kernel.Task, sockaddr []byte, blocking boo
defer ep.Release()
// Connect the server endpoint.
- return syserr.TranslateNetstackError(s.ep.Connect(ep))
+ return s.ep.Connect(ep)
}
// Writev implements fs.FileOperations.Write.
@@ -350,8 +350,8 @@ func (s *SocketOperations) Write(ctx context.Context, _ *fs.File, src usermem.IO
ctrl := control.New(t, s.ep, nil)
if src.NumBytes() == 0 {
- nInt, tcpipError := s.ep.SendMsg([][]byte{}, ctrl, nil)
- return int64(nInt), syserr.TranslateNetstackError(tcpipError).ToError()
+ nInt, err := s.ep.SendMsg([][]byte{}, ctrl, nil)
+ return int64(nInt), err.ToError()
}
return src.CopyInTo(ctx, &EndpointWriter{
@@ -448,7 +448,7 @@ func (s *SocketOperations) Shutdown(t *kernel.Task, how int) *syserr.Error {
}
// Issue shutdown request.
- return syserr.TranslateNetstackError(s.ep.Shutdown(f))
+ return s.ep.Shutdown(f)
}
// Read implements fs.FileOperations.Read.