gvisor/fs: don't update file.offset for sockets, pipes, etc
sockets, pipes and other non-seekable file descriptors don't use file.offset, so we don't need to update it. With this change, we will be able to call file operations without locking the file.mu mutex. This is already used for pipes in the splice system call. PiperOrigin-RevId: 253746644
This commit is contained in:
parent
3d1e44a677
commit
8ab0848c70
|
@ -97,6 +97,7 @@ func newZeroDevice(ctx context.Context, owner fs.FileOwner, mode linux.FileMode)
|
|||
func (zd *zeroDevice) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
|
||||
flags.Pread = true
|
||||
flags.Pwrite = true
|
||||
flags.NonSeekable = true
|
||||
|
||||
return fs.NewFile(ctx, dirent, flags, &zeroFileOperations{}), nil
|
||||
}
|
||||
|
|
|
@ -267,7 +267,7 @@ func (f *File) Readv(ctx context.Context, dst usermem.IOSequence) (int64, error)
|
|||
|
||||
reads.Increment()
|
||||
n, err := f.FileOperations.Read(ctx, f, dst, f.offset)
|
||||
if n > 0 {
|
||||
if n > 0 && !f.flags.NonSeekable {
|
||||
atomic.AddInt64(&f.offset, n)
|
||||
}
|
||||
f.mu.Unlock()
|
||||
|
@ -330,7 +330,7 @@ func (f *File) Writev(ctx context.Context, src usermem.IOSequence) (int64, error
|
|||
|
||||
// We must hold the lock during the write.
|
||||
n, err := f.FileOperations.Write(ctx, f, src, f.offset)
|
||||
if n >= 0 {
|
||||
if n >= 0 && !f.flags.NonSeekable {
|
||||
atomic.StoreInt64(&f.offset, f.offset+n)
|
||||
}
|
||||
f.mu.Unlock()
|
||||
|
|
|
@ -57,6 +57,9 @@ type FileFlags struct {
|
|||
// Linux sets this flag for all files. Since gVisor is only compatible
|
||||
// with 64-bit Linux, it also sets this flag for all files.
|
||||
LargeFile bool
|
||||
|
||||
// NonSeekable indicates that file.offset isn't used.
|
||||
NonSeekable bool
|
||||
}
|
||||
|
||||
// SettableFileFlags is a subset of FileFlags above that can be changed
|
||||
|
|
|
@ -162,6 +162,7 @@ func NewConnectedPipe(ctx context.Context, sizeBytes, atomicIOBytes int64) (*fs.
|
|||
//
|
||||
// Precondition: at least one of flags.Read or flags.Write must be set.
|
||||
func (p *Pipe) Open(ctx context.Context, d *fs.Dirent, flags fs.FileFlags) *fs.File {
|
||||
flags.NonSeekable = true
|
||||
switch {
|
||||
case flags.Read && flags.Write:
|
||||
p.rOpen()
|
||||
|
|
|
@ -262,7 +262,7 @@ func New(t *kernel.Task, family int, skType linux.SockType, protocol int, queue
|
|||
|
||||
dirent := socket.NewDirent(t, epsocketDevice)
|
||||
defer dirent.DecRef()
|
||||
return fs.NewFile(t, dirent, fs.FileFlags{Read: true, Write: true}, &SocketOperations{
|
||||
return fs.NewFile(t, dirent, fs.FileFlags{Read: true, Write: true, NonSeekable: true}, &SocketOperations{
|
||||
Queue: queue,
|
||||
family: family,
|
||||
Endpoint: endpoint,
|
||||
|
|
|
@ -77,7 +77,7 @@ func newSocketFile(ctx context.Context, family int, stype linux.SockType, protoc
|
|||
}
|
||||
dirent := socket.NewDirent(ctx, socketDevice)
|
||||
defer dirent.DecRef()
|
||||
return fs.NewFile(ctx, dirent, fs.FileFlags{NonBlocking: nonblock, Read: true, Write: true}, s), nil
|
||||
return fs.NewFile(ctx, dirent, fs.FileFlags{NonBlocking: nonblock, Read: true, Write: true, NonSeekable: true}, s), nil
|
||||
}
|
||||
|
||||
// Release implements fs.FileOperations.Release.
|
||||
|
|
|
@ -89,7 +89,7 @@ func (*socketProvider) Socket(t *kernel.Task, stype linux.SockType, protocol int
|
|||
|
||||
d := socket.NewDirent(t, netlinkSocketDevice)
|
||||
defer d.DecRef()
|
||||
return fs.NewFile(t, d, fs.FileFlags{Read: true, Write: true}, s), nil
|
||||
return fs.NewFile(t, d, fs.FileFlags{Read: true, Write: true, NonSeekable: true}, s), nil
|
||||
}
|
||||
|
||||
// Pair implements socket.Provider.Pair by returning an error.
|
||||
|
|
|
@ -322,7 +322,13 @@ func (s *socketOperations) Accept(t *kernel.Task, peerRequested bool, flags int,
|
|||
|
||||
dirent := socket.NewDirent(t, socketDevice)
|
||||
defer dirent.DecRef()
|
||||
file := fs.NewFile(t, dirent, fs.FileFlags{Read: true, Write: true, NonBlocking: flags&linux.SOCK_NONBLOCK != 0}, &socketOperations{
|
||||
fileFlags := fs.FileFlags{
|
||||
Read: true,
|
||||
Write: true,
|
||||
NonSeekable: true,
|
||||
NonBlocking: flags&linux.SOCK_NONBLOCK != 0,
|
||||
}
|
||||
file := fs.NewFile(t, dirent, fileFlags, &socketOperations{
|
||||
wq: &wq,
|
||||
fd: payload.Fd,
|
||||
rpcConn: s.rpcConn,
|
||||
|
|
|
@ -64,7 +64,7 @@ type SocketOperations struct {
|
|||
func New(ctx context.Context, endpoint transport.Endpoint, stype linux.SockType) *fs.File {
|
||||
dirent := socket.NewDirent(ctx, unixSocketDevice)
|
||||
defer dirent.DecRef()
|
||||
return NewWithDirent(ctx, dirent, endpoint, stype, fs.FileFlags{Read: true, Write: true})
|
||||
return NewWithDirent(ctx, dirent, endpoint, stype, fs.FileFlags{Read: true, Write: true, NonSeekable: true})
|
||||
}
|
||||
|
||||
// NewWithDirent creates a new unix socket using an existing dirent.
|
||||
|
|
Loading…
Reference in New Issue