commit ad0e2cef986d0df1ce241945147b846deb11f349
parent d9489a887724bc0a012c7764e05039ec576c87e8
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 17 May 2021 16:06:31 -0400
linux::io_uring: implement io_uring_register
Diffstat:
6 files changed, 154 insertions(+), 12 deletions(-)
diff --git a/linux/io_uring/register.ha b/linux/io_uring/register.ha
@@ -0,0 +1,144 @@
+use errors;
+use rt;
+use types;
+
+// Registers a set of fixed buffers with an [[io_uring]]. Note that you must
+// call [[unregister_buffers]] before registering a new set of buffers (even if
+// some of them have similar addresses to the old set).
+export fn register_buffers(ring: *io_uring, iov: []rt::iovec) (void | error) = {
+ assert(len(iov) <= types::UINT_MAX);
+ return match (rt::io_uring_register(ring.fd, regop::REGISTER_BUFFERS,
+ iov: *[*]rt::iovec, len(iov): uint)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
+
+// Unregisters all fixed buffers associated with an [[io_uring]].
+export fn unregister_buffers(ring: *io_uring) (void | error) = {
+ return match (rt::io_uring_register(ring.fd,
+ regop::UNREGISTER_BUFFERS, null, 0)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
+
+// Registers a set of file descriptors with an [[io_uring]]. The set of files
+// may be sparse, meaning that some are set to -1, to be updated later using
+// [[register_files_update]].
+export fn register_files(ring: *io_uring, files: []int) (void | error) = {
+ assert(len(files) <= types::UINT_MAX);
+ return match (rt::io_uring_register(ring.fd, regop::REGISTER_FILES,
+ files: *[*]int, len(files): uint)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
+
+// Applies a set of [[files_update]]s to the set of files registered with an
+// [[io_uring]].
+export fn register_files_update(
+ ring: *io_uring,
+ updates: []files_update,
+) (void | error) = {
+ assert(len(updates) <= types::UINT_MAX);
+ return match (rt::io_uring_register(ring.fd, regop::REGISTER_FILES_UPDATE,
+ updates: *[*]files_update, len(updates): uint)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
+
+// Unregisters all files associated with an [[io_uring]].
+export fn unregister_files(ring: *io_uring) (void | error) = {
+ return match (rt::io_uring_register(ring.fd,
+ regop::UNREGISTER_FILES, null, 0)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
+
+// Registers an eventfd(2) with this [[io_uring]] to be notified of completion
+// events.
+export fn register_eventfd(ring: *io_uring, fd: int) (void | error) = {
+ return match (rt::io_uring_register(ring.fd,
+ regop::REGISTER_EVENTFD, &fd, 1)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
+
+// Similar to [[register_eventfd]], but only notifies of events which complet
+// asyncronously.
+export fn register_eventfd_async(ring: *io_uring, fd: int) (void | error) = {
+ return match (rt::io_uring_register(ring.fd,
+ regop::REGISTER_EVENTFD_ASYNC, &fd, 1)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
+
+// Unregisters the eventfd(2) associated with this [[io_uring]].
+export fn unregister_eventfd(ring: *io_uring) (void | error) = {
+ return match (rt::io_uring_register(ring.fd,
+ regop::UNREGISTER_EVENTFD, null, 0)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
+
+// XXX: This interface is pretty bad. It would be nice to improve on it
+// a bit before making it part of the API.
+//export fn register_probe(ring: *io_uring, out: *probe, nops: size) void = {
+// assert(nops * size(probe_op) <= types::UINT_MAX);
+// match (rt::io_uring_register(ring.fd, regop::REGISTER_PROBE,
+// out, (nops * size(probe)): uint)) {
+// rt::errno => abort("Unexpected io_uring REGISTER_PROBE error"),
+// void => void,
+// };
+//};
+
+// Registers the current process's credentials as a personality with an
+// [[io_uring]], returning an ID. Set the personality field of an [[sqe]] to use
+// that personality for an I/O submission.
+export fn register_personality(ring: *io_uring) int = {
+ return match (rt::io_uring_register(ring.fd,
+ regop::REGISTER_PERSONALITY, null, 0)) {
+ rt::errno => abort("Unexpected io_uring REGISTER_PERSONALITY error"),
+ i: int => i,
+ };
+};
+
+// Unregisters a personality previously configured with
+// [[register_personality]].
+export fn unregister_personality(ring: *io_uring, id: int) (void | error) = {
+ return match (rt::io_uring_register(ring.fd,
+ regop::UNREGISTER_PERSONALITY, null, id: uint)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
+
+// Enables submissions for an [[io_uring]] which was started in the disabled
+// state via [[setup_flags::R_DISABLED]]. Future access to this io_uring is
+// subject to any configured restrictions.
+export fn register_enable_rings(ring: *io_uring) (void | error) = {
+ return match (rt::io_uring_register(ring.fd,
+ regop::REGISTER_ENABLE_RINGS, null, 0)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
+
+// Registers a restriction for this [[io_uring]], limiting the kinds of future
+// registrations and I/O submissions which are permitted for it. This is only
+// accepted if the [[io_uring]] was set up in a disabled state via
+// [[setup_flags::R_DISABLED]].
+export fn register_restrictions(ring: *io_uring, res: []restriction) (void | error) = {
+ assert(len(res) < types::UINT_MAX);
+ return match (rt::io_uring_register(ring.fd, regop::REGISTER_RESTRICTIONS,
+ res: *[*]restriction, len(res): uint)) {
+ err: rt::errno => errors::errno(err),
+ int => void,
+ };
+};
diff --git a/linux/io_uring/sqe.ha b/linux/io_uring/sqe.ha
@@ -1,5 +1,3 @@
-// TODO:
-// - Interface for buffer registration
use rt;
use types;
diff --git a/linux/io_uring/uring.ha b/linux/io_uring/uring.ha
@@ -276,18 +276,18 @@ export type probe = struct {
// Details for a REGISTER_RESTRICTIONS operation.
export type restriction = struct {
- opcode: restriction_op,
+ opcode: resop,
union {
- register_op: u8,
- sqe_op: u8,
- sqe_flags: u8,
+ register_op: regop,
+ sqe_op: op,
+ sqe_flags: sqe_flags,
},
resv: u8,
resv2: [3]u32,
};
// Opcode for a [[restriction]].
-export type restriction_op = enum u16 {
+export type resop = enum u16 {
// Allow an io_uring_register(2) opcode
REGISTER_OP = 0,
// Allow an sqe opcode
diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha
@@ -608,11 +608,8 @@ export fn io_uring_register(
opcode: uint,
arg: nullable *void,
nr_args: uint,
-) (void | errno) = {
- wrap_return(syscall4(SYS_io_uring_register,
- fd: u64, opcode: u64, arg: uintptr: u64, nr_args: u64))?;
- return;
-};
+) (int | errno) = wrap_return(syscall4(SYS_io_uring_register,
+ fd: u64, opcode: u64, arg: uintptr: u64, nr_args: u64))?: int;
export fn io_uring_enter(
fd: int,
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -520,6 +520,7 @@ linux() {
linux_io_uring() {
gen_srcs linux::io_uring \
queue.ha \
+ register.ha \
setup.ha \
sqe.ha \
uring.ha
diff --git a/stdlib.mk b/stdlib.mk
@@ -759,6 +759,7 @@ $(HARECACHE)/linux/linux.ssa: $(stdlib_linux_srcs) $(stdlib_rt) $(stdlib_format_
# linux::io_uring
stdlib_linux_io_uring_srcs= \
$(STDLIB)/linux/io_uring/queue.ha \
+ $(STDLIB)/linux/io_uring/register.ha \
$(STDLIB)/linux/io_uring/setup.ha \
$(STDLIB)/linux/io_uring/sqe.ha \
$(STDLIB)/linux/io_uring/uring.ha
@@ -1811,6 +1812,7 @@ $(TESTCACHE)/linux/linux.ssa: $(testlib_linux_srcs) $(testlib_rt) $(testlib_form
# linux::io_uring
testlib_linux_io_uring_srcs= \
$(STDLIB)/linux/io_uring/queue.ha \
+ $(STDLIB)/linux/io_uring/register.ha \
$(STDLIB)/linux/io_uring/setup.ha \
$(STDLIB)/linux/io_uring/sqe.ha \
$(STDLIB)/linux/io_uring/uring.ha