mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
io_uring_enter: adding support for READV operation.
Handling NOP operations helped us to introduce facilities to process submission requests. Now we can proceed to adding more meaningful operations. The logical choice for the first one is the READV operation as it is a next operation after NOP and it is also used for the cat-like application example based of IO_URING. PiperOrigin-RevId: 487615618
This commit is contained in:
committed by
gVisor bot
parent
ae136df849
commit
60f83d99ea
@@ -26,6 +26,11 @@ const (
|
||||
IORING_SETUP_SUBMIT_ALL = (1 << 7)
|
||||
)
|
||||
|
||||
// Constants for io_uring_enter(2). See include/uapi/linux/io_uring.h.
|
||||
const (
|
||||
IORING_ENTER_GETEVENTS = (1 << 0)
|
||||
)
|
||||
|
||||
// Constants for IoUringParams.Features. See include/uapi/linux/io_uring.h.
|
||||
const (
|
||||
IORING_FEAT_SINGLE_MMAP = (1 << 0)
|
||||
@@ -53,6 +58,12 @@ const (
|
||||
IORING_OFF_SQES = 0x10000000
|
||||
)
|
||||
|
||||
// Constants for the IO_URING opcodes. See include/uapi/linux/io_uring.h.
|
||||
const (
|
||||
IORING_OP_NOP = 0
|
||||
IORING_OP_READV = 1
|
||||
)
|
||||
|
||||
// IORingIndex represents SQE array indexes.
|
||||
//
|
||||
// +marshal
|
||||
@@ -161,14 +172,14 @@ type IORings struct {
|
||||
type IOUringSqe struct {
|
||||
Opcode uint8
|
||||
Flags uint8
|
||||
ioPrio uint16
|
||||
fd int32
|
||||
offOrAddrOrCmdOp uint64
|
||||
addrOrSpliceOff uint64
|
||||
len uint32
|
||||
IoPrio uint16
|
||||
Fd int32
|
||||
OffOrAddrOrCmdOp uint64
|
||||
AddrOrSpliceOff uint64
|
||||
Len uint32
|
||||
specialFlags uint32
|
||||
UserData uint64
|
||||
bufIndexOrGroup uint16
|
||||
BufIndexOrGroup uint16
|
||||
personality uint16
|
||||
spliceFDOrFileIndex int32
|
||||
addr3 uint64
|
||||
|
||||
@@ -13,10 +13,12 @@ go_library(
|
||||
"//pkg/errors/linuxerr",
|
||||
"//pkg/hostarch",
|
||||
"//pkg/safemem",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/memmap",
|
||||
"//pkg/sentry/pgalloc",
|
||||
"//pkg/sentry/usage",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/usermem",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -32,10 +32,12 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
"gvisor.dev/gvisor/pkg/hostarch"
|
||||
"gvisor.dev/gvisor/pkg/safemem"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/memmap"
|
||||
"gvisor.dev/gvisor/pkg/sentry/pgalloc"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usage"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
// FileDescription implements vfs.FileDescriptionImpl for file-based IO_URING.
|
||||
@@ -313,7 +315,7 @@ func (fd *FileDescription) ConfigureMMap(ctx context.Context, opts *memmap.MMapO
|
||||
}
|
||||
|
||||
// ProcessSubmissions processes submission requests.
|
||||
func (fd *FileDescription) ProcessSubmissions(toSubmit uint32, minComplete uint32, flags uint32) (int, error) {
|
||||
func (fd *FileDescription) ProcessSubmissions(t *kernel.Task, toSubmit uint32, minComplete uint32, flags uint32) (int, error) {
|
||||
fd.mu.Lock()
|
||||
defer fd.mu.Unlock()
|
||||
|
||||
@@ -345,10 +347,7 @@ func (fd *FileDescription) ProcessSubmissions(toSubmit uint32, minComplete uint3
|
||||
return -1, err
|
||||
}
|
||||
|
||||
cqe, err := fd.ProcessSubmission(&sqe, flags)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
cqe := fd.ProcessSubmission(t, &sqe, flags)
|
||||
sqHead.Add(1)
|
||||
if (cqTail.Load()-cqHead.Load())/ioRings.CqRingEntries == 1 {
|
||||
ioRings.CqOverflow++
|
||||
@@ -371,21 +370,75 @@ func (fd *FileDescription) ProcessSubmissions(toSubmit uint32, minComplete uint3
|
||||
}
|
||||
|
||||
// ProcessSubmission processes a single submission request.
|
||||
func (fd *FileDescription) ProcessSubmission(sqe *linux.IOUringSqe, flags uint32) (*linux.IOUringCqe, error) {
|
||||
func (fd *FileDescription) ProcessSubmission(t *kernel.Task, sqe *linux.IOUringSqe, flags uint32) *linux.IOUringCqe {
|
||||
var (
|
||||
cqeErr error
|
||||
cqeFlags uint32
|
||||
retValue int32
|
||||
)
|
||||
|
||||
switch op := sqe.Opcode; op {
|
||||
case 0: // NOP
|
||||
return &linux.IOUringCqe{
|
||||
UserData: sqe.UserData,
|
||||
Res: 0,
|
||||
Flags: 0,
|
||||
}, nil
|
||||
case linux.IORING_OP_NOP:
|
||||
// For the NOP operation, we don't do anything special.
|
||||
case linux.IORING_OP_READV:
|
||||
retValue, cqeErr = fd.handleReadv(t, sqe, flags)
|
||||
default: // Unsupported operation
|
||||
return &linux.IOUringCqe{
|
||||
UserData: sqe.UserData,
|
||||
Res: -int32(linuxerr.EINVAL.Errno()),
|
||||
Flags: 0,
|
||||
}, nil
|
||||
retValue = -int32(linuxerr.EINVAL.Errno())
|
||||
}
|
||||
|
||||
if cqeErr != nil {
|
||||
retValue = -int32(kernel.ExtractErrno(cqeErr, -1))
|
||||
}
|
||||
|
||||
return &linux.IOUringCqe{
|
||||
UserData: sqe.UserData,
|
||||
Res: retValue,
|
||||
Flags: cqeFlags,
|
||||
}
|
||||
}
|
||||
|
||||
// handleReadv handles IORING_OP_READV.
|
||||
func (fd *FileDescription) handleReadv(t *kernel.Task, sqe *linux.IOUringSqe, flags uint32) (int32, error) {
|
||||
// Check that a file descriptor is valid.
|
||||
if sqe.Fd < 0 {
|
||||
return 0, linuxerr.EBADF
|
||||
}
|
||||
// Currently we don't support any flags for the SQEs.
|
||||
if sqe.Flags != 0 {
|
||||
return 0, linuxerr.EINVAL
|
||||
}
|
||||
// If the file is not seekable then offset must be zero. And currently, we don't support them.
|
||||
if sqe.OffOrAddrOrCmdOp != 0 {
|
||||
return 0, linuxerr.EINVAL
|
||||
}
|
||||
// ioprio should not be set for the READV operation.
|
||||
if sqe.IoPrio != 0 {
|
||||
return 0, linuxerr.EINVAL
|
||||
}
|
||||
// buf_index should not be set for the READV operation.
|
||||
if sqe.BufIndexOrGroup != 0 {
|
||||
return 0, linuxerr.EINVAL
|
||||
}
|
||||
|
||||
// AddressSpaceActive is set to true as we are doing this from the task goroutine.And this is a
|
||||
// case as we currently don't support neither IOPOLL nor SQPOLL modes.
|
||||
dst, err := t.IovecsIOSequence(hostarch.Addr(sqe.AddrOrSpliceOff), int(sqe.Len), usermem.IOOpts{
|
||||
AddressSpaceActive: true,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
file := t.GetFileVFS2(sqe.Fd)
|
||||
if file == nil {
|
||||
return 0, linuxerr.EBADF
|
||||
}
|
||||
defer file.DecRef(t)
|
||||
n, err := file.PRead(t, dst, 0, vfs.ReadOptions{})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return int32(n), nil
|
||||
}
|
||||
|
||||
// updateCq updates a completion queue by adding a given completion queue entry.
|
||||
|
||||
@@ -86,7 +86,7 @@ func IOUringEnter(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.
|
||||
ret := -1
|
||||
|
||||
// List of currently supported flags for io_uring_enter(2).
|
||||
const supportedFlags = 0 // Currently support none
|
||||
const supportedFlags = linux.IORING_ENTER_GETEVENTS
|
||||
|
||||
// Since we don't implement everything, we fail explicitly on flags that are unimplemented.
|
||||
if flags|supportedFlags != supportedFlags {
|
||||
@@ -112,7 +112,7 @@ func IOUringEnter(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.
|
||||
if !ok {
|
||||
return uintptr(ret), nil, linuxerr.EBADF
|
||||
}
|
||||
ret, err := iouringfd.ProcessSubmissions(toSubmit, minComplete, flags)
|
||||
ret, err := iouringfd.ProcessSubmissions(t, toSubmit, minComplete, flags)
|
||||
if err != nil {
|
||||
return uintptr(ret), nil, err
|
||||
}
|
||||
|
||||
+530
-11
File diff suppressed because it is too large
Load Diff
@@ -68,6 +68,8 @@ cc_library(
|
||||
":file_descriptor",
|
||||
":posix_error",
|
||||
":save_util",
|
||||
"//test/util:temp_path",
|
||||
"//test/util:test_util",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define GVISOR_TEST_UTIL_IOURING_UTIL_H_
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <atomic>
|
||||
@@ -36,6 +37,9 @@ namespace testing {
|
||||
#define IORING_SETUP_SQPOLL (1U << 1)
|
||||
#define IORING_SETUP_CQSIZE (1U << 3)
|
||||
|
||||
// io_uring_enter(2) flags
|
||||
#define IORING_ENTER_GETEVENTS (1U << 0)
|
||||
|
||||
#define IORING_FEAT_SINGLE_MMAP (1U << 0)
|
||||
|
||||
#define IORING_OFF_SQ_RING 0ULL
|
||||
@@ -44,6 +48,9 @@ namespace testing {
|
||||
|
||||
// IO_URING operation codes.
|
||||
#define IORING_OP_NOP 0
|
||||
#define IORING_OP_READV 1
|
||||
|
||||
#define BLOCK_SZ kPageSize
|
||||
|
||||
struct io_sqring_offsets {
|
||||
uint32_t head;
|
||||
|
||||
Reference in New Issue
Block a user