Skip to main content

liburing_rs/
lib.rs

1#![no_std]
2#![allow(unsafe_op_in_unsafe_fn, non_snake_case)]
3#![warn(clippy::pedantic)]
4#![allow(clippy::missing_safety_doc,
5         clippy::cast_sign_loss,
6         clippy::similar_names,
7         clippy::cast_possible_truncation,
8         clippy::cast_possible_wrap,
9         clippy::cast_ptr_alignment,
10         clippy::used_underscore_items,
11         clippy::unnecessary_cast)]
12
13mod uring;
14
15use core::{
16    ffi::{c_char, c_int, c_longlong, c_uint, c_ulong, c_ushort, c_void},
17    mem::{self, zeroed},
18    ptr,
19    sync::atomic::{
20        AtomicU16, AtomicU32,
21        Ordering::{self, Acquire, Relaxed, Release},
22    },
23    time::Duration,
24};
25
26pub use uring::*;
27
28const LIBURING_UDATA_TIMEOUT: u64 = u64::MAX;
29
30trait Atomic: Copy
31{
32    unsafe fn store(p: *mut Self, val: Self, order: Ordering);
33    unsafe fn load(p: *mut Self, order: Ordering) -> Self;
34}
35
36impl Atomic for u32
37{
38    #[inline]
39    unsafe fn store(p: *mut u32, val: u32, order: Ordering)
40    {
41        AtomicU32::from_ptr(p).store(val, order);
42    }
43
44    #[inline]
45    unsafe fn load(p: *mut u32, order: Ordering) -> u32
46    {
47        AtomicU32::from_ptr(p).load(order)
48    }
49}
50
51impl Atomic for u16
52{
53    #[inline]
54    unsafe fn store(p: *mut u16, val: u16, order: Ordering)
55    {
56        AtomicU16::from_ptr(p).store(val, order);
57    }
58
59    #[inline]
60    unsafe fn load(p: *mut u16, order: Ordering) -> u16
61    {
62        AtomicU16::from_ptr(p).load(order)
63    }
64}
65
66unsafe fn io_uring_smp_store_release<T: Atomic>(p: *mut T, v: T)
67{
68    Atomic::store(p, v, Release);
69}
70
71unsafe fn io_uring_smp_load_acquire<T: Atomic>(p: *const T) -> T
72{
73    Atomic::load(p.cast_mut(), Acquire)
74}
75
76unsafe fn IO_URING_READ_ONCE<T: Atomic>(var: *const T) -> T
77{
78    Atomic::load(var.cast_mut(), Relaxed)
79}
80
81unsafe fn IO_URING_WRITE_ONCE<T: Atomic>(var: *mut T, val: T)
82{
83    Atomic::store(var, val, Relaxed);
84}
85
86/*
87 * Library interface
88 */
89
90#[must_use]
91#[inline]
92unsafe fn uring_ptr_to_u64(ptr: *const c_void) -> u64
93{
94    ptr as u64
95}
96
97#[inline]
98pub unsafe fn io_uring_opcode_supported(p: *mut io_uring_probe, op: c_int) -> c_int
99{
100    if op < 0 || op > (*p).last_op.into() {
101        return 0;
102    }
103
104    i32::from((*(*p).ops.as_ptr().add(op as _)).flags & IO_URING_OP_SUPPORTED as u16 != 0)
105}
106
107/*
108 * Returns the bit shift needed to index the CQ.
109 * This shift is 1 for rings with big CQEs, and 0 for rings with normal CQEs.
110 * CQE `index` can be computed as &cq.cqes[(index & cq.ring_mask) << cqe_shift].
111 */
112#[must_use]
113#[inline]
114pub fn io_uring_cqe_shift_from_flags(flags: c_uint) -> c_uint
115{
116    u32::from(flags & IORING_SETUP_CQE32 != 0)
117}
118
119#[must_use]
120#[inline]
121pub unsafe fn io_uring_cqe_shift(ring: *const io_uring) -> c_uint
122{
123    io_uring_cqe_shift_from_flags((*ring).flags)
124}
125
126#[must_use]
127#[inline]
128pub unsafe fn io_uring_cqe_nr(cqe: *const io_uring_cqe) -> c_uint
129{
130    let shift = i32::from((*cqe).flags & IORING_CQE_F_32 != 0);
131    1 << shift
132}
133
134#[must_use]
135#[inline]
136pub unsafe fn io_uring_cqe_iter_init(ring: *const io_uring) -> io_uring_cqe_iter
137{
138    io_uring_cqe_iter { cqes: (*ring).cq.cqes,
139                        mask: (*ring).cq.ring_mask,
140                        shift: io_uring_cqe_shift(ring),
141                        head: *(*ring).cq.khead,
142                        /* Acquire ordering ensures tail is loaded before any CQEs */
143                        tail: io_uring_smp_load_acquire((*ring).cq.ktail) }
144}
145
146#[inline]
147pub unsafe fn io_uring_cqe_iter_next(iter: *mut io_uring_cqe_iter, cqe: *mut *mut io_uring_cqe)
148                                     -> bool
149{
150    if (*iter).head == (*iter).tail {
151        return false;
152    }
153
154    let head = (*iter).head;
155    (*iter).head += 1;
156
157    let offset = (head & (*iter).mask) << (*iter).shift;
158    *cqe = (*iter).cqes.add(offset as usize);
159
160    if (*(*cqe)).flags & IORING_CQE_F_32 > 0 {
161        (*iter).head += 1;
162    }
163
164    true
165}
166
167pub unsafe fn io_uring_for_each_cqe<F>(ring: *mut io_uring, mut f: F)
168    where F: FnMut(*mut io_uring_cqe)
169{
170    let mut iter = io_uring_cqe_iter_init(ring);
171    let mut cqe = ptr::null_mut::<io_uring_cqe>();
172    while io_uring_cqe_iter_next(&raw mut iter, &raw mut cqe) {
173        f(cqe);
174    }
175}
176
177/*
178 * Must be called after io_uring_for_each_cqe()
179 */
180#[inline]
181pub unsafe fn io_uring_cq_advance(ring: *mut io_uring, nr: c_uint)
182{
183    if nr > 0 {
184        let cq = &raw mut (*ring).cq;
185
186        /*
187         * Ensure that the kernel only sees the new value of the head
188         * index after the CQEs have been read.
189         */
190        io_uring_smp_store_release((*cq).khead, *(*cq).khead + nr);
191    }
192}
193
194/*
195 * Must be called after io_uring_{peek,wait}_cqe() after the cqe has
196 * been processed by the application.
197 */
198#[inline]
199pub unsafe fn io_uring_cqe_seen(ring: *mut io_uring, cqe: *mut io_uring_cqe)
200{
201    if !cqe.is_null() {
202        io_uring_cq_advance(ring, io_uring_cqe_nr(cqe));
203    }
204}
205
206/*
207 * Command prep helpers
208 */
209
210/*
211 * Associate pointer @data with the sqe, for later retrieval from the cqe
212 * at command completion time with io_uring_cqe_get_data().
213 */
214#[inline]
215pub unsafe fn io_uring_sqe_set_data(sqe: *mut io_uring_sqe, data: *mut c_void)
216{
217    (*sqe).user_data = data as u64;
218}
219
220#[must_use]
221#[inline]
222pub unsafe fn io_uring_cqe_get_data(cqe: *const io_uring_cqe) -> *mut c_void
223{
224    (*cqe).user_data as *mut c_void
225}
226
227/*
228 * Assign a 64-bit value to this sqe, which can get retrieved at completion
229 * time with io_uring_cqe_get_data64. Just like the non-64 variants, except
230 * these store a 64-bit type rather than a data pointer.
231 */
232#[inline]
233pub unsafe fn io_uring_sqe_set_data64(sqe: *mut io_uring_sqe, data: u64)
234{
235    (*sqe).user_data = data;
236}
237
238#[must_use]
239#[inline]
240pub unsafe fn io_uring_cqe_get_data64(cqe: *const io_uring_cqe) -> u64
241{
242    (*cqe).user_data
243}
244
245#[inline]
246pub unsafe fn io_uring_sqe_set_flags(sqe: *mut io_uring_sqe, flags: c_uint)
247{
248    (*sqe).flags = flags as u8;
249}
250
251#[inline]
252pub unsafe fn io_uring_sqe_set_buf_group(sqe: *mut io_uring_sqe, bgid: c_int)
253{
254    (*sqe).__liburing_anon_4.buf_group = bgid as u16;
255}
256
257#[inline]
258unsafe fn __io_uring_set_target_fixed_file(sqe: *mut io_uring_sqe, file_index: c_uint)
259{
260    /* 0 means no fixed files, indexes should be encoded as "index + 1" */
261    (*sqe).__liburing_anon_5.file_index = file_index + 1;
262}
263
264#[inline]
265pub unsafe fn io_uring_initialize_sqe(sqe: *mut io_uring_sqe)
266{
267    (*sqe).flags = 0;
268    (*sqe).ioprio = 0;
269    (*sqe).__liburing_anon_3.rw_flags = 0;
270    (*sqe).__liburing_anon_4.buf_index = 0;
271    (*sqe).personality = 0;
272    (*sqe).__liburing_anon_5.file_index = 0;
273    (*sqe).__liburing_anon_6.__liburing_anon_1.as_mut().addr3 = 0;
274    (*sqe).__liburing_anon_6.__liburing_anon_1.as_mut().__pad2[0] = 0;
275}
276
277#[inline]
278pub unsafe fn io_uring_prep_rw(op: c_uint, sqe: *mut io_uring_sqe, fd: c_int, addr: *const c_void,
279                               len: c_uint, offset: __u64)
280{
281    (*sqe).opcode = op as u8;
282    (*sqe).fd = fd;
283    (*sqe).__liburing_anon_1.off = offset;
284    (*sqe).__liburing_anon_2.addr = addr as u64;
285    (*sqe).len = len;
286}
287
288/*
289 * io_uring_prep_splice() - Either @fd_in or @fd_out must be a pipe.
290 *
291 * - If @fd_in refers to a pipe, @off_in is ignored and must be set to -1.
292 *
293 * - If @fd_in does not refer to a pipe and @off_in is -1, then @nbytes are read
294 *   from @fd_in starting from the file offset, which is incremented by the
295 *   number of bytes read.
296 *
297 * - If @fd_in does not refer to a pipe and @off_in is not -1, then the starting
298 *   offset of @fd_in will be @off_in.
299 *
300 * This splice operation can be used to implement sendfile by splicing to an
301 * intermediate pipe first, then splice to the final destination.
302 * In fact, the implementation of sendfile in kernel uses splice internally.
303 *
304 * NOTE that even if fd_in or fd_out refers to a pipe, the splice operation
305 * can still fail with EINVAL if one of the fd doesn't explicitly support splice
306 * operation, e.g. reading from terminal is unsupported from kernel 5.7 to 5.11.
307 * Check issue #291 for more information.
308 */
309#[inline]
310pub unsafe fn io_uring_prep_splice(sqe: *mut io_uring_sqe, fd_in: c_int, off_in: i64,
311                                   fd_out: c_int, off_out: i64, nbytes: c_uint,
312                                   splice_flags: c_uint)
313{
314    io_uring_prep_rw(IORING_OP_SPLICE, sqe, fd_out, ptr::null_mut(), nbytes, off_out as u64);
315    (*sqe).__liburing_anon_2.splice_off_in = off_in as u64;
316    (*sqe).__liburing_anon_5.splice_fd_in = fd_in;
317    (*sqe).__liburing_anon_3.splice_flags = splice_flags;
318}
319
320#[inline]
321pub unsafe fn io_uring_prep_tee(sqe: *mut io_uring_sqe, fd_in: c_int, fd_out: c_int,
322                                nbytes: c_uint, splice_flags: c_uint)
323{
324    io_uring_prep_rw(IORING_OP_TEE, sqe, fd_out, ptr::null_mut(), nbytes, 0);
325    (*sqe).__liburing_anon_2.splice_off_in = 0;
326    (*sqe).__liburing_anon_5.splice_fd_in = fd_in;
327    (*sqe).__liburing_anon_3.splice_flags = splice_flags;
328}
329
330#[inline]
331pub unsafe fn io_uring_prep_readv(sqe: *mut io_uring_sqe, fd: c_int, iovecs: *const iovec,
332                                  nr_vecs: c_uint, offset: u64)
333{
334    io_uring_prep_rw(IORING_OP_READV, sqe, fd, iovecs.cast(), nr_vecs, offset);
335}
336
337#[inline]
338pub unsafe fn io_uring_prep_readv2(sqe: *mut io_uring_sqe, fd: c_int, iovecs: *const iovec,
339                                   nr_vecs: c_uint, offset: u64, flags: c_int)
340{
341    io_uring_prep_readv(sqe, fd, iovecs, nr_vecs, offset);
342    (*sqe).__liburing_anon_3.rw_flags = flags;
343}
344
345#[inline]
346pub unsafe fn io_uring_prep_read_fixed(sqe: *mut io_uring_sqe, fd: c_int, buf: *mut c_void,
347                                       nbytes: c_uint, offset: u64, buf_index: c_int)
348{
349    io_uring_prep_rw(IORING_OP_READ_FIXED, sqe, fd, buf, nbytes, offset);
350    (*sqe).__liburing_anon_4.buf_index = buf_index as u16;
351}
352
353#[inline]
354pub unsafe fn io_uring_prep_readv_fixed(sqe: *mut io_uring_sqe, fd: c_int, iovecs: *const iovec,
355                                        nr_vecs: c_uint, offset: u64, flags: c_int,
356                                        buf_index: c_int)
357{
358    io_uring_prep_readv2(sqe, fd, iovecs, nr_vecs, offset, flags);
359    (*sqe).opcode = IORING_OP_READV_FIXED as _;
360    (*sqe).__liburing_anon_4.buf_index = buf_index as u16;
361}
362
363#[inline]
364pub unsafe fn io_uring_prep_writev(sqe: *mut io_uring_sqe, fd: c_int, iovecs: *const iovec,
365                                   nr_vecs: c_uint, offset: u64)
366{
367    io_uring_prep_rw(IORING_OP_WRITEV, sqe, fd, iovecs.cast(), nr_vecs, offset);
368}
369
370#[inline]
371pub unsafe fn io_uring_prep_writev2(sqe: *mut io_uring_sqe, fd: c_int, iovecs: *const iovec,
372                                    nr_vecs: c_uint, offset: u64, flags: c_int)
373{
374    io_uring_prep_writev(sqe, fd, iovecs, nr_vecs, offset);
375    (*sqe).__liburing_anon_3.rw_flags = flags;
376}
377
378#[inline]
379pub unsafe fn io_uring_prep_write_fixed(sqe: *mut io_uring_sqe, fd: c_int, buf: *const c_void,
380                                        nbytes: c_uint, offset: u64, buf_index: c_int)
381{
382    io_uring_prep_rw(IORING_OP_WRITE_FIXED, sqe, fd, buf, nbytes, offset);
383    (*sqe).__liburing_anon_4.buf_index = buf_index as u16;
384}
385
386#[inline]
387pub unsafe fn io_uring_prep_writev_fixed(sqe: *mut io_uring_sqe, fd: c_int, iovecs: *const iovec,
388                                         nr_vecs: c_uint, offset: u64, flags: c_int,
389                                         buf_index: c_int)
390{
391    io_uring_prep_writev2(sqe, fd, iovecs, nr_vecs, offset, flags);
392    (*sqe).opcode = IORING_OP_WRITEV_FIXED as _;
393    (*sqe).__liburing_anon_4.buf_index = buf_index as u16;
394}
395
396#[inline]
397pub unsafe fn io_uring_prep_recvmsg(sqe: *mut io_uring_sqe, fd: c_int, msg: *mut msghdr,
398                                    flags: c_uint)
399{
400    io_uring_prep_rw(IORING_OP_RECVMSG, sqe, fd, msg.cast(), 1, 0);
401    (*sqe).__liburing_anon_3.msg_flags = flags;
402}
403
404#[inline]
405pub unsafe fn io_uring_prep_recvmsg_multishot(sqe: *mut io_uring_sqe, fd: c_int, msg: *mut msghdr,
406                                              flags: c_uint)
407{
408    io_uring_prep_recvmsg(sqe, fd, msg, flags);
409    (*sqe).ioprio |= IORING_RECV_MULTISHOT as u16;
410}
411
412#[inline]
413pub unsafe fn io_uring_prep_sendmsg(sqe: *mut io_uring_sqe, fd: c_int, msg: *const msghdr,
414                                    flags: c_uint)
415{
416    io_uring_prep_rw(IORING_OP_SENDMSG, sqe, fd, msg.cast(), 1, 0);
417    (*sqe).__liburing_anon_3.msg_flags = flags;
418}
419
420#[must_use]
421#[inline]
422pub fn __io_uring_prep_poll_mask(poll_mask: c_uint) -> c_uint
423{
424    poll_mask.to_le()
425}
426
427#[inline]
428pub unsafe fn io_uring_prep_poll_add(sqe: *mut io_uring_sqe, fd: c_int, poll_mask: c_uint)
429{
430    io_uring_prep_rw(IORING_OP_POLL_ADD, sqe, fd, ptr::null_mut(), 0, 0);
431    (*sqe).__liburing_anon_3.poll32_events = __io_uring_prep_poll_mask(poll_mask);
432}
433
434#[inline]
435pub unsafe fn io_uring_prep_poll_multishot(sqe: *mut io_uring_sqe, fd: c_int, poll_mask: c_uint)
436{
437    io_uring_prep_poll_add(sqe, fd, poll_mask);
438    (*sqe).len = IORING_POLL_ADD_MULTI;
439}
440
441#[inline]
442pub unsafe fn io_uring_prep_poll_remove(sqe: *mut io_uring_sqe, user_data: u64)
443{
444    io_uring_prep_rw(IORING_OP_POLL_REMOVE, sqe, -1, ptr::null_mut(), 0, 0);
445    (*sqe).__liburing_anon_2.addr = user_data;
446}
447
448#[inline]
449pub unsafe fn io_uring_prep_poll_update(sqe: *mut io_uring_sqe, old_user_data: u64,
450                                        new_user_data: u64, poll_mask: c_uint, flags: c_uint)
451{
452    io_uring_prep_rw(IORING_OP_POLL_REMOVE, sqe, -1, ptr::null_mut(), flags, new_user_data);
453    (*sqe).__liburing_anon_2.addr = old_user_data;
454    (*sqe).__liburing_anon_3.poll32_events = __io_uring_prep_poll_mask(poll_mask);
455}
456
457#[inline]
458pub unsafe fn io_uring_prep_fsync(sqe: *mut io_uring_sqe, fd: c_int, fsync_flags: c_uint)
459{
460    io_uring_prep_rw(IORING_OP_FSYNC, sqe, fd, ptr::null_mut(), 0, 0);
461    (*sqe).__liburing_anon_3.fsync_flags = fsync_flags;
462}
463
464#[inline]
465pub unsafe fn io_uring_prep_nop(sqe: *mut io_uring_sqe)
466{
467    io_uring_prep_rw(IORING_OP_NOP, sqe, -1, ptr::null_mut(), 0, 0);
468}
469
470#[inline]
471pub unsafe fn io_uring_prep_nop128(sqe: *mut io_uring_sqe)
472{
473    io_uring_prep_rw(IORING_OP_NOP128, sqe, -1, ptr::null_mut(), 0, 0);
474}
475
476#[inline]
477pub unsafe fn io_uring_prep_timeout(sqe: *mut io_uring_sqe, ts: *const __kernel_timespec,
478                                    count: c_uint, flags: c_uint)
479{
480    io_uring_prep_rw(IORING_OP_TIMEOUT, sqe, -1, ts.cast(), 1, count.into());
481    (*sqe).__liburing_anon_3.timeout_flags = flags;
482}
483
484#[inline]
485pub unsafe fn io_uring_prep_timeout_remove(sqe: *mut io_uring_sqe, user_data: __u64, flags: c_uint)
486{
487    io_uring_prep_rw(IORING_OP_TIMEOUT_REMOVE, sqe, -1, ptr::null_mut(), 0, 0);
488    (*sqe).__liburing_anon_2.addr = user_data;
489    (*sqe).__liburing_anon_3.timeout_flags = flags;
490}
491
492#[inline]
493pub unsafe fn io_uring_prep_timeout_update(sqe: *mut io_uring_sqe, ts: *const __kernel_timespec,
494                                           user_data: __u64, flags: c_uint)
495{
496    io_uring_prep_rw(IORING_OP_TIMEOUT_REMOVE, sqe, -1, ptr::null_mut(), 0, ts as u64);
497    (*sqe).__liburing_anon_2.addr = user_data;
498    (*sqe).__liburing_anon_3.timeout_flags = flags | IORING_TIMEOUT_UPDATE;
499}
500
501#[inline]
502pub unsafe fn io_uring_prep_accept(sqe: *mut io_uring_sqe, fd: c_int, addr: *mut sockaddr,
503                                   addrlen: *mut socklen_t, flags: c_int)
504{
505    io_uring_prep_rw(IORING_OP_ACCEPT, sqe, fd, addr.cast(), 0, uring_ptr_to_u64(addrlen.cast()));
506    (*sqe).__liburing_anon_3.accept_flags = flags as u32;
507}
508
509/* accept directly into the fixed file table */
510#[inline]
511pub unsafe fn io_uring_prep_accept_direct(sqe: *mut io_uring_sqe, fd: c_int, addr: *mut sockaddr,
512                                          addrlen: *mut socklen_t, flags: c_int,
513                                          mut file_index: c_uint)
514{
515    io_uring_prep_accept(sqe, fd, addr, addrlen, flags);
516    /* offset by 1 for allocation */
517    if file_index == IORING_FILE_INDEX_ALLOC as _ {
518        file_index -= 1;
519    }
520    __io_uring_set_target_fixed_file(sqe, file_index);
521}
522
523#[inline]
524pub unsafe fn io_uring_prep_multishot_accept(sqe: *mut io_uring_sqe, fd: c_int,
525                                             addr: *mut sockaddr, addrlen: *mut socklen_t,
526                                             flags: c_int)
527{
528    io_uring_prep_accept(sqe, fd, addr, addrlen, flags);
529    (*sqe).ioprio |= IORING_ACCEPT_MULTISHOT as u16;
530}
531
532/* multishot accept directly into the fixed file table */
533#[inline]
534pub unsafe fn io_uring_prep_multishot_accept_direct(sqe: *mut io_uring_sqe, fd: c_int,
535                                                    addr: *mut sockaddr, addrlen: *mut socklen_t,
536                                                    flags: c_int)
537{
538    io_uring_prep_multishot_accept(sqe, fd, addr, addrlen, flags);
539    __io_uring_set_target_fixed_file(sqe, (IORING_FILE_INDEX_ALLOC - 1) as u32);
540}
541
542#[inline]
543pub unsafe fn io_uring_prep_cancel64(sqe: *mut io_uring_sqe, user_data: u64, flags: c_int)
544{
545    io_uring_prep_rw(IORING_OP_ASYNC_CANCEL, sqe, -1, ptr::null_mut(), 0, 0);
546    (*sqe).__liburing_anon_2.addr = user_data;
547    (*sqe).__liburing_anon_3.cancel_flags = flags as u32;
548}
549
550#[inline]
551pub unsafe fn io_uring_prep_cancel(sqe: *mut io_uring_sqe, user_data: *const c_void, flags: c_int)
552{
553    io_uring_prep_cancel64(sqe, user_data as usize as u64, flags);
554}
555
556#[inline]
557pub unsafe fn io_uring_prep_cancel_fd(sqe: *mut io_uring_sqe, fd: c_int, flags: c_uint)
558{
559    io_uring_prep_rw(IORING_OP_ASYNC_CANCEL, sqe, fd, ptr::null_mut(), 0, 0);
560    (*sqe).__liburing_anon_3.cancel_flags = flags | IORING_ASYNC_CANCEL_FD;
561}
562
563#[inline]
564pub unsafe fn io_uring_prep_link_timeout(sqe: *mut io_uring_sqe, ts: *const __kernel_timespec,
565                                         flags: c_uint)
566{
567    io_uring_prep_rw(IORING_OP_LINK_TIMEOUT, sqe, -1, ts.cast(), 1, 0);
568    (*sqe).__liburing_anon_3.timeout_flags = flags;
569}
570
571#[inline]
572pub unsafe fn io_uring_prep_connect(sqe: *mut io_uring_sqe, fd: c_int, addr: *const sockaddr,
573                                    addrlen: socklen_t)
574{
575    io_uring_prep_rw(IORING_OP_CONNECT, sqe, fd, addr.cast(), 0, addrlen.into());
576}
577
578#[inline]
579pub unsafe fn io_uring_prep_bind(sqe: *mut io_uring_sqe, fd: c_int, addr: *const sockaddr,
580                                 addrlen: socklen_t)
581{
582    io_uring_prep_rw(IORING_OP_BIND, sqe, fd, addr.cast(), 0, addrlen.into());
583}
584
585#[inline]
586pub unsafe fn io_uring_prep_listen(sqe: *mut io_uring_sqe, fd: c_int, backlog: c_int)
587{
588    io_uring_prep_rw(IORING_OP_LISTEN, sqe, fd, ptr::null_mut(), backlog as _, 0);
589}
590
591#[inline]
592pub unsafe fn io_uring_prep_epoll_wait(sqe: *mut io_uring_sqe, fd: c_int,
593                                       events: *mut epoll_event, maxevents: c_int, flags: c_uint)
594{
595    io_uring_prep_rw(IORING_OP_EPOLL_WAIT, sqe, fd, events.cast(), maxevents as _, 0);
596    (*sqe).__liburing_anon_3.rw_flags = flags as _;
597}
598
599#[inline]
600pub unsafe fn io_uring_prep_files_update(sqe: *mut io_uring_sqe, fds: *mut c_int, nr_fds: c_uint,
601                                         offset: c_int)
602{
603    io_uring_prep_rw(IORING_OP_FILES_UPDATE, sqe, -1, fds.cast(), nr_fds, offset as u64);
604}
605
606#[inline]
607pub unsafe fn io_uring_prep_fallocate(sqe: *mut io_uring_sqe, fd: c_int, mode: c_int, offset: u64,
608                                      len: u64)
609{
610    io_uring_prep_rw(IORING_OP_FALLOCATE, sqe, fd, ptr::null_mut(), mode as c_uint, offset);
611    (*sqe).__liburing_anon_2.addr = len;
612}
613
614#[inline]
615pub unsafe fn io_uring_prep_openat(sqe: *mut io_uring_sqe, dfd: c_int, path: *const c_char,
616                                   flags: c_int, mode: mode_t)
617{
618    io_uring_prep_rw(IORING_OP_OPENAT, sqe, dfd, path.cast(), mode, 0);
619    (*sqe).__liburing_anon_3.open_flags = flags as u32;
620}
621
622/* open directly into the fixed file table */
623#[inline]
624pub unsafe fn io_uring_prep_openat_direct(sqe: *mut io_uring_sqe, dfd: c_int, path: *const c_char,
625                                          flags: c_int, mode: mode_t, mut file_index: c_uint)
626{
627    io_uring_prep_openat(sqe, dfd, path, flags, mode);
628    /* offset by 1 for allocation */
629    if file_index == IORING_FILE_INDEX_ALLOC as _ {
630        file_index -= 1;
631    }
632    __io_uring_set_target_fixed_file(sqe, file_index);
633}
634
635#[inline]
636pub unsafe fn io_uring_prep_open(sqe: *mut io_uring_sqe, path: *const c_char, flags: c_int,
637                                 mode: mode_t)
638{
639    io_uring_prep_openat(sqe, AT_FDCWD, path, flags, mode);
640}
641
642/* open directly into the fixed file table */
643#[inline]
644pub unsafe fn io_uring_prep_open_direct(sqe: *mut io_uring_sqe, path: *const c_char, flags: c_int,
645                                        mode: mode_t, file_index: c_uint)
646{
647    io_uring_prep_openat_direct(sqe, AT_FDCWD, path, flags, mode, file_index);
648}
649
650#[inline]
651pub unsafe fn io_uring_prep_close(sqe: *mut io_uring_sqe, fd: c_int)
652{
653    io_uring_prep_rw(IORING_OP_CLOSE, sqe, fd, ptr::null_mut(), 0, 0);
654}
655
656#[inline]
657pub unsafe fn io_uring_prep_close_direct(sqe: *mut io_uring_sqe, file_index: c_uint)
658{
659    io_uring_prep_close(sqe, 0);
660    __io_uring_set_target_fixed_file(sqe, file_index);
661}
662
663#[inline]
664pub unsafe fn io_uring_prep_read(sqe: *mut io_uring_sqe, fd: c_int, buf: *mut c_void,
665                                 nbytes: c_uint, offset: u64)
666{
667    io_uring_prep_rw(IORING_OP_READ, sqe, fd, buf, nbytes, offset);
668}
669
670#[inline]
671pub unsafe fn io_uring_prep_read_multishot(sqe: *mut io_uring_sqe, fd: c_int, nbytes: c_uint,
672                                           offset: u64, buf_group: c_int)
673{
674    io_uring_prep_rw(IORING_OP_READ_MULTISHOT, sqe, fd, ptr::null_mut(), nbytes, offset);
675    (*sqe).__liburing_anon_4.buf_group = buf_group as _;
676    (*sqe).flags = IOSQE_BUFFER_SELECT as _;
677}
678
679#[inline]
680pub unsafe fn io_uring_prep_write(sqe: *mut io_uring_sqe, fd: c_int, buf: *const c_void,
681                                  nbytes: c_uint, offset: u64)
682{
683    io_uring_prep_rw(IORING_OP_WRITE, sqe, fd, buf, nbytes, offset);
684}
685
686#[inline]
687pub unsafe fn io_uring_prep_statx(sqe: *mut io_uring_sqe, dfd: c_int, path: *const c_char,
688                                  flags: c_int, mask: c_uint, statxbuf: *mut statx)
689{
690    io_uring_prep_rw(IORING_OP_STATX,
691                     sqe,
692                     dfd,
693                     path.cast(),
694                     mask,
695                     uring_ptr_to_u64(statxbuf.cast()));
696    (*sqe).__liburing_anon_3.statx_flags = flags as u32;
697}
698
699#[inline]
700pub unsafe fn io_uring_prep_fadvise(sqe: *mut io_uring_sqe, fd: c_int, offset: u64, len: u32,
701                                    advice: c_int)
702{
703    io_uring_prep_rw(IORING_OP_FADVISE, sqe, fd, ptr::null_mut(), len, offset);
704    (*sqe).__liburing_anon_3.fadvise_advice = advice as u32;
705}
706
707#[inline]
708pub unsafe fn io_uring_prep_madvise(sqe: *mut io_uring_sqe, addr: *mut c_void, length: u32,
709                                    advice: c_int)
710{
711    io_uring_prep_rw(IORING_OP_MADVISE, sqe, -1, addr, length, 0);
712    (*sqe).__liburing_anon_3.fadvise_advice = advice as u32;
713}
714
715#[inline]
716pub unsafe fn io_uring_prep_fadvise64(sqe: *mut io_uring_sqe, fd: c_int, offset: u64, len: off_t,
717                                      advice: c_int)
718{
719    io_uring_prep_rw(IORING_OP_FADVISE, sqe, fd, ptr::null_mut(), 0, offset);
720    (*sqe).__liburing_anon_2.addr = len as _;
721    (*sqe).__liburing_anon_3.fadvise_advice = advice as u32;
722}
723
724#[inline]
725pub unsafe fn io_uring_prep_madvise64(sqe: *mut io_uring_sqe, addr: *mut c_void, length: off_t,
726                                      advice: c_int)
727{
728    io_uring_prep_rw(IORING_OP_MADVISE, sqe, -1, addr, 0, length as _);
729    (*sqe).__liburing_anon_3.fadvise_advice = advice as u32;
730}
731
732#[inline]
733pub unsafe fn io_uring_prep_send(sqe: *mut io_uring_sqe, sockfd: c_int, buf: *const c_void,
734                                 len: usize, flags: c_int)
735{
736    io_uring_prep_rw(IORING_OP_SEND, sqe, sockfd, buf, len as u32, 0);
737    (*sqe).__liburing_anon_3.msg_flags = flags as u32;
738}
739
740#[inline]
741pub unsafe fn io_uring_prep_send_bundle(sqe: *mut io_uring_sqe, sockfd: c_int, len: usize,
742                                        flags: c_int)
743{
744    io_uring_prep_send(sqe, sockfd, ptr::null_mut(), len, flags);
745    (*sqe).ioprio |= IORING_RECVSEND_BUNDLE as u16;
746}
747
748#[inline]
749pub unsafe fn io_uring_prep_send_set_addr(sqe: *mut io_uring_sqe, dest_addr: *const sockaddr,
750                                          addr_len: u16)
751{
752    (*sqe).__liburing_anon_1.addr2 = dest_addr as usize as u64;
753    (*sqe).__liburing_anon_5.__liburing_anon_1.addr_len = addr_len;
754}
755
756#[inline]
757pub unsafe fn io_uring_prep_sendto(sqe: *mut io_uring_sqe, sockfd: c_int, buf: *const c_void,
758                                   len: usize, flags: c_int, addr: *const sockaddr,
759                                   addrlen: socklen_t)
760{
761    io_uring_prep_send(sqe, sockfd, buf, len, flags);
762    io_uring_prep_send_set_addr(sqe, addr, addrlen as _);
763}
764
765#[inline]
766pub unsafe fn io_uring_prep_send_zc(sqe: *mut io_uring_sqe, sockfd: c_int, buf: *const c_void,
767                                    len: usize, flags: c_int, zc_flags: c_uint)
768{
769    io_uring_prep_rw(IORING_OP_SEND_ZC, sqe, sockfd, buf, len as u32, 0);
770    (*sqe).__liburing_anon_3.msg_flags = flags as u32;
771    (*sqe).ioprio = zc_flags as _;
772}
773
774#[inline]
775pub unsafe fn io_uring_prep_send_zc_fixed(sqe: *mut io_uring_sqe, sockfd: c_int,
776                                          buf: *const c_void, len: usize, flags: c_int,
777                                          zc_flags: c_uint, buf_index: c_uint)
778{
779    io_uring_prep_send_zc(sqe, sockfd, buf, len, flags, zc_flags);
780    (*sqe).ioprio |= IORING_RECVSEND_FIXED_BUF as u16;
781    (*sqe).__liburing_anon_4.buf_index = buf_index as _;
782}
783
784#[inline]
785pub unsafe fn io_uring_prep_sendmsg_zc(sqe: *mut io_uring_sqe, fd: c_int, msg: *const msghdr,
786                                       flags: c_uint)
787{
788    io_uring_prep_sendmsg(sqe, fd, msg, flags);
789    (*sqe).opcode = IORING_OP_SENDMSG_ZC as _;
790}
791
792#[inline]
793pub unsafe fn io_uring_prep_sendmsg_zc_fixed(sqe: *mut io_uring_sqe, fd: c_int,
794                                             msg: *const msghdr, flags: c_uint, buf_index: c_uint)
795{
796    io_uring_prep_sendmsg_zc(sqe, fd, msg, flags);
797    (*sqe).ioprio |= IORING_RECVSEND_FIXED_BUF as u16;
798    (*sqe).__liburing_anon_4.buf_index = buf_index as _;
799}
800
801#[inline]
802pub unsafe fn io_uring_prep_recv(sqe: *mut io_uring_sqe, sockfd: c_int, buf: *mut c_void,
803                                 len: usize, flags: c_int)
804{
805    io_uring_prep_rw(IORING_OP_RECV, sqe, sockfd, buf, len as u32, 0);
806    (*sqe).__liburing_anon_3.msg_flags = flags as u32;
807}
808
809#[inline]
810pub unsafe fn io_uring_prep_recv_multishot(sqe: *mut io_uring_sqe, sockfd: c_int,
811                                           buf: *mut c_void, len: usize, flags: c_int)
812{
813    io_uring_prep_recv(sqe, sockfd, buf, len, flags);
814    (*sqe).ioprio |= IORING_RECV_MULTISHOT as u16;
815}
816
817#[inline]
818pub unsafe fn io_uring_recvmsg_validate(buf: *mut c_void, buf_len: c_int, msgh: *mut msghdr)
819                                        -> *mut io_uring_recvmsg_out
820{
821    let ulen = c_ulong::from(buf_len as c_uint);
822    let hdr = size_of::<io_uring_recvmsg_out>() as c_ulong;
823    let namelen = c_ulong::from((*msgh).msg_namelen);
824    let controllen = (*msgh).msg_controllen as c_ulong;
825
826    if buf_len < 0 || ulen < hdr {
827        return ptr::null_mut();
828    }
829    /* check each addition separately to avoid integer overflow */
830    if namelen > ulen - hdr {
831        return ptr::null_mut();
832    }
833    if controllen > ulen - hdr - namelen {
834        return ptr::null_mut();
835    }
836
837    buf.cast()
838}
839
840#[inline]
841pub unsafe fn io_uring_recvmsg_name(o: *mut io_uring_recvmsg_out) -> *mut c_void
842{
843    o.add(1).cast()
844}
845
846#[inline]
847pub unsafe fn io_uring_recvmsg_cmsg_firsthdr(o: *mut io_uring_recvmsg_out, msgh: *mut msghdr)
848                                             -> *mut cmsghdr
849{
850    if ((*o).controllen as usize) < mem::size_of::<cmsghdr>() {
851        return ptr::null_mut();
852    }
853
854    io_uring_recvmsg_name(o).cast::<u8>()
855                            .add((*msgh).msg_namelen as _)
856                            .cast()
857}
858
859#[inline]
860pub unsafe fn io_uring_recvmsg_cmsg_nexthdr(o: *mut io_uring_recvmsg_out, msgh: *mut msghdr,
861                                            cmsg: *mut cmsghdr)
862                                            -> *mut cmsghdr
863{
864    #[allow(non_snake_case)]
865    fn CMSG_ALIGN(len: usize) -> usize
866    {
867        ((len) + mem::size_of::<usize>() - 1) & !(mem::size_of::<usize>() - 1)
868    }
869
870    if ((*cmsg).cmsg_len as usize) < mem::size_of::<cmsghdr>() {
871        return ptr::null_mut();
872    }
873
874    let end = io_uring_recvmsg_cmsg_firsthdr(o, msgh).cast::<u8>()
875                                                     .add((*o).controllen as _);
876
877    let cmsg = cmsg.cast::<u8>()
878                   .add(CMSG_ALIGN((*cmsg).cmsg_len as usize))
879                   .cast::<cmsghdr>();
880
881    if cmsg.add(1).cast::<u8>() > end {
882        return ptr::null_mut();
883    }
884
885    if cmsg.cast::<u8>().add(CMSG_ALIGN((*cmsg).cmsg_len as usize)) > end {
886        return ptr::null_mut();
887    }
888
889    cmsg
890}
891
892#[inline]
893pub unsafe fn io_uring_recvmsg_payload(o: *mut io_uring_recvmsg_out, msgh: *mut msghdr)
894                                       -> *mut c_void
895{
896    io_uring_recvmsg_name(o).cast::<u8>()
897                            .add((*msgh).msg_namelen as usize + (*msgh).msg_controllen as usize)
898                            .cast::<c_void>()
899}
900
901#[inline]
902pub unsafe fn io_uring_recvmsg_payload_length(o: *mut io_uring_recvmsg_out, buf_len: c_int,
903                                              msgh: *mut msghdr)
904                                              -> c_uint
905{
906    if buf_len < 0 {
907        return 0;
908    }
909
910    let payload_start = io_uring_recvmsg_payload(o, msgh) as usize;
911    let payload_end = o as usize + buf_len as usize;
912    if payload_start >= payload_end {
913        return 0;
914    }
915
916    (payload_end - payload_start) as _
917}
918
919#[inline]
920pub unsafe fn io_uring_prep_openat2(sqe: *mut io_uring_sqe, dfd: c_int, path: *const c_char,
921                                    how: *const open_how)
922{
923    io_uring_prep_rw(IORING_OP_OPENAT2 as _,
924                     sqe,
925                     dfd,
926                     path.cast(),
927                     mem::size_of::<open_how>() as u32,
928                     how as usize as u64);
929}
930
931/* open directly into the fixed file table */
932#[inline]
933pub unsafe fn io_uring_prep_openat2_direct(sqe: *mut io_uring_sqe, dfd: c_int,
934                                           path: *const c_char, how: *const open_how,
935                                           mut file_index: c_uint)
936{
937    io_uring_prep_openat2(sqe, dfd, path, how);
938    /* offset by 1 for allocation */
939    if file_index == IORING_FILE_INDEX_ALLOC as _ {
940        file_index -= 1;
941    }
942    __io_uring_set_target_fixed_file(sqe, file_index);
943}
944
945#[inline]
946pub unsafe fn io_uring_prep_epoll_ctl(sqe: *mut io_uring_sqe, epfd: c_int, fd: c_int, op: c_int,
947                                      ev: *const epoll_event)
948{
949    io_uring_prep_rw(IORING_OP_EPOLL_CTL, sqe, epfd, ev.cast(), op as u32, u64::from(fd as u32));
950}
951
952#[inline]
953pub unsafe fn io_uring_prep_provide_buffers(sqe: *mut io_uring_sqe, addr: *mut c_void, len: c_int,
954                                            nr: c_int, bgid: c_int, bid: c_int)
955{
956    io_uring_prep_rw(IORING_OP_PROVIDE_BUFFERS, sqe, nr, addr, len as u32, bid as u64);
957    (*sqe).__liburing_anon_4.buf_group = bgid as u16;
958}
959
960#[inline]
961pub unsafe fn io_uring_prep_remove_buffers(sqe: *mut io_uring_sqe, nr: c_int, bgid: c_int)
962{
963    io_uring_prep_rw(IORING_OP_REMOVE_BUFFERS, sqe, nr, ptr::null_mut(), 0, 0);
964    (*sqe).__liburing_anon_4.buf_group = bgid as u16;
965}
966
967#[inline]
968pub unsafe fn io_uring_prep_shutdown(sqe: *mut io_uring_sqe, fd: c_int, how: c_int)
969{
970    io_uring_prep_rw(IORING_OP_SHUTDOWN, sqe, fd, ptr::null_mut(), how as u32, 0);
971}
972
973#[inline]
974pub unsafe fn io_uring_prep_unlinkat(sqe: *mut io_uring_sqe, dfd: c_int, path: *const c_char,
975                                     flags: c_int)
976{
977    io_uring_prep_rw(IORING_OP_UNLINKAT, sqe, dfd, path.cast(), 0, 0);
978    (*sqe).__liburing_anon_3.unlink_flags = flags as u32;
979}
980
981#[inline]
982pub unsafe fn io_uring_prep_unlink(sqe: *mut io_uring_sqe, path: *const c_char, flags: c_int)
983{
984    io_uring_prep_unlinkat(sqe, AT_FDCWD, path, flags);
985}
986
987#[inline]
988pub unsafe fn io_uring_prep_renameat(sqe: *mut io_uring_sqe, olddfd: c_int,
989                                     oldpath: *const c_char, newdfd: c_int,
990                                     newpath: *const c_char, flags: c_uint)
991{
992    io_uring_prep_rw(IORING_OP_RENAMEAT,
993                     sqe,
994                     olddfd,
995                     oldpath.cast(),
996                     newdfd as u32,
997                     newpath as usize as u64);
998    (*sqe).__liburing_anon_3.rename_flags = flags;
999}
1000
1001#[inline]
1002pub unsafe fn io_uring_prep_rename(sqe: *mut io_uring_sqe, oldpath: *const c_char,
1003                                   newpath: *const c_char)
1004{
1005    io_uring_prep_renameat(sqe, AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
1006}
1007
1008#[inline]
1009pub unsafe fn io_uring_prep_sync_file_range(sqe: *mut io_uring_sqe, fd: c_int, len: c_uint,
1010                                            offset: u64, flags: c_int)
1011{
1012    io_uring_prep_rw(IORING_OP_SYNC_FILE_RANGE, sqe, fd, ptr::null_mut(), len, offset);
1013    (*sqe).__liburing_anon_3.sync_range_flags = flags as u32;
1014}
1015
1016#[inline]
1017pub unsafe fn io_uring_prep_mkdirat(sqe: *mut io_uring_sqe, dfd: c_int, path: *const c_char,
1018                                    mode: mode_t)
1019{
1020    io_uring_prep_rw(IORING_OP_MKDIRAT, sqe, dfd, path.cast(), mode, 0);
1021}
1022
1023#[inline]
1024pub unsafe fn io_uring_prep_mkdir(sqe: *mut io_uring_sqe, path: *const c_char, mode: mode_t)
1025{
1026    io_uring_prep_mkdirat(sqe, AT_FDCWD, path, mode);
1027}
1028
1029#[inline]
1030pub unsafe fn io_uring_prep_symlinkat(sqe: *mut io_uring_sqe, target: *const c_char,
1031                                      newdirfd: c_int, linkpath: *const c_char)
1032{
1033    io_uring_prep_rw(IORING_OP_SYMLINKAT,
1034                     sqe,
1035                     newdirfd,
1036                     target.cast(),
1037                     0,
1038                     linkpath as usize as u64);
1039}
1040#[inline]
1041pub unsafe fn io_uring_prep_symlink(sqe: *mut io_uring_sqe, target: *const c_char,
1042                                    linkpath: *const c_char)
1043{
1044    io_uring_prep_symlinkat(sqe, target, AT_FDCWD, linkpath);
1045}
1046
1047#[inline]
1048pub unsafe fn io_uring_prep_linkat(sqe: *mut io_uring_sqe, olddfd: c_int, oldpath: *const c_char,
1049                                   newdfd: c_int, newpath: *const c_char, flags: c_int)
1050{
1051    io_uring_prep_rw(IORING_OP_LINKAT,
1052                     sqe,
1053                     olddfd,
1054                     oldpath.cast(),
1055                     newdfd as u32,
1056                     newpath as usize as u64);
1057    (*sqe).__liburing_anon_3.hardlink_flags = flags as u32;
1058}
1059
1060#[inline]
1061pub unsafe fn io_uring_prep_link(sqe: *mut io_uring_sqe, oldpath: *const c_char,
1062                                 newpath: *const c_char, flags: c_int)
1063{
1064    io_uring_prep_linkat(sqe, AT_FDCWD, oldpath, AT_FDCWD, newpath, flags);
1065}
1066
1067#[inline]
1068pub unsafe fn io_uring_prep_msg_ring_cqe_flags(sqe: *mut io_uring_sqe, fd: c_int, len: c_uint,
1069                                               data: u64, flags: c_uint, cqe_flags: c_uint)
1070{
1071    io_uring_prep_rw(IORING_OP_MSG_RING, sqe, fd, ptr::null_mut(), len, data);
1072    (*sqe).__liburing_anon_3.msg_ring_flags = IORING_MSG_RING_FLAGS_PASS | flags;
1073    (*sqe).__liburing_anon_5.file_index = cqe_flags;
1074}
1075
1076#[inline]
1077pub unsafe fn io_uring_prep_msg_ring(sqe: *mut io_uring_sqe, fd: c_int, len: c_uint, data: u64,
1078                                     flags: c_uint)
1079{
1080    io_uring_prep_rw(IORING_OP_MSG_RING, sqe, fd, ptr::null_mut(), len, data);
1081    (*sqe).__liburing_anon_3.msg_ring_flags = IORING_MSG_RING_FLAGS_PASS | flags;
1082}
1083
1084#[inline]
1085pub unsafe fn io_uring_prep_msg_ring_fd(sqe: *mut io_uring_sqe, fd: c_int, source_fd: c_int,
1086                                        mut target_fd: c_int, data: u64, flags: c_uint)
1087{
1088    io_uring_prep_rw(IORING_OP_MSG_RING,
1089                     sqe,
1090                     fd,
1091                     IORING_MSG_SEND_FD as usize as *const c_void,
1092                     0,
1093                     data);
1094    (*sqe).__liburing_anon_6.__liburing_anon_1.as_mut().addr3 = source_fd as _;
1095    /* offset by 1 for allocation */
1096    if target_fd == IORING_FILE_INDEX_ALLOC as _ {
1097        target_fd -= 1;
1098    }
1099    __io_uring_set_target_fixed_file(sqe, target_fd as _);
1100    (*sqe).__liburing_anon_3.msg_ring_flags = flags;
1101}
1102
1103#[inline]
1104pub unsafe fn io_uring_prep_msg_ring_fd_alloc(sqe: *mut io_uring_sqe, fd: c_int, source_fd: c_int,
1105                                              data: u64, flags: c_uint)
1106{
1107    io_uring_prep_msg_ring_fd(sqe, fd, source_fd, IORING_FILE_INDEX_ALLOC, data, flags);
1108}
1109
1110#[inline]
1111pub unsafe fn io_uring_prep_getxattr(sqe: *mut io_uring_sqe, name: *const c_char,
1112                                     value: *mut c_char, path: *const c_char, len: c_uint)
1113{
1114    io_uring_prep_rw(IORING_OP_GETXATTR, sqe, 0, name.cast(), len, value as usize as u64);
1115    (*sqe).__liburing_anon_6.__liburing_anon_1.as_mut().addr3 = path as usize as u64;
1116
1117    (*sqe).__liburing_anon_3.xattr_flags = 0;
1118}
1119
1120#[inline]
1121pub unsafe fn io_uring_prep_setxattr(sqe: *mut io_uring_sqe, name: *const c_char,
1122                                     value: *const c_char, path: *const c_char, flags: c_int,
1123                                     len: c_uint)
1124{
1125    io_uring_prep_rw(IORING_OP_SETXATTR, sqe, 0, name.cast(), len, value as usize as u64);
1126    (*sqe).__liburing_anon_6.__liburing_anon_1.as_mut().addr3 = path as usize as u64;
1127    (*sqe).__liburing_anon_3.xattr_flags = flags as _;
1128}
1129
1130#[inline]
1131pub unsafe fn io_uring_prep_fgetxattr(sqe: *mut io_uring_sqe, fd: c_int, name: *const c_char,
1132                                      value: *mut c_char, len: c_uint)
1133{
1134    io_uring_prep_rw(IORING_OP_FGETXATTR, sqe, fd, name.cast(), len, value as usize as u64);
1135    (*sqe).__liburing_anon_3.xattr_flags = 0;
1136}
1137
1138#[inline]
1139pub unsafe fn io_uring_prep_fsetxattr(sqe: *mut io_uring_sqe, fd: c_int, name: *const c_char,
1140                                      value: *mut c_char, flags: c_int, len: c_uint)
1141{
1142    io_uring_prep_rw(IORING_OP_FSETXATTR, sqe, fd, name.cast(), len, value as usize as u64);
1143    (*sqe).__liburing_anon_3.xattr_flags = flags as _;
1144}
1145
1146#[inline]
1147pub unsafe fn io_uring_prep_socket(sqe: *mut io_uring_sqe, domain: c_int, r#type: c_int,
1148                                   protocol: c_int, flags: c_uint)
1149{
1150    io_uring_prep_rw(IORING_OP_SOCKET,
1151                     sqe,
1152                     domain,
1153                     ptr::null_mut(),
1154                     protocol as u32,
1155                     r#type as u64);
1156    (*sqe).__liburing_anon_3.rw_flags = flags as i32;
1157}
1158
1159#[inline]
1160pub unsafe fn io_uring_prep_socket_direct(sqe: *mut io_uring_sqe, domain: c_int, r#type: c_int,
1161                                          protocol: c_int, mut file_index: c_uint, flags: c_uint)
1162{
1163    io_uring_prep_rw(IORING_OP_SOCKET,
1164                     sqe,
1165                     domain,
1166                     ptr::null_mut(),
1167                     protocol as u32,
1168                     r#type as u64);
1169    (*sqe).__liburing_anon_3.rw_flags = flags as i32;
1170    /* offset by 1 for allocation */
1171    if file_index == IORING_FILE_INDEX_ALLOC as _ {
1172        file_index -= 1;
1173    }
1174    __io_uring_set_target_fixed_file(sqe, file_index);
1175}
1176
1177#[inline]
1178pub unsafe fn io_uring_prep_socket_direct_alloc(sqe: *mut io_uring_sqe, domain: c_int,
1179                                                r#type: c_int, protocol: c_int, flags: c_uint)
1180{
1181    io_uring_prep_rw(IORING_OP_SOCKET,
1182                     sqe,
1183                     domain,
1184                     ptr::null_mut(),
1185                     protocol as u32,
1186                     r#type as u64);
1187    (*sqe).__liburing_anon_3.rw_flags = flags as i32;
1188    __io_uring_set_target_fixed_file(sqe, (IORING_FILE_INDEX_ALLOC - 1) as _);
1189}
1190
1191#[inline]
1192pub unsafe fn __io_uring_prep_uring_cmd(sqe: *mut io_uring_sqe, op: c_int, cmd_op: u32, fd: c_int)
1193{
1194    (*sqe).opcode = op as _;
1195    (*sqe).fd = fd;
1196    (*sqe).__liburing_anon_1.__liburing_anon_1.cmd_op = cmd_op;
1197    (*sqe).__liburing_anon_1.__liburing_anon_1.__pad1 = 0;
1198    (*sqe).__liburing_anon_2.addr = 0;
1199    (*sqe).len = 0;
1200}
1201
1202#[inline]
1203pub unsafe fn io_uring_prep_uring_cmd(sqe: *mut io_uring_sqe, cmd_op: c_int, fd: c_int)
1204{
1205    __io_uring_prep_uring_cmd(sqe, IORING_OP_URING_CMD as _, cmd_op as _, fd);
1206}
1207
1208#[inline]
1209pub unsafe fn io_uring_prep_uring_cmd128(sqe: *mut io_uring_sqe, cmd_op: c_int, fd: c_int)
1210{
1211    __io_uring_prep_uring_cmd(sqe, IORING_OP_URING_CMD128 as _, cmd_op as _, fd);
1212}
1213
1214/*
1215 * Prepare commands for sockets
1216 */
1217#[inline]
1218pub unsafe fn io_uring_prep_cmd_sock(sqe: *mut io_uring_sqe, cmd_op: c_int, fd: c_int,
1219                                     level: c_int, optname: c_int, optval: *mut c_void,
1220                                     optlen: c_int)
1221{
1222    io_uring_prep_uring_cmd(sqe, cmd_op as _, fd);
1223
1224    *(*sqe).__liburing_anon_6.optval.as_mut() = optval as usize as _;
1225    (*sqe).__liburing_anon_2.__liburing_anon_1.optname = optname as _;
1226    (*sqe).__liburing_anon_5.optlen = optlen as _;
1227    (*sqe).__liburing_anon_1.__liburing_anon_1.cmd_op = cmd_op as _;
1228    (*sqe).__liburing_anon_2.__liburing_anon_1.level = level as _;
1229}
1230
1231#[inline]
1232pub unsafe fn io_uring_prep_cmd_getsockname(sqe: *mut io_uring_sqe, fd: c_int,
1233                                            sockaddr: *mut sockaddr, sockaddr_len: *mut socklen_t,
1234                                            peer: c_int)
1235{
1236    io_uring_prep_uring_cmd(sqe, SOCKET_URING_OP_GETSOCKNAME as _, fd);
1237
1238    (*sqe).__liburing_anon_2.addr = sockaddr as _;
1239    (*sqe).__liburing_anon_6.__liburing_anon_1.as_mut().addr3 = sockaddr_len as _;
1240    (*sqe).__liburing_anon_5.optlen = peer as _;
1241}
1242
1243#[inline]
1244pub unsafe fn io_uring_prep_waitid(sqe: *mut io_uring_sqe, idtype: idtype_t, id: id_t,
1245                                   infop: *mut siginfo_t, options: c_int, flags: c_uint)
1246{
1247    io_uring_prep_rw(IORING_OP_WAITID, sqe, id as _, ptr::null_mut(), idtype, 0);
1248    (*sqe).__liburing_anon_3.waitid_flags = flags;
1249    (*sqe).__liburing_anon_5.file_index = options as _;
1250    (*sqe).__liburing_anon_1.addr2 = infop as usize as u64;
1251}
1252
1253#[inline]
1254pub unsafe fn io_uring_prep_futex_wake(sqe: *mut io_uring_sqe, futex: *const u32, val: u64,
1255                                       mask: u64, futex_flags: u32, flags: c_uint)
1256{
1257    io_uring_prep_rw(IORING_OP_FUTEX_WAKE, sqe, futex_flags as _, futex.cast(), 0, val);
1258    (*sqe).__liburing_anon_3.futex_flags = flags;
1259    (*sqe).__liburing_anon_6.__liburing_anon_1.as_mut().addr3 = mask;
1260}
1261
1262#[inline]
1263pub unsafe fn io_uring_prep_futex_wait(sqe: *mut io_uring_sqe, futex: *const u32, val: u64,
1264                                       mask: u64, futex_flags: u32, flags: c_uint)
1265{
1266    io_uring_prep_rw(IORING_OP_FUTEX_WAIT, sqe, futex_flags as _, futex.cast(), 0, val);
1267    (*sqe).__liburing_anon_3.futex_flags = flags;
1268    (*sqe).__liburing_anon_6.__liburing_anon_1.as_mut().addr3 = mask;
1269}
1270
1271#[inline]
1272pub unsafe fn io_uring_prep_futex_waitv(sqe: *mut io_uring_sqe, futex: *const futex_waitv,
1273                                        nr_futex: u32, flags: c_uint)
1274{
1275    io_uring_prep_rw(IORING_OP_FUTEX_WAITV, sqe, 0, futex.cast(), nr_futex, 0);
1276    (*sqe).__liburing_anon_3.futex_flags = flags;
1277}
1278
1279#[inline]
1280pub unsafe fn io_uring_prep_fixed_fd_install(sqe: *mut io_uring_sqe, fd: c_int, flags: c_uint)
1281{
1282    io_uring_prep_rw(IORING_OP_FIXED_FD_INSTALL, sqe, fd, ptr::null_mut(), 0, 0);
1283
1284    (*sqe).flags = IOSQE_FIXED_FILE as _;
1285    (*sqe).__liburing_anon_3.install_fd_flags = flags;
1286}
1287
1288#[inline]
1289pub unsafe fn io_uring_prep_ftruncate(sqe: *mut io_uring_sqe, fd: c_int, len: c_longlong)
1290{
1291    io_uring_prep_rw(IORING_OP_FTRUNCATE, sqe, fd, ptr::null_mut(), 0, len as _);
1292}
1293
1294#[inline]
1295pub unsafe fn io_uring_prep_cmd_discard(sqe: *mut io_uring_sqe, fd: c_int, offset: u64, nbytes: u64)
1296{
1297    // TODO: really someday fix this
1298    // We need bindgen to actually evaluate this macro's value during generation.
1299    // No idea if hard-coding this value like this is viable in practice.
1300    io_uring_prep_uring_cmd(sqe, ((0x12) << 8) as _ /* BLOCK_URING_CMD_DISCARD */, fd);
1301
1302    (*sqe).__liburing_anon_2.addr = offset;
1303    (*sqe).__liburing_anon_6.__liburing_anon_1.as_mut().addr3 = nbytes;
1304}
1305
1306#[inline]
1307pub unsafe fn io_uring_prep_pipe(sqe: *mut io_uring_sqe, fds: *mut c_int, pipe_flags: c_int)
1308{
1309    io_uring_prep_rw(IORING_OP_PIPE, sqe, 0, fds as *const _, 0, 0);
1310    (*sqe).__liburing_anon_3.pipe_flags = pipe_flags as u32;
1311}
1312
1313/* setup pipe directly into the fixed file table */
1314#[inline]
1315pub unsafe fn io_uring_prep_pipe_direct(sqe: *mut io_uring_sqe, fds: *mut c_int,
1316                                        pipe_flags: c_int, mut file_index: c_uint)
1317{
1318    io_uring_prep_pipe(sqe, fds, pipe_flags);
1319    /* offset by 1 for allocation */
1320    if file_index == IORING_FILE_INDEX_ALLOC as u32 {
1321        file_index -= 1;
1322    }
1323    __io_uring_set_target_fixed_file(sqe, file_index);
1324}
1325
1326/* Read the kernel's SQ head index with appropriate memory ordering */
1327#[inline]
1328pub unsafe fn io_uring_load_sq_head(ring: *mut io_uring) -> c_uint
1329{
1330    /*
1331     * Without acquire ordering, we could overwrite a SQE before the kernel
1332     * finished reading it. We don't need the acquire ordering for
1333     * non-SQPOLL since then we drive updates.
1334     */
1335    if (*ring).flags & IORING_SETUP_SQPOLL > 0 {
1336        return io_uring_smp_load_acquire((*ring).sq.khead);
1337    }
1338
1339    *(*ring).sq.khead
1340}
1341
1342/*
1343 * Returns number of unconsumed (if SQPOLL) or unsubmitted entries exist in
1344 * the SQ ring
1345 */
1346#[inline]
1347pub unsafe fn io_uring_sq_ready(ring: *mut io_uring) -> c_uint
1348{
1349    (*ring).sq.sqe_tail - io_uring_load_sq_head(ring)
1350}
1351
1352/*
1353 * Returns how much space is left in the SQ ring.
1354 */
1355#[inline]
1356pub unsafe fn io_uring_sq_space_left(ring: *mut io_uring) -> c_uint
1357{
1358    (*ring).sq.ring_entries - io_uring_sq_ready(ring)
1359}
1360
1361/*
1362 * Returns the bit shift needed to index the SQ.
1363 * This shift is 1 for rings with big SQEs, and 0 for rings with normal SQEs.
1364 * SQE `index` can be computed as &sq.sqes[(index & sq.ring_mask) << sqe_shift].
1365 */
1366#[must_use]
1367#[inline]
1368pub fn io_uring_sqe_shift_from_flags(flags: c_uint) -> c_uint
1369{
1370    u32::from(flags & IORING_SETUP_SQE128 != 0)
1371}
1372
1373#[inline]
1374pub unsafe fn io_uring_sqe_shift(ring: *mut io_uring) -> c_uint
1375{
1376    io_uring_sqe_shift_from_flags((*ring).flags)
1377}
1378
1379/*
1380 * Only applicable when using SQPOLL - allows the caller to wait for space
1381 * to free up in the SQ ring, which happens when the kernel side thread has
1382 * consumed one or more entries. If the SQ ring is currently non-full, no
1383 * action is taken. Note: may return -EINVAL if the kernel doesn't support
1384 * this feature.
1385 */
1386#[inline]
1387pub unsafe fn io_uring_sqring_wait(ring: *mut io_uring) -> c_int
1388{
1389    if (*ring).flags & IORING_SETUP_SQPOLL == 0 {
1390        return 0;
1391    }
1392    if io_uring_sq_space_left(ring) > 0 {
1393        return 0;
1394    }
1395
1396    __io_uring_sqring_wait(ring)
1397}
1398
1399/*
1400 * Returns how many unconsumed entries are ready in the CQ ring
1401 */
1402#[inline]
1403pub unsafe fn io_uring_cq_ready(ring: *mut io_uring) -> c_uint
1404{
1405    io_uring_smp_load_acquire((*ring).cq.ktail) - *(*ring).cq.khead
1406}
1407
1408/*
1409 * Returns true if there are overflow entries waiting to be flushed onto
1410 * the CQ ring
1411 */
1412#[inline]
1413pub unsafe fn io_uring_cq_has_overflow(ring: *mut io_uring) -> bool
1414{
1415    IO_URING_READ_ONCE((*ring).sq.kflags) & IORING_SQ_CQ_OVERFLOW > 0
1416}
1417
1418/*
1419 * Returns true if the eventfd notification is currently enabled
1420 */
1421#[inline]
1422pub unsafe fn io_uring_cq_eventfd_enabled(ring: *mut io_uring) -> bool
1423{
1424    if (*ring).cq.kflags.is_null() {
1425        return true;
1426    }
1427    (*(*ring).cq.kflags & IORING_CQ_EVENTFD_DISABLED) == 0
1428}
1429
1430/*
1431 * Toggle eventfd notification on or off, if an eventfd is registered with
1432 * the ring.
1433 */
1434#[inline]
1435pub unsafe fn io_uring_cq_eventfd_toggle(ring: *mut io_uring, enabled: bool) -> c_int
1436{
1437    if enabled == io_uring_cq_eventfd_enabled(ring) {
1438        return 0;
1439    }
1440
1441    if (*ring).cq.kflags.is_null() {
1442        return -(EOPNOTSUPP as c_int);
1443    }
1444
1445    let mut flags = *(*ring).cq.kflags;
1446
1447    if enabled {
1448        flags &= !IORING_CQ_EVENTFD_DISABLED;
1449    } else {
1450        flags |= IORING_CQ_EVENTFD_DISABLED;
1451    }
1452
1453    IO_URING_WRITE_ONCE((*ring).cq.kflags, flags);
1454
1455    0
1456}
1457
1458/*
1459 * Return an IO completion, waiting for 'wait_nr' completions if one isn't
1460 * readily available. Returns 0 with cqe_ptr filled in on success, -errno on
1461 * failure.
1462 */
1463#[inline]
1464pub unsafe fn io_uring_wait_cqe_nr(ring: *mut io_uring, cqe_ptr: *mut *mut io_uring_cqe,
1465                                   wait_nr: c_uint)
1466                                   -> c_int
1467{
1468    __io_uring_get_cqe(ring, cqe_ptr, 0, wait_nr, ptr::null_mut())
1469}
1470
1471#[inline]
1472unsafe fn io_uring_skip_cqe(ring: *mut io_uring, cqe: *mut io_uring_cqe, err: *mut c_int) -> bool
1473{
1474    'out: {
1475        if (*cqe).flags & IORING_CQE_F_SKIP != 0 {
1476            break 'out;
1477        }
1478
1479        if (*ring).features & IORING_FEAT_EXT_ARG != 0 {
1480            return false;
1481        }
1482
1483        if (*cqe).user_data != LIBURING_UDATA_TIMEOUT {
1484            return false;
1485        }
1486
1487        if (*cqe).res < 0 {
1488            *err = (*cqe).res;
1489        }
1490    }
1491
1492    io_uring_cq_advance(ring, io_uring_cqe_nr(cqe));
1493    *err == 0
1494}
1495
1496/*
1497 * Internal helper, don't use directly in applications. Use one of the
1498 * "official" versions of this, io_uring_peek_cqe(), io_uring_wait_cqe(),
1499 * or io_uring_wait_cqes*().
1500 */
1501#[inline]
1502unsafe fn __io_uring_peek_cqe(ring: *mut io_uring, cqe_ptr: *mut *mut io_uring_cqe,
1503                              nr_available: *mut c_uint)
1504                              -> c_int
1505{
1506    let mut cqe;
1507    let mut err = 0;
1508
1509    let mut available;
1510    let mask = (*ring).cq.ring_mask;
1511    let shift = io_uring_cqe_shift(ring);
1512
1513    loop {
1514        let tail = io_uring_smp_load_acquire((*ring).cq.ktail);
1515
1516        /*
1517         * The acquire ordering on the tail load pairs with the kernel
1518         * side publishing CQEs, and guarantees the contents of any
1519         * entry in [head, tail). The CQ head is only ever written by
1520         * the application, so a plain load is sufficient.
1521         */
1522        let head = *((*ring).cq.khead);
1523
1524        cqe = ptr::null_mut();
1525        available = tail - head;
1526        if available == 0 {
1527            break;
1528        }
1529
1530        cqe = &raw mut *(*ring).cq.cqes.add(((head & mask) << shift) as usize);
1531        if !io_uring_skip_cqe(ring, cqe, &raw mut err) {
1532            /*
1533             * If an error was set, the CQE was an internal
1534             * timeout and has already been consumed - don't
1535             * return a pointer to it.
1536             */
1537            if err != 0 {
1538                cqe = ptr::null_mut();
1539            }
1540            break;
1541        }
1542    }
1543
1544    *cqe_ptr = cqe;
1545    if !nr_available.is_null() {
1546        *nr_available = available;
1547    }
1548    err
1549}
1550
1551/*
1552 * Return an IO completion, if one is readily available. Returns 0 with
1553 * cqe_ptr filled in on success, -errno on failure.
1554 */
1555#[inline]
1556pub unsafe fn io_uring_peek_cqe(ring: *mut io_uring, cqe_ptr: *mut *mut io_uring_cqe) -> c_int
1557{
1558    if __io_uring_peek_cqe(ring, cqe_ptr, ptr::null_mut()) == 0 {
1559        if !(*cqe_ptr).is_null() {
1560            return 0;
1561        }
1562
1563        /*
1564         * If the CQ is empty and there's nothing the kernel could
1565         * flush to it (no IOPOLL completions to reap, no overflown
1566         * CQEs, no pending task work), avoid the round trip into
1567         * the full get_cqe machinery.
1568         */
1569        if ((*ring).flags & IORING_SETUP_IOPOLL) == 0
1570           && (IO_URING_READ_ONCE((*ring).sq.kflags) & (IORING_SQ_CQ_OVERFLOW | IORING_SQ_TASKRUN))
1571              == 0
1572        {
1573            return -(EAGAIN as c_int);
1574        }
1575    }
1576
1577    io_uring_wait_cqe_nr(ring, cqe_ptr, 0)
1578}
1579
1580/*
1581 * Return an IO completion, waiting for it if necessary. Returns 0 with
1582 * cqe_ptr filled in on success, -errno on failure.
1583 */
1584#[inline]
1585pub unsafe fn io_uring_wait_cqe(ring: *mut io_uring, cqe_ptr: *mut *mut io_uring_cqe) -> c_int
1586{
1587    if __io_uring_peek_cqe(ring, cqe_ptr, ptr::null_mut()) == 0 && !(*cqe_ptr).is_null() {
1588        return 0;
1589    }
1590
1591    io_uring_wait_cqe_nr(ring, cqe_ptr, 1)
1592}
1593
1594/*
1595 * Return an sqe to fill. Application must later call io_uring_submit()
1596 * when it's ready to tell the kernel about it. The caller may call this
1597 * function multiple times before calling io_uring_submit().
1598 *
1599 * Returns a vacant sqe, or NULL if we're full.
1600 */
1601#[inline]
1602unsafe fn _io_uring_get_sqe(ring: *mut io_uring) -> *mut io_uring_sqe
1603{
1604    let sq = &raw mut (*ring).sq;
1605
1606    let head = io_uring_load_sq_head(ring);
1607    let tail = (*sq).sqe_tail;
1608
1609    if tail - head >= (*sq).ring_entries {
1610        return ptr::null_mut();
1611    }
1612
1613    let offset = (tail & (*sq).ring_mask) << io_uring_sqe_shift(ring);
1614    let sqe = (*sq).sqes.add(offset as usize);
1615    (*sq).sqe_tail = tail + 1;
1616    io_uring_initialize_sqe(sqe);
1617    sqe
1618}
1619
1620/*
1621 * Return the appropriate mask for a buffer ring of size 'ring_entries'
1622 */
1623#[must_use]
1624#[inline]
1625pub fn io_uring_buf_ring_mask(ring_entries: u32) -> c_int
1626{
1627    (ring_entries - 1) as _
1628}
1629
1630#[inline]
1631pub unsafe fn io_uring_buf_ring_init(br: *mut io_uring_buf_ring)
1632{
1633    (*br).__liburing_anon_1.__liburing_anon_1.as_mut().tail = 0;
1634}
1635
1636/*
1637 * Assign 'buf' with the addr/len/buffer ID supplied
1638 */
1639#[inline]
1640pub unsafe fn io_uring_buf_ring_add(br: *mut io_uring_buf_ring, addr: *mut c_void, len: c_uint,
1641                                    bid: c_ushort, mask: c_int, buf_offset: c_int)
1642{
1643    let tail = (*br).__liburing_anon_1.__liburing_anon_1.as_ref().tail;
1644    let buf = (*br).__liburing_anon_1
1645                   .bufs
1646                   .as_mut()
1647                   .as_mut_ptr()
1648                   .add(((i32::from(tail) + buf_offset) & mask) as usize);
1649
1650    (*buf).addr = addr as usize as u64;
1651    (*buf).len = len;
1652    (*buf).bid = bid;
1653}
1654
1655/*
1656 * Make 'count' new buffers visible to the kernel. Called after
1657 * io_uring_buf_ring_add() has been called 'count' times to fill in new
1658 * buffers.
1659 */
1660#[inline]
1661pub unsafe fn io_uring_buf_ring_advance(br: *mut io_uring_buf_ring, count: c_int)
1662{
1663    let tail = (*br).__liburing_anon_1.__liburing_anon_1.as_ref().tail;
1664    let new_tail = tail.wrapping_add(count as u16);
1665
1666    io_uring_smp_store_release(&raw mut (*br).__liburing_anon_1.__liburing_anon_1.as_mut().tail,
1667                               new_tail);
1668}
1669
1670#[inline]
1671unsafe fn __io_uring_buf_ring_cq_advance(ring: *mut io_uring, br: *mut io_uring_buf_ring,
1672                                         cq_count: i32, buf_count: c_int)
1673{
1674    io_uring_buf_ring_advance(br, buf_count);
1675    io_uring_cq_advance(ring, cq_count as _);
1676}
1677
1678/*
1679 * Make 'count' new buffers visible to the kernel while at the same time
1680 * advancing the CQ ring seen entries. This can be used when the application
1681 * is using ring provided buffers and returns buffers while processing CQEs,
1682 * avoiding an extra atomic when needing to increment both the CQ ring and
1683 * the ring buffer index at the same time.
1684 */
1685#[inline]
1686pub unsafe fn io_uring_buf_ring_cq_advance(ring: *mut io_uring, br: *mut io_uring_buf_ring,
1687                                           count: c_int)
1688{
1689    __io_uring_buf_ring_cq_advance(ring, br, count, count);
1690}
1691
1692#[inline]
1693pub unsafe fn io_uring_buf_ring_available(ring: *mut io_uring, br: *mut io_uring_buf_ring,
1694                                          bgid: c_ushort)
1695                                          -> c_int
1696{
1697    let mut head = 0;
1698    let ret = io_uring_buf_ring_head(ring, bgid.into(), &raw mut head);
1699    if ret > 0 {
1700        return ret;
1701    }
1702    c_int::from((*br).__liburing_anon_1.__liburing_anon_1.as_mut().tail - head)
1703}
1704
1705#[inline]
1706pub unsafe fn io_uring_get_sqe(ring: *mut io_uring) -> *mut io_uring_sqe
1707{
1708    _io_uring_get_sqe(ring)
1709}
1710
1711/*
1712 * Return a 128B sqe to fill. Applications must later call io_uring_submit()
1713 * when it's ready to tell the kernel about it. The caller may call this
1714 * function multiple times before calling io_uring_submit().
1715 *
1716 * Returns a vacant 128B sqe, or NULL if we're full. If the current tail is the
1717 * last entry in the ring, this function will insert a nop + skip complete such
1718 * that the 128b entry wraps back to the beginning of the queue for a
1719 * contiguous big sq entry. It's up to the caller to use a 128b opcode in order
1720 * for the kernel to know how to advance its sq head pointer.
1721 */
1722#[inline]
1723pub unsafe fn io_uring_get_sqe128(ring: *mut io_uring) -> *mut io_uring_sqe
1724{
1725    let sq = &raw mut (*ring).sq;
1726
1727    let head = io_uring_load_sq_head(ring);
1728    let mut tail = (*sq).sqe_tail;
1729
1730    if (*ring).flags & IORING_SETUP_SQE128 != 0 {
1731        return io_uring_get_sqe(ring);
1732    }
1733
1734    if (*ring).flags & IORING_SETUP_SQE_MIXED == 0 {
1735        return ptr::null_mut();
1736    }
1737
1738    let mut sqe: *mut io_uring_sqe;
1739    if (tail + 1) & (*sq).ring_mask == 0 {
1740        if (tail + 2) - head >= (*sq).ring_entries {
1741            return ptr::null_mut();
1742        }
1743
1744        sqe = _io_uring_get_sqe(ring);
1745        io_uring_prep_nop(sqe);
1746        (*sqe).flags |= IOSQE_CQE_SKIP_SUCCESS as u8;
1747        tail = (*sq).sqe_tail;
1748    } else if (tail + 1) - head >= (*sq).ring_entries {
1749        return ptr::null_mut();
1750    }
1751
1752    sqe = &raw mut *(*sq).sqes.add((tail & (*sq).ring_mask) as usize);
1753    (*sq).sqe_tail = tail + 2;
1754    io_uring_initialize_sqe(sqe);
1755    sqe
1756}
1757
1758//-----------------------------------------------------------------------------
1759
1760impl From<Duration> for timespec
1761{
1762    #[cfg(not(any(target_arch = "powerpc", target_arch = "arm")))]
1763    #[inline]
1764    fn from(duration: Duration) -> Self
1765    {
1766        let mut ts = unsafe { zeroed::<timespec>() };
1767        ts.tv_sec = duration.as_secs() as _;
1768        ts.tv_nsec = duration.subsec_nanos().into();
1769        ts
1770    }
1771
1772    #[cfg(any(target_arch = "powerpc", target_arch = "arm"))]
1773    #[inline]
1774    fn from(duration: Duration) -> Self
1775    {
1776        let mut ts = unsafe { zeroed::<timespec>() };
1777        ts.tv_sec = duration.as_secs() as _;
1778        ts.tv_nsec = duration.subsec_nanos().try_into().unwrap();
1779        ts
1780    }
1781}
1782
1783impl From<Duration> for __kernel_timespec
1784{
1785    #[inline]
1786    fn from(duration: Duration) -> Self
1787    {
1788        let mut ts = unsafe { zeroed::<__kernel_timespec>() };
1789        ts.tv_sec = duration.as_secs() as _;
1790        ts.tv_nsec = duration.subsec_nanos().into();
1791        ts
1792    }
1793}