summaryrefslogtreecommitdiffhomepage
path: root/pkg/sentry/fsimpl/devpts/queue.go
diff options
context:
space:
mode:
authorEtienne Perot <eperot@google.com>2021-07-08 12:01:47 -0700
committergVisor bot <gvisor-bot@google.com>2021-07-08 12:04:56 -0700
commit07f2c8b56b5948759b3df6587a8fcea13fbcc82b (patch)
tree7dd45402c07749ed81dae5172913a1a911002256 /pkg/sentry/fsimpl/devpts/queue.go
parent1fc7a9eac2f27053ed4ca138c6568b14ef520648 (diff)
devpts: Notify of echo'd input queue bytes only after locks have been released.
PiperOrigin-RevId: 383684320
Diffstat (limited to 'pkg/sentry/fsimpl/devpts/queue.go')
-rw-r--r--pkg/sentry/fsimpl/devpts/queue.go42
1 files changed, 25 insertions, 17 deletions
diff --git a/pkg/sentry/fsimpl/devpts/queue.go b/pkg/sentry/fsimpl/devpts/queue.go
index 47b0f1599..ff1d89955 100644
--- a/pkg/sentry/fsimpl/devpts/queue.go
+++ b/pkg/sentry/fsimpl/devpts/queue.go
@@ -98,17 +98,19 @@ func (q *queue) readableSize(t *kernel.Task, io usermem.IO, args arch.SyscallArg
}
-// read reads from q to userspace. It returns the number of bytes read as well
-// as whether the read caused more readable data to become available (whether
+// read reads from q to userspace. It returns:
+// - The number of bytes read
+// - Whether the read caused more readable data to become available (whether
// data was pushed from the wait buffer to the read buffer).
+// - Whether any data was echoed back (need to notify readers).
//
// Preconditions: l.termiosMu must be held for reading.
-func (q *queue) read(ctx context.Context, dst usermem.IOSequence, l *lineDiscipline) (int64, bool, error) {
+func (q *queue) read(ctx context.Context, dst usermem.IOSequence, l *lineDiscipline) (int64, bool, bool, error) {
q.mu.Lock()
defer q.mu.Unlock()
if !q.readable {
- return 0, false, syserror.ErrWouldBlock
+ return 0, false, false, syserror.ErrWouldBlock
}
if dst.NumBytes() > canonMaxBytes {
@@ -131,19 +133,20 @@ func (q *queue) read(ctx context.Context, dst usermem.IOSequence, l *lineDiscipl
return n, nil
}))
if err != nil {
- return 0, false, err
+ return 0, false, false, err
}
// Move data from the queue's wait buffer to its read buffer.
- nPushed := q.pushWaitBufLocked(l)
+ nPushed, notifyEcho := q.pushWaitBufLocked(l)
- return int64(n), nPushed > 0, nil
+ return int64(n), nPushed > 0, notifyEcho, nil
}
// write writes to q from userspace.
+// The returned boolean indicates whether any data was echoed back.
//
// Preconditions: l.termiosMu must be held for reading.
-func (q *queue) write(ctx context.Context, src usermem.IOSequence, l *lineDiscipline) (int64, error) {
+func (q *queue) write(ctx context.Context, src usermem.IOSequence, l *lineDiscipline) (int64, bool, error) {
q.mu.Lock()
defer q.mu.Unlock()
@@ -173,44 +176,49 @@ func (q *queue) write(ctx context.Context, src usermem.IOSequence, l *lineDiscip
return n, nil
}))
if err != nil {
- return 0, err
+ return 0, false, err
}
// Push data from the wait to the read buffer.
- q.pushWaitBufLocked(l)
+ _, notifyEcho := q.pushWaitBufLocked(l)
- return n, nil
+ return n, notifyEcho, nil
}
// writeBytes writes to q from b.
+// The returned boolean indicates whether any data was echoed back.
//
// Preconditions: l.termiosMu must be held for reading.
-func (q *queue) writeBytes(b []byte, l *lineDiscipline) {
+func (q *queue) writeBytes(b []byte, l *lineDiscipline) bool {
q.mu.Lock()
defer q.mu.Unlock()
// Write to the wait buffer.
q.waitBufAppend(b)
- q.pushWaitBufLocked(l)
+ _, notifyEcho := q.pushWaitBufLocked(l)
+ return notifyEcho
}
// pushWaitBufLocked fills the queue's read buffer with data from the wait
// buffer.
+// The returned boolean indicates whether any data was echoed back.
//
// Preconditions:
// * l.termiosMu must be held for reading.
// * q.mu must be locked.
-func (q *queue) pushWaitBufLocked(l *lineDiscipline) int {
+func (q *queue) pushWaitBufLocked(l *lineDiscipline) (int, bool) {
if q.waitBufLen == 0 {
- return 0
+ return 0, false
}
// Move data from the wait to the read buffer.
var total int
var i int
+ var notifyEcho bool
for i = 0; i < len(q.waitBuf); i++ {
- n := q.transform(l, q, q.waitBuf[i])
+ n, echo := q.transform(l, q, q.waitBuf[i])
total += n
+ notifyEcho = notifyEcho || echo
if n != len(q.waitBuf[i]) {
// The read buffer filled up without consuming the
// entire buffer.
@@ -223,7 +231,7 @@ func (q *queue) pushWaitBufLocked(l *lineDiscipline) int {
q.waitBuf = q.waitBuf[i:]
q.waitBufLen -= uint64(total)
- return total
+ return total, notifyEcho
}
// Precondition: q.mu must be locked.