kevy_uring/layout.rs
1//! `#[repr(C)]` wire-layout structs the kernel reads/writes through the
2//! shared mmap regions. These are the io_uring ABI definitions translated
3//! from `<linux/io_uring.h>`.
4
5/// `struct io_sqring_offsets` — byte offsets of each SQ cursor inside the SQ
6/// ring mapping, returned by `io_uring_setup`.
7#[repr(C)]
8#[derive(Default)]
9pub struct IoSqringOffsets {
10 pub head: u32,
11 pub tail: u32,
12 pub ring_mask: u32,
13 pub ring_entries: u32,
14 pub flags: u32,
15 pub dropped: u32,
16 pub array: u32,
17 pub resv1: u32,
18 pub resv2: u64,
19}
20
21/// `struct io_cqring_offsets` — byte offsets of each CQ cursor inside the CQ
22/// ring mapping.
23#[repr(C)]
24#[derive(Default)]
25pub struct IoCqringOffsets {
26 pub head: u32,
27 pub tail: u32,
28 pub ring_mask: u32,
29 pub ring_entries: u32,
30 pub overflow: u32,
31 pub cqes: u32,
32 pub flags: u32,
33 pub resv1: u32,
34 pub resv2: u64,
35}
36
37/// `struct io_uring_params` — `io_uring_setup`'s in/out parameter.
38#[repr(C)]
39#[derive(Default)]
40pub struct IoUringParams {
41 pub sq_entries: u32,
42 pub cq_entries: u32,
43 pub flags: u32,
44 pub sq_thread_cpu: u32,
45 pub sq_thread_idle: u32,
46 pub features: u32,
47 pub wq_fd: u32,
48 pub resv: [u32; 3],
49 pub sq_off: IoSqringOffsets,
50 pub cq_off: IoCqringOffsets,
51}
52
53/// `struct io_uring_sqe` — the 64-byte submission entry.
54#[repr(C)]
55pub struct IoUringSqe {
56 pub opcode: u8,
57 pub flags: u8,
58 pub ioprio: u16,
59 pub fd: i32,
60 pub off: u64,
61 pub addr: u64,
62 pub len: u32,
63 pub rw_flags: u32,
64 pub user_data: u64,
65 pub buf_index: u16,
66 pub personality: u16,
67 pub splice_fd_in: i32,
68 pub addr3: u64,
69 pub __pad2: u64,
70}
71
72impl IoUringSqe {
73 /// A zeroed SQE with the common fields set. Op-specific fields (e.g.
74 /// `rw_flags` for accept flags) are tweaked by the caller afterward.
75 pub fn new(opcode: u8, fd: i32, addr: u64, len: u32, user_data: u64) -> IoUringSqe {
76 IoUringSqe {
77 opcode,
78 flags: 0,
79 ioprio: 0,
80 fd,
81 off: 0,
82 addr,
83 len,
84 rw_flags: 0,
85 user_data,
86 buf_index: 0,
87 personality: 0,
88 splice_fd_in: 0,
89 addr3: 0,
90 __pad2: 0,
91 }
92 }
93}
94
95/// `struct __kernel_timespec` — the timeout payload an `IORING_OP_TIMEOUT`
96/// SQE points at (always 64-bit fields, independent of the C `time_t` width).
97#[repr(C)]
98#[derive(Default)]
99pub struct KernelTimespec {
100 /// Whole seconds of the (relative) timeout.
101 pub tv_sec: i64,
102 /// Sub-second remainder in nanoseconds (`0..1_000_000_000`).
103 pub tv_nsec: i64,
104}
105
106impl KernelTimespec {
107 /// A relative timeout of `ms` milliseconds.
108 pub fn from_millis(ms: u64) -> KernelTimespec {
109 KernelTimespec {
110 tv_sec: (ms / 1000) as i64,
111 tv_nsec: ((ms % 1000) * 1_000_000) as i64,
112 }
113 }
114
115 /// A relative timeout of `us` microseconds — for sub-ms nap timers
116 /// (io_uring reactor's bounded nap; the previous `thread::sleep`
117 /// version was wake-deaf and broke -c1 Rust-client latency).
118 pub fn from_micros(us: u64) -> KernelTimespec {
119 KernelTimespec {
120 tv_sec: (us / 1_000_000) as i64,
121 tv_nsec: ((us % 1_000_000) * 1_000) as i64,
122 }
123 }
124}
125
126/// `struct io_uring_buf_reg` — `io_uring_register(IORING_REGISTER_PBUF_RING,
127/// …)`'s argument layout.
128#[repr(C)]
129pub struct IoUringBufReg {
130 pub ring_addr: u64,
131 pub ring_entries: u32,
132 pub bgid: u16,
133 pub pad: u16,
134 pub resv: [u64; 3],
135}
136
137/// `struct io_uring_files_update` — `io_uring_register(IORING_REGISTER_FILES_UPDATE,
138/// …)`'s argument layout. Updates a contiguous range of `len` slots starting
139/// at `offset` in the registered files table; `fds` points to `len` i32 fds
140/// (use -1 to clear a slot).
141#[repr(C)]
142pub struct IoUringFilesUpdate {
143 pub offset: u32,
144 pub resv: u32,
145 pub fds: u64,
146}
147
148/// `struct io_uring_rsrc_update` — kernel `struct io_uring_rsrc_update`,
149/// the argument layout for [`crate::ffi::IORING_REGISTER_RING_FDS`]. The
150/// caller fills `data` with the raw ring fd to register; the kernel writes
151/// the assigned index back into `offset`. `nr_args` in the syscall is the
152/// number of entries in the array (we register one at a time).
153#[repr(C)]
154#[derive(Default)]
155pub struct IoUringRsrcUpdate {
156 pub offset: u32,
157 pub resv: u32,
158 pub data: u64,
159}
160
161/// `struct io_uring_rsrc_register` — `io_uring_register(IORING_REGISTER_FILES2,
162/// …)`'s argument layout. With `flags = IORING_RSRC_REGISTER_SPARSE` and
163/// `nr = slot_count` it registers an empty registered-files table of that
164/// size. `data`/`tags` are unused for sparse registration. `nr_args` in the
165/// syscall must equal `sizeof::<Self>()` = 32.
166#[repr(C)]
167#[derive(Default)]
168pub struct IoUringRsrcRegister {
169 pub nr: u32,
170 pub flags: u32,
171 pub resv2: u64,
172 pub data: u64,
173 pub tags: u64,
174}
175
176/// `IORING_RSRC_REGISTER_SPARSE` — tells the kernel "no initial fds, just
177/// give me an empty table of size `nr`."
178pub const IORING_RSRC_REGISTER_SPARSE: u32 = 1 << 0;