Enable automated marshalling for epoll events.
Ensure we use the correct architecture-specific defintion of epoll event, and use go-marshal for serialization. PiperOrigin-RevId: 308145677
This commit is contained in:
parent
5042ea7e2c
commit
93dd471461
|
@ -12,11 +12,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build amd64
|
||||
|
||||
package linux
|
||||
|
||||
// EpollEvent is equivalent to struct epoll_event from epoll(2).
|
||||
//
|
||||
// +marshal
|
||||
// +marshal slice:EpollEventSlice
|
||||
type EpollEvent struct {
|
||||
Events uint32
|
||||
// Linux makes struct epoll_event::data a __u64. We represent it as
|
||||
|
|
|
@ -12,11 +12,13 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build arm64
|
||||
|
||||
package linux
|
||||
|
||||
// EpollEvent is equivalent to struct epoll_event from epoll(2).
|
||||
//
|
||||
// +marshal
|
||||
// +marshal slice:EpollEventSlice
|
||||
type EpollEvent struct {
|
||||
Events uint32
|
||||
// Linux makes struct epoll_event a __u64, necessitating 4 bytes of padding
|
||||
|
|
|
@ -24,6 +24,7 @@ go_library(
|
|||
],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/context",
|
||||
"//pkg/refs",
|
||||
"//pkg/sentry/fs",
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/refs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
|
@ -30,19 +31,6 @@ import (
|
|||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
// Event describes the event mask that was observed and the user data to be
|
||||
// returned when one of the events occurs. It has this format to match the linux
|
||||
// format to avoid extra copying/allocation when writing events to userspace.
|
||||
type Event struct {
|
||||
// Events is the event mask containing the set of events that have been
|
||||
// observed on an entry.
|
||||
Events uint32
|
||||
|
||||
// Data is an opaque 64-bit value provided by the caller when adding the
|
||||
// entry, and returned to the caller when the entry reports an event.
|
||||
Data [2]int32
|
||||
}
|
||||
|
||||
// EntryFlags is a bitmask that holds an entry's flags.
|
||||
type EntryFlags int
|
||||
|
||||
|
@ -227,9 +215,9 @@ func (e *EventPoll) Readiness(mask waiter.EventMask) waiter.EventMask {
|
|||
}
|
||||
|
||||
// ReadEvents returns up to max available events.
|
||||
func (e *EventPoll) ReadEvents(max int) []Event {
|
||||
func (e *EventPoll) ReadEvents(max int) []linux.EpollEvent {
|
||||
var local pollEntryList
|
||||
var ret []Event
|
||||
var ret []linux.EpollEvent
|
||||
|
||||
e.listsMu.Lock()
|
||||
|
||||
|
@ -251,7 +239,7 @@ func (e *EventPoll) ReadEvents(max int) []Event {
|
|||
}
|
||||
|
||||
// Add event to the array that will be returned to caller.
|
||||
ret = append(ret, Event{
|
||||
ret = append(ret, linux.EpollEvent{
|
||||
Events: uint32(ready),
|
||||
Data: entry.userData,
|
||||
})
|
||||
|
|
|
@ -17,6 +17,7 @@ package syscalls
|
|||
import (
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/epoll"
|
||||
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
|
||||
|
@ -118,7 +119,7 @@ func RemoveEpoll(t *kernel.Task, epfd int32, fd int32) error {
|
|||
}
|
||||
|
||||
// WaitEpoll implements the epoll_wait(2) linux syscall.
|
||||
func WaitEpoll(t *kernel.Task, fd int32, max int, timeout int) ([]epoll.Event, error) {
|
||||
func WaitEpoll(t *kernel.Task, fd int32, max int, timeout int) ([]linux.EpollEvent, error) {
|
||||
// Get epoll from the file descriptor.
|
||||
epollfile := t.GetFile(fd)
|
||||
if epollfile == nil {
|
||||
|
|
|
@ -21,7 +21,6 @@ import (
|
|||
"gvisor.dev/gvisor/pkg/sentry/kernel/epoll"
|
||||
"gvisor.dev/gvisor/pkg/sentry/syscalls"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
|
@ -72,7 +71,7 @@ func EpollCtl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
|
|||
var data [2]int32
|
||||
if op != linux.EPOLL_CTL_DEL {
|
||||
var e linux.EpollEvent
|
||||
if _, err := t.CopyIn(eventAddr, &e); err != nil {
|
||||
if _, err := e.CopyIn(t, eventAddr); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
|
@ -105,28 +104,6 @@ func EpollCtl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sysc
|
|||
}
|
||||
}
|
||||
|
||||
// copyOutEvents copies epoll events from the kernel to user memory.
|
||||
func copyOutEvents(t *kernel.Task, addr usermem.Addr, e []epoll.Event) error {
|
||||
const itemLen = 12
|
||||
buffLen := len(e) * itemLen
|
||||
if _, ok := addr.AddLength(uint64(buffLen)); !ok {
|
||||
return syserror.EFAULT
|
||||
}
|
||||
|
||||
b := t.CopyScratchBuffer(buffLen)
|
||||
for i := range e {
|
||||
usermem.ByteOrder.PutUint32(b[i*itemLen:], e[i].Events)
|
||||
usermem.ByteOrder.PutUint32(b[i*itemLen+4:], uint32(e[i].Data[0]))
|
||||
usermem.ByteOrder.PutUint32(b[i*itemLen+8:], uint32(e[i].Data[1]))
|
||||
}
|
||||
|
||||
if _, err := t.CopyOutBytes(addr, b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// EpollWait implements the epoll_wait(2) linux syscall.
|
||||
func EpollWait(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
epfd := args[0].Int()
|
||||
|
@ -140,7 +117,7 @@ func EpollWait(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sys
|
|||
}
|
||||
|
||||
if len(r) != 0 {
|
||||
if err := copyOutEvents(t, eventsAddr, r); err != nil {
|
||||
if _, err := linux.CopyEpollEventSliceOut(t, eventsAddr, r); err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ go_library(
|
|||
name = "vfs2",
|
||||
srcs = [
|
||||
"epoll.go",
|
||||
"epoll_unsafe.go",
|
||||
"execve.go",
|
||||
"fd.go",
|
||||
"filesystem.go",
|
||||
|
|
|
@ -28,6 +28,8 @@ import (
|
|||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
var sizeofEpollEvent = (*linux.EpollEvent)(nil).SizeBytes()
|
||||
|
||||
// EpollCreate1 implements Linux syscall epoll_create1(2).
|
||||
func EpollCreate1(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
|
||||
flags := args[0].Int()
|
||||
|
@ -124,7 +126,7 @@ func EpollWait(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sys
|
|||
maxEvents := int(args[2].Int())
|
||||
timeout := int(args[3].Int())
|
||||
|
||||
const _EP_MAX_EVENTS = math.MaxInt32 / sizeofEpollEvent // Linux: fs/eventpoll.c:EP_MAX_EVENTS
|
||||
var _EP_MAX_EVENTS = math.MaxInt32 / sizeofEpollEvent // Linux: fs/eventpoll.c:EP_MAX_EVENTS
|
||||
if maxEvents <= 0 || maxEvents > _EP_MAX_EVENTS {
|
||||
return 0, nil, syserror.EINVAL
|
||||
}
|
||||
|
@ -157,7 +159,8 @@ func EpollWait(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sys
|
|||
maxEvents -= n
|
||||
if n != 0 {
|
||||
// Copy what we read out.
|
||||
copiedEvents, err := copyOutEvents(t, eventsAddr, events[:n])
|
||||
copiedBytes, err := linux.CopyEpollEventSliceOut(t, eventsAddr, events[:n])
|
||||
copiedEvents := copiedBytes / sizeofEpollEvent // rounded down
|
||||
eventsAddr += usermem.Addr(copiedEvents * sizeofEpollEvent)
|
||||
total += copiedEvents
|
||||
if err != nil {
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright 2020 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package vfs2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/gohacks"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
const sizeofEpollEvent = int(unsafe.Sizeof(linux.EpollEvent{}))
|
||||
|
||||
func copyOutEvents(t *kernel.Task, addr usermem.Addr, events []linux.EpollEvent) (int, error) {
|
||||
if len(events) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
// Cast events to a byte slice for copying.
|
||||
var eventBytes []byte
|
||||
eventBytesHdr := (*reflect.SliceHeader)(unsafe.Pointer(&eventBytes))
|
||||
eventBytesHdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(&events[0])))
|
||||
eventBytesHdr.Len = len(events) * sizeofEpollEvent
|
||||
eventBytesHdr.Cap = len(events) * sizeofEpollEvent
|
||||
copiedBytes, err := t.CopyOutBytes(addr, eventBytes)
|
||||
runtime.KeepAlive(events)
|
||||
copiedEvents := copiedBytes / sizeofEpollEvent // rounded down
|
||||
return copiedEvents, err
|
||||
}
|
Loading…
Reference in New Issue