commit 894f7029fe39643c5cba46c81838739762c4b1e3
parent 5fb8ec29c21a8f68e9da23b1a972dadb3c98cfd2
Author: Drew DeVault <sir@cmpwn.com>
Date: Wed, 20 Oct 2021 09:22:31 +0200
linux::io_uring: implement provide_buffers support
Note that this has not been tested. A follow-up patch will integrate
this with iobus and it will be tested there.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
5 files changed, 61 insertions(+), 4 deletions(-)
diff --git a/iobus/io_uring/bus.ha b/iobus/io_uring/bus.ha
@@ -5,7 +5,7 @@ use linux::io_uring;
def DEFAULT_RING_SIZE: u32 = 512;
// Creates a new io_uring I/O bus.
-export fn new() (*bus | errors::error) = {
+export fn new() (*bus | error) = {
let params = io_uring::params { ... };
match (io_uring::setup(DEFAULT_RING_SIZE, ¶ms)) {
case err: io_uring::error =>
diff --git a/iobus/io_uring/types.ha b/iobus/io_uring/types.ha
@@ -3,6 +3,8 @@ use io;
use linux::io_uring;
use rt;
+// TODO: Add our own nobuffers error
+
// All errors which may be raised by iobus.
export type error = io_uring::error;
diff --git a/linux/io_uring/cqe.ha b/linux/io_uring/cqe.ha
@@ -37,6 +37,15 @@ export fn result(cqe: *cqe) (int | error) =
export fn get_user(cqe: *cqe) nullable *void =
cqe.user_data: uintptr: nullable *void;
+// Returns the buffer ID used for this [[cqe]] in combination with
+// [[set_buffer_select]]. Aborts the program if this CQE was not configured to
+// use a buffer pool.
+export fn get_buffer_id(cqe: *cqe) u16 = {
+ assert(cqe.flags & cqe_flags::F_BUFFER > 0,
+ "get_buffer_id called for CQE without buffer");
+ return (cqe.flags: u32 >> CQE_BUFFER_SHIFT): u16;
+};
+
fn peek_cqe(ring: *io_uring) (nullable *cqe, uint) = {
let head = *ring.cq.khead;
let tail = *ring.cq.ktail;
diff --git a/linux/io_uring/sqe.ha b/linux/io_uring/sqe.ha
@@ -33,6 +33,14 @@ export fn set_user(sqe: *sqe, user_data: *void) void = {
sqe.user_data = user_data: uintptr: u64;
};
+// Sets the BUFFER_SELECT flag and sets the desired buffer group. See
+// [[provide_buffers]] for configuring buffer groups, and [[get_buffer_id]] to
+// retrieve the buffer used from the corresponding [[cqe]].
+export fn set_buffer_select(sqe: *sqe, group: u16) void = {
+ sqe.flags |= flags::BUFFER_SELECT;
+ sqe.buf_group = group;
+};
+
// Prepares a no-op "operation" for an [[sqe]].
export fn nop(sqe: *sqe, flags: flags...) void = {
prep(sqe, op::NOP, flags...);
@@ -303,3 +311,32 @@ export fn openat(
export fn close(sqe: *sqe, fd: int, flags: flags...) void = {
preprw(sqe, op::CLOSE, fd, null, 0, 0, flags...);
};
+
+// Prepares an [[sqe]] operation which provides a buffer pool to the kernel.
+// len(pool) must be equal to nbuf * bufsz. See [[set_buffer_select]] to use
+// the buffer pool for a subsequent request.
+export fn provide_buffers(
+ sqe: *sqe,
+ group: u16,
+ pool: []u8,
+ nbuf: size,
+ bufsz: size,
+ bufid: u16,
+ flags: flags...
+) void = {
+ assert(len(pool) == nbuf * bufsz);
+ preprw(sqe, op::PROVIDE_BUFFERS, nbuf: int, pool: *[*]u8,
+ bufsz: uint, bufid: uint, flags...);
+ sqe.buf_group = group;
+};
+
+// Removes buffers previously registered with [[provide_buffers]].
+export fn remove_buffers(
+ sqe: *sqe,
+ nbuf: size,
+ group: u16,
+ flags: flags...
+) void = {
+ preprw(sqe, op::REMOVE_BUFFERS, nbuf: int, null, 0, 0, flags...);
+ sqe.buf_group = group;
+};
diff --git a/linux/io_uring/uring.ha b/linux/io_uring/uring.ha
@@ -1,17 +1,26 @@
use errors;
+// Returned when buffer pool use was configured for an [[sqe]], but there are no
+// buffers available.
+export type nobuffers = !void;
+
// All errors which may be returned by this module.
-export type error = !errors::error;
+export type error = !(errors::error | nobuffers);
// Converts an [[error]] into a human-readable string.
export fn strerror(err: error) const str = {
- return errors::strerror(err);
+ match (err) {
+ case nobuffers =>
+ return "Buffer pool exhausted";
+ case err: errors::error =>
+ return errors::strerror(err);
+ };
};
// The maximum value for the first parameter of [[setup]].
export def MAX_ENTRIES: uint = 4096;
-def CQE_BUFFER_SHIFT: uint = 16;
+def CQE_BUFFER_SHIFT: u32 = 16;
def OFF_SQ_RING: u64 = 0;
def OFF_CQ_RING: u64 = 0x8000000;
def OFF_SQES: u64 = 0x10000000;