summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBrian Geffon <bgeffon@google.com>2018-12-04 18:14:17 -0800
committerShentubot <shentubot@google.com>2018-12-04 18:15:10 -0800
commitffcbda0c8bd772c9019977775daf1d86891c3f28 (patch)
treed1ba294f99df79f301e01d82f6916286899e0789
parentd209f71b9f1b6ab57684240112553aa8c700f929 (diff)
Partial writes should loop in rpcinet.
FileOperations.Write should return ErrWouldBlock to allow the upper layer to loop and sendmsg should continue writing where it left off on a partial write. PiperOrigin-RevId: 224081631 Change-Id: Ic61f6943ea6b7abbd82e4279decea215347eac48
-rw-r--r--pkg/sentry/socket/rpcinet/socket.go39
1 files changed, 33 insertions, 6 deletions
diff --git a/pkg/sentry/socket/rpcinet/socket.go b/pkg/sentry/socket/rpcinet/socket.go
index 7328661ab..90844f10f 100644
--- a/pkg/sentry/socket/rpcinet/socket.go
+++ b/pkg/sentry/socket/rpcinet/socket.go
@@ -212,6 +212,11 @@ func (s *socketOperations) Write(ctx context.Context, _ *fs.File, src usermem.IO
}
n, err := rpcWrite(t, &pb.SyscallRequest_Write{&pb.WriteRequest{Fd: s.fd, Data: v}})
+ if n > 0 && n < uint32(src.NumBytes()) {
+ // The FileOperations.Write interface expects us to return ErrWouldBlock in
+ // the event of a partial write.
+ return int64(n), syserror.ErrWouldBlock
+ }
return int64(n), err.ToError()
}
@@ -735,19 +740,24 @@ func (s *socketOperations) SendMsg(t *kernel.Task, src usermem.IOSequence, to []
// TODO: this needs to change to map directly to a SendMsg syscall
// in the RPC.
- req := &pb.SyscallRequest_Sendmsg{&pb.SendmsgRequest{
+ totalWritten := 0
+ n, err := rpcSendMsg(t, &pb.SyscallRequest_Sendmsg{&pb.SendmsgRequest{
Fd: uint32(s.fd),
Data: v,
Address: to,
More: flags&linux.MSG_MORE != 0,
EndOfRecord: flags&linux.MSG_EOR != 0,
- }}
+ }})
- n, err := rpcSendMsg(t, req)
if err != syserr.ErrWouldBlock && err != syserr.ErrTryAgain || flags&linux.MSG_DONTWAIT != 0 {
return int(n), err
}
+ if n > 0 {
+ totalWritten += int(n)
+ v.TrimFront(int(n))
+ }
+
// We'll have to block. Register for notification and keep trying to
// send all the data.
e, ch := waiter.NewChannelEntry(nil)
@@ -755,13 +765,30 @@ func (s *socketOperations) SendMsg(t *kernel.Task, src usermem.IOSequence, to []
defer s.EventUnregister(&e)
for {
- n, err := rpcSendMsg(t, req)
+ n, err := rpcSendMsg(t, &pb.SyscallRequest_Sendmsg{&pb.SendmsgRequest{
+ Fd: uint32(s.fd),
+ Data: v,
+ Address: to,
+ More: flags&linux.MSG_MORE != 0,
+ EndOfRecord: flags&linux.MSG_EOR != 0,
+ }})
+
+ if n > 0 {
+ totalWritten += int(n)
+ v.TrimFront(int(n))
+
+ if err == nil && totalWritten < int(src.NumBytes()) {
+ continue
+ }
+ }
+
if err != syserr.ErrWouldBlock && err != syserr.ErrTryAgain {
- return int(n), err
+ // We eat the error in this situation.
+ return int(totalWritten), nil
}
if err := t.Block(ch); err != nil {
- return 0, syserr.FromError(err)
+ return int(totalWritten), syserr.FromError(err)
}
}
}